pass heat source/system type to prepare_sector_network and add_existing_baseyear
This commit is contained in:
parent
0edf566e3f
commit
29479c50d0
@ -417,9 +417,9 @@ sector:
|
|||||||
isentropic_compressor_efficiency: 0.8
|
isentropic_compressor_efficiency: 0.8
|
||||||
heat_loss: 0.0
|
heat_loss: 0.0
|
||||||
heat_pump_sources:
|
heat_pump_sources:
|
||||||
central_heating:
|
central:
|
||||||
- air
|
- air
|
||||||
decentral_heating:
|
decentral:
|
||||||
- air
|
- air
|
||||||
- ground
|
- ground
|
||||||
cluster_heat_buses: true
|
cluster_heat_buses: true
|
||||||
|
@ -214,6 +214,13 @@ rule build_temperature_profiles:
|
|||||||
script:
|
script:
|
||||||
"../scripts/build_temperature_profiles.py"
|
"../scripts/build_temperature_profiles.py"
|
||||||
|
|
||||||
|
# def output_cop(wildcards):
|
||||||
|
# return {
|
||||||
|
# f"cop_{source}_{sink}": resources(
|
||||||
|
# "cop_" + source + "_" + sink + "_" + "elec_s{simpl}_{clusters}.nc"
|
||||||
|
# )
|
||||||
|
# for sink, source in config["sector"]["heat_pump_sources"].items()
|
||||||
|
# }
|
||||||
|
|
||||||
rule build_cop_profiles:
|
rule build_cop_profiles:
|
||||||
params:
|
params:
|
||||||
@ -237,21 +244,7 @@ rule build_cop_profiles:
|
|||||||
temp_soil_total=resources("temp_soil_total_elec_s{simpl}_{clusters}.nc"),
|
temp_soil_total=resources("temp_soil_total_elec_s{simpl}_{clusters}.nc"),
|
||||||
temp_air_total=resources("temp_air_total_elec_s{simpl}_{clusters}.nc"),
|
temp_air_total=resources("temp_air_total_elec_s{simpl}_{clusters}.nc"),
|
||||||
output:
|
output:
|
||||||
**{f"cop_{source}_{sink}": resources(
|
cop_profiles=resources("cop_profiles_elec_s{simpl}_{clusters}.nc"),
|
||||||
"cop_" + source + "_" + {sink} + "_" + "elec_s{simpl}_{clusters}.nc"
|
|
||||||
) for sink, source in config_provider("sector", "heat_pump_sources").items()},
|
|
||||||
# cop_air_decentral_heating=resources(
|
|
||||||
# "cop_air_decentral_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
# ),
|
|
||||||
# cop_soil_decentral_heating=resources(
|
|
||||||
# "cop_soil_decentral_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
# ),
|
|
||||||
# cop_air_central_heating=resources(
|
|
||||||
# "cop_air_central_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
# ),
|
|
||||||
# cop_soil_central_heating=resources(
|
|
||||||
# "cop_soil_central_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
# ),
|
|
||||||
resources:
|
resources:
|
||||||
mem_mb=20000,
|
mem_mb=20000,
|
||||||
log:
|
log:
|
||||||
@ -969,6 +962,7 @@ rule prepare_sector_network:
|
|||||||
adjustments=config_provider("adjustments", "sector"),
|
adjustments=config_provider("adjustments", "sector"),
|
||||||
emissions_scope=config_provider("energy", "emissions"),
|
emissions_scope=config_provider("energy", "emissions"),
|
||||||
RDIR=RDIR,
|
RDIR=RDIR,
|
||||||
|
heat_pump_sources=config_provider("sector", "heat_pump_sources"),
|
||||||
input:
|
input:
|
||||||
unpack(input_profile_offwind),
|
unpack(input_profile_offwind),
|
||||||
**rules.cluster_gas_network.output,
|
**rules.cluster_gas_network.output,
|
||||||
@ -1045,18 +1039,7 @@ rule prepare_sector_network:
|
|||||||
),
|
),
|
||||||
temp_soil_total=resources("temp_soil_total_elec_s{simpl}_{clusters}.nc"),
|
temp_soil_total=resources("temp_soil_total_elec_s{simpl}_{clusters}.nc"),
|
||||||
temp_air_total=resources("temp_air_total_elec_s{simpl}_{clusters}.nc"),
|
temp_air_total=resources("temp_air_total_elec_s{simpl}_{clusters}.nc"),
|
||||||
cop_soil_decentral_heating=resources(
|
cop_profiles=resources("cop_profiles_elec_s{simpl}_{clusters}.nc"),
|
||||||
"cop_soil_decentral_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
),
|
|
||||||
cop_air_decentral_heating=resources(
|
|
||||||
"cop_air_decentral_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
),
|
|
||||||
cop_air_central_heating=resources(
|
|
||||||
"cop_air_central_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
),
|
|
||||||
cop_soil_central_heating=resources(
|
|
||||||
"cop_soil_central_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
),
|
|
||||||
solar_thermal_total=lambda w: (
|
solar_thermal_total=lambda w: (
|
||||||
resources("solar_thermal_total_elec_s{simpl}_{clusters}.nc")
|
resources("solar_thermal_total_elec_s{simpl}_{clusters}.nc")
|
||||||
if config_provider("sector", "solar_thermal")(w)
|
if config_provider("sector", "solar_thermal")(w)
|
||||||
|
@ -9,6 +9,7 @@ rule add_existing_baseyear:
|
|||||||
sector=config_provider("sector"),
|
sector=config_provider("sector"),
|
||||||
existing_capacities=config_provider("existing_capacities"),
|
existing_capacities=config_provider("existing_capacities"),
|
||||||
costs=config_provider("costs"),
|
costs=config_provider("costs"),
|
||||||
|
heat_pump_sources=config_provider("sector", "heat_pump_sources"),
|
||||||
input:
|
input:
|
||||||
network=RESULTS
|
network=RESULTS
|
||||||
+ "prenetworks/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}.nc",
|
+ "prenetworks/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}.nc",
|
||||||
@ -21,18 +22,7 @@ rule add_existing_baseyear:
|
|||||||
config_provider("scenario", "planning_horizons", 0)(w)
|
config_provider("scenario", "planning_horizons", 0)(w)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
cop_soil_decentral_heating=resources(
|
cop_profiles=resources("cop_profiles_elec_s{simpl}_{clusters}.nc"),
|
||||||
"cop_soil_decentral_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
),
|
|
||||||
cop_air_decentral_heating=resources(
|
|
||||||
"cop_air_decentral_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
),
|
|
||||||
cop_air_central_heating=resources(
|
|
||||||
"cop_air_central_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
),
|
|
||||||
cop_soil_central_heating=resources(
|
|
||||||
"cop_soil_central_heating_elec_s{simpl}_{clusters}.nc"
|
|
||||||
),
|
|
||||||
existing_heating_distribution=resources(
|
existing_heating_distribution=resources(
|
||||||
"existing_heating_distribution_elec_s{simpl}_{clusters}_{planning_horizons}.csv"
|
"existing_heating_distribution_elec_s{simpl}_{clusters}_{planning_horizons}.csv"
|
||||||
),
|
),
|
||||||
|
@ -442,27 +442,27 @@ def add_heating_capacities_installed_before_baseyear(
|
|||||||
"""
|
"""
|
||||||
logger.debug(f"Adding heating capacities installed before {baseyear}")
|
logger.debug(f"Adding heating capacities installed before {baseyear}")
|
||||||
|
|
||||||
for name in existing_heating.columns.get_level_values(0).unique():
|
for heat_system in existing_heating.columns.get_level_values(0).unique():
|
||||||
name_type = "central" if name == "urban central" else "decentral"
|
system_type = "central" if heat_system == "urban central" else "decentral"
|
||||||
|
|
||||||
nodes = pd.Index(n.buses.location[n.buses.index.str.contains(f"{name} heat")])
|
nodes = pd.Index(n.buses.location[n.buses.index.str.contains(f"{heat_system} heat")])
|
||||||
|
|
||||||
if (name_type != "central") and options["electricity_distribution_grid"]:
|
if (system_type != "central") and options["electricity_distribution_grid"]:
|
||||||
nodes_elec = nodes + " low voltage"
|
nodes_elec = nodes + " low voltage"
|
||||||
else:
|
else:
|
||||||
nodes_elec = nodes
|
nodes_elec = nodes
|
||||||
|
|
||||||
heat_pump_type = "air" if "urban" in name else "ground"
|
|
||||||
|
|
||||||
# Add heat pumps
|
# Add heat pumps
|
||||||
costs_name = f"decentral {heat_pump_type}-sourced heat pump"
|
heat_source = snakemake.params.heat_pump_sources[system_type]
|
||||||
|
costs_name = f"{system_type} {heat_source}-sourced heat pump"
|
||||||
|
|
||||||
efficiency = (
|
efficiency = (
|
||||||
cop[f"{heat_pump_type} {name_type}"][nodes]
|
cop.sel(heat_system=system_type, heat_source=heat_source, name=nodes).to_pandas().reindex(index=n.snapshots)
|
||||||
if time_dep_hp_cop
|
if options["time_dep_hp_cop"]
|
||||||
else costs.at[costs_name, "efficiency"]
|
else costs.at[costs_name, "efficiency"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
too_large_grouping_years = [gy for gy in grouping_years if gy >= int(baseyear)]
|
too_large_grouping_years = [gy for gy in grouping_years if gy >= int(baseyear)]
|
||||||
if too_large_grouping_years:
|
if too_large_grouping_years:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@ -491,14 +491,14 @@ def add_heating_capacities_installed_before_baseyear(
|
|||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes,
|
nodes,
|
||||||
suffix=f" {name} {heat_pump_type} heat pump-{grouping_year}",
|
suffix=f" {heat_system} {heat_source} heat pump-{grouping_year}",
|
||||||
bus0=nodes_elec,
|
bus0=nodes_elec,
|
||||||
bus1=nodes + " " + name + " heat",
|
bus1=nodes + " " + heat_system + " heat",
|
||||||
carrier=f"{name} {heat_pump_type} heat pump",
|
carrier=f"{heat_system} {heat_source} heat pump",
|
||||||
efficiency=efficiency,
|
efficiency=efficiency,
|
||||||
capital_cost=costs.at[costs_name, "efficiency"]
|
capital_cost=costs.at[costs_name, "efficiency"]
|
||||||
* costs.at[costs_name, "fixed"],
|
* costs.at[costs_name, "fixed"],
|
||||||
p_nom=existing_heating.loc[nodes, (name, f"{heat_pump_type} heat pump")]
|
p_nom=existing_heating.loc[nodes, (heat_system, f"{heat_source} heat pump")]
|
||||||
* ratio
|
* ratio
|
||||||
/ costs.at[costs_name, "efficiency"],
|
/ costs.at[costs_name, "efficiency"],
|
||||||
build_year=int(grouping_year),
|
build_year=int(grouping_year),
|
||||||
@ -509,66 +509,66 @@ def add_heating_capacities_installed_before_baseyear(
|
|||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes,
|
nodes,
|
||||||
suffix=f" {name} resistive heater-{grouping_year}",
|
suffix=f" {heat_system} resistive heater-{grouping_year}",
|
||||||
bus0=nodes_elec,
|
bus0=nodes_elec,
|
||||||
bus1=nodes + " " + name + " heat",
|
bus1=nodes + " " + heat_system + " heat",
|
||||||
carrier=name + " resistive heater",
|
carrier=heat_system + " resistive heater",
|
||||||
efficiency=costs.at[f"{name_type} resistive heater", "efficiency"],
|
efficiency=costs.at[f"{system_type} resistive heater", "efficiency"],
|
||||||
capital_cost=(
|
capital_cost=(
|
||||||
costs.at[f"{name_type} resistive heater", "efficiency"]
|
costs.at[f"{system_type} resistive heater", "efficiency"]
|
||||||
* costs.at[f"{name_type} resistive heater", "fixed"]
|
* costs.at[f"{system_type} resistive heater", "fixed"]
|
||||||
),
|
),
|
||||||
p_nom=(
|
p_nom=(
|
||||||
existing_heating.loc[nodes, (name, "resistive heater")]
|
existing_heating.loc[nodes, (heat_system, "resistive heater")]
|
||||||
* ratio
|
* ratio
|
||||||
/ costs.at[f"{name_type} resistive heater", "efficiency"]
|
/ costs.at[f"{system_type} resistive heater", "efficiency"]
|
||||||
),
|
),
|
||||||
build_year=int(grouping_year),
|
build_year=int(grouping_year),
|
||||||
lifetime=costs.at[f"{name_type} resistive heater", "lifetime"],
|
lifetime=costs.at[f"{system_type} resistive heater", "lifetime"],
|
||||||
)
|
)
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes,
|
nodes,
|
||||||
suffix=f" {name} gas boiler-{grouping_year}",
|
suffix=f" {heat_system} gas boiler-{grouping_year}",
|
||||||
bus0="EU gas" if "EU gas" in spatial.gas.nodes else nodes + " gas",
|
bus0="EU gas" if "EU gas" in spatial.gas.nodes else nodes + " gas",
|
||||||
bus1=nodes + " " + name + " heat",
|
bus1=nodes + " " + heat_system + " heat",
|
||||||
bus2="co2 atmosphere",
|
bus2="co2 atmosphere",
|
||||||
carrier=name + " gas boiler",
|
carrier=heat_system + " gas boiler",
|
||||||
efficiency=costs.at[f"{name_type} gas boiler", "efficiency"],
|
efficiency=costs.at[f"{system_type} gas boiler", "efficiency"],
|
||||||
efficiency2=costs.at["gas", "CO2 intensity"],
|
efficiency2=costs.at["gas", "CO2 intensity"],
|
||||||
capital_cost=(
|
capital_cost=(
|
||||||
costs.at[f"{name_type} gas boiler", "efficiency"]
|
costs.at[f"{system_type} gas boiler", "efficiency"]
|
||||||
* costs.at[f"{name_type} gas boiler", "fixed"]
|
* costs.at[f"{system_type} gas boiler", "fixed"]
|
||||||
),
|
),
|
||||||
p_nom=(
|
p_nom=(
|
||||||
existing_heating.loc[nodes, (name, "gas boiler")]
|
existing_heating.loc[nodes, (heat_system, "gas boiler")]
|
||||||
* ratio
|
* ratio
|
||||||
/ costs.at[f"{name_type} gas boiler", "efficiency"]
|
/ costs.at[f"{system_type} gas boiler", "efficiency"]
|
||||||
),
|
),
|
||||||
build_year=int(grouping_year),
|
build_year=int(grouping_year),
|
||||||
lifetime=costs.at[f"{name_type} gas boiler", "lifetime"],
|
lifetime=costs.at[f"{system_type} gas boiler", "lifetime"],
|
||||||
)
|
)
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes,
|
nodes,
|
||||||
suffix=f" {name} oil boiler-{grouping_year}",
|
suffix=f" {heat_system} oil boiler-{grouping_year}",
|
||||||
bus0=spatial.oil.nodes,
|
bus0=spatial.oil.nodes,
|
||||||
bus1=nodes + " " + name + " heat",
|
bus1=nodes + " " + heat_system + " heat",
|
||||||
bus2="co2 atmosphere",
|
bus2="co2 atmosphere",
|
||||||
carrier=name + " oil boiler",
|
carrier=heat_system + " oil boiler",
|
||||||
efficiency=costs.at["decentral oil boiler", "efficiency"],
|
efficiency=costs.at["decentral oil boiler", "efficiency"],
|
||||||
efficiency2=costs.at["oil", "CO2 intensity"],
|
efficiency2=costs.at["oil", "CO2 intensity"],
|
||||||
capital_cost=costs.at["decentral oil boiler", "efficiency"]
|
capital_cost=costs.at["decentral oil boiler", "efficiency"]
|
||||||
* costs.at["decentral oil boiler", "fixed"],
|
* costs.at["decentral oil boiler", "fixed"],
|
||||||
p_nom=(
|
p_nom=(
|
||||||
existing_heating.loc[nodes, (name, "oil boiler")]
|
existing_heating.loc[nodes, (heat_system, "oil boiler")]
|
||||||
* ratio
|
* ratio
|
||||||
/ costs.at["decentral oil boiler", "efficiency"]
|
/ costs.at["decentral oil boiler", "efficiency"]
|
||||||
),
|
),
|
||||||
build_year=int(grouping_year),
|
build_year=int(grouping_year),
|
||||||
lifetime=costs.at[f"{name_type} gas boiler", "lifetime"],
|
lifetime=costs.at[f"{system_type} gas boiler", "lifetime"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# delete links with p_nom=nan corresponding to extra nodes in country
|
# delete links with p_nom=nan corresponding to extra nodes in country
|
||||||
|
@ -39,12 +39,12 @@ class DecentralHeatingCopApproximator(BaseCopApproximator):
|
|||||||
return_temperature_celsius : Union[xr.DataArray, np.array]
|
return_temperature_celsius : Union[xr.DataArray, np.array]
|
||||||
The return temperature in Celsius.
|
The return temperature in Celsius.
|
||||||
source: str
|
source: str
|
||||||
The source of the heat pump. Must be either 'air' or 'soil'
|
The source of the heat pump. Must be either 'air' or 'ground'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.delta_t = forward_temperature_celsius - source_inlet_temperature_celsius
|
self.delta_t = forward_temperature_celsius - source_inlet_temperature_celsius
|
||||||
if source_type not in ["air", "soil"]:
|
if source_type not in ["air", "ground"]:
|
||||||
raise ValueError("'source' must be one of ['air', 'soil']")
|
raise ValueError("'source' must be one of ['air', 'ground']")
|
||||||
else:
|
else:
|
||||||
self.source_type = source_type
|
self.source_type = source_type
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ class DecentralHeatingCopApproximator(BaseCopApproximator):
|
|||||||
"""
|
"""
|
||||||
if self.source_type == "air":
|
if self.source_type == "air":
|
||||||
return self._approximate_cop_air_source()
|
return self._approximate_cop_air_source()
|
||||||
elif self.source_type == "soil":
|
elif self.source_type == "ground":
|
||||||
return self._approximate_cop_ground_source()
|
return self._approximate_cop_ground_source()
|
||||||
|
|
||||||
def _approximate_cop_air_source(self) -> Union[xr.DataArray, np.array]:
|
def _approximate_cop_air_source(self) -> Union[xr.DataArray, np.array]:
|
||||||
|
@ -4,11 +4,39 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
import xarray as xr
|
import xarray as xr
|
||||||
from _helpers import set_scenario_config
|
from _helpers import set_scenario_config
|
||||||
from CentralHeatingCopApproximator import CentralHeatingCopApproximator
|
from CentralHeatingCopApproximator import CentralHeatingCopApproximator
|
||||||
from DecentralHeatingCopApproximator import DecentralHeatingCopApproximator
|
from DecentralHeatingCopApproximator import DecentralHeatingCopApproximator
|
||||||
|
|
||||||
|
|
||||||
|
def get_cop(
|
||||||
|
heat_system_type: str,
|
||||||
|
heat_source: str,
|
||||||
|
source_inlet_temperature_celsius: xr.DataArray,
|
||||||
|
) -> xr.DataArray:
|
||||||
|
if heat_system_type == "decentral":
|
||||||
|
return DecentralHeatingCopApproximator(
|
||||||
|
forward_temperature_celsius=snakemake.params.heat_pump_sink_T_decentral_heating,
|
||||||
|
source_inlet_temperature_celsius=source_inlet_temperature_celsius,
|
||||||
|
source_type=heat_source,
|
||||||
|
).approximate_cop()
|
||||||
|
|
||||||
|
elif heat_system_type == "central":
|
||||||
|
return CentralHeatingCopApproximator(
|
||||||
|
forward_temperature_celsius=snakemake.params.forward_temperature_central_heating,
|
||||||
|
return_temperature_celsius=snakemake.params.return_temperature_central_heating,
|
||||||
|
source_inlet_temperature_celsius=source_inlet_temperature_celsius,
|
||||||
|
source_outlet_temperature_celsius=source_inlet_temperature_celsius
|
||||||
|
- snakemake.params.heat_source_cooling_central_heating,
|
||||||
|
).approximate_cop()
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid heat system type '{heat_system_type}'. Must be one of ['decentral', 'central']"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if "snakemake" not in globals():
|
if "snakemake" not in globals():
|
||||||
from _helpers import mock_snakemake
|
from _helpers import mock_snakemake
|
||||||
@ -21,30 +49,28 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
set_scenario_config(snakemake)
|
set_scenario_config(snakemake)
|
||||||
|
|
||||||
for source_type in ["air", "soil"]:
|
cop_all_system_types = []
|
||||||
# source inlet temperature (air/soil) is based on weather data
|
for heat_system_type, heat_sources in snakemake.params.heat_pump_sources.items():
|
||||||
source_inlet_temperature_celsius = xr.open_dataarray(
|
cop_this_system_type = []
|
||||||
snakemake.input[f"temp_{source_type}_total"]
|
for heat_source in heat_sources:
|
||||||
|
source_inlet_temperature_celsius = xr.open_dataarray(
|
||||||
|
snakemake.input[f"temp_{heat_source.replace('ground', 'soil')}_total"]
|
||||||
|
)
|
||||||
|
cop_da = get_cop(
|
||||||
|
heat_system_type=heat_system_type,
|
||||||
|
heat_source=heat_source,
|
||||||
|
source_inlet_temperature_celsius=source_inlet_temperature_celsius,
|
||||||
|
)
|
||||||
|
cop_this_system_type.append(cop_da)
|
||||||
|
cop_all_system_types.append(
|
||||||
|
xr.concat(
|
||||||
|
cop_this_system_type, dim=pd.Index(heat_sources, name="heat_source")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Approximate COP for decentral (individual) heating
|
cop_dataarray = xr.concat(
|
||||||
cop_individual_heating = DecentralHeatingCopApproximator(
|
cop_all_system_types,
|
||||||
forward_temperature_celsius=snakemake.params.heat_pump_sink_T_decentral_heating,
|
dim=pd.Index(snakemake.params.heat_pump_sources.keys(), name="heat_system"),
|
||||||
source_inlet_temperature_celsius=source_inlet_temperature_celsius,
|
)
|
||||||
source_type=source_type,
|
|
||||||
).approximate_cop()
|
|
||||||
cop_individual_heating.to_netcdf(
|
|
||||||
snakemake.output[f"cop_{source_type}_decentral_heating"]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Approximate COP for central (district) heating
|
cop_dataarray.to_netcdf(snakemake.output.cop_profiles)
|
||||||
cop_central_heating = CentralHeatingCopApproximator(
|
|
||||||
forward_temperature_celsius=snakemake.params.forward_temperature_central_heating,
|
|
||||||
return_temperature_celsius=snakemake.params.return_temperature_central_heating,
|
|
||||||
source_inlet_temperature_celsius=source_inlet_temperature_celsius,
|
|
||||||
source_outlet_temperature_celsius=source_inlet_temperature_celsius
|
|
||||||
- snakemake.params.heat_source_cooling_central_heating,
|
|
||||||
).approximate_cop()
|
|
||||||
cop_central_heating.to_netcdf(
|
|
||||||
snakemake.output[f"cop_{source_type}_central_heating"]
|
|
||||||
)
|
|
||||||
|
@ -1825,23 +1825,6 @@ def add_heat(n, costs):
|
|||||||
"urban central",
|
"urban central",
|
||||||
]
|
]
|
||||||
|
|
||||||
cop = {
|
|
||||||
"air decentral": xr.open_dataarray(snakemake.input.cop_air_decentral_heating)
|
|
||||||
.to_pandas()
|
|
||||||
.reindex(index=n.snapshots),
|
|
||||||
"ground decentral": xr.open_dataarray(
|
|
||||||
snakemake.input.cop_soil_decentral_heating
|
|
||||||
)
|
|
||||||
.to_pandas()
|
|
||||||
.reindex(index=n.snapshots),
|
|
||||||
"air central": xr.open_dataarray(snakemake.input.cop_air_central_heating)
|
|
||||||
.to_pandas()
|
|
||||||
.reindex(index=n.snapshots),
|
|
||||||
"ground central": xr.open_dataarray(snakemake.input.cop_soil_central_heating)
|
|
||||||
.to_pandas()
|
|
||||||
.reindex(index=n.snapshots),
|
|
||||||
}
|
|
||||||
|
|
||||||
if options["solar_thermal"]:
|
if options["solar_thermal"]:
|
||||||
solar_thermal = (
|
solar_thermal = (
|
||||||
xr.open_dataarray(snakemake.input.solar_thermal_total)
|
xr.open_dataarray(snakemake.input.solar_thermal_total)
|
||||||
@ -1851,31 +1834,32 @@ def add_heat(n, costs):
|
|||||||
# 1e3 converts from W/m^2 to MW/(1000m^2) = kW/m^2
|
# 1e3 converts from W/m^2 to MW/(1000m^2) = kW/m^2
|
||||||
solar_thermal = options["solar_cf_correction"] * solar_thermal / 1e3
|
solar_thermal = options["solar_cf_correction"] * solar_thermal / 1e3
|
||||||
|
|
||||||
for name in heat_systems:
|
cop = xr.open_dataarray(snakemake.input.cop_profiles)
|
||||||
name_type = "central" if name == "urban central" else "decentral"
|
for heat_system in heat_systems:
|
||||||
|
system_type = "central" if heat_system == "urban central" else "decentral"
|
||||||
|
|
||||||
if name == "urban central":
|
if heat_system == "urban central":
|
||||||
nodes = dist_fraction.index[dist_fraction > 0]
|
nodes = dist_fraction.index[dist_fraction > 0]
|
||||||
else:
|
else:
|
||||||
nodes = pop_layout.index
|
nodes = pop_layout.index
|
||||||
|
|
||||||
n.add("Carrier", name + " heat")
|
n.add("Carrier", heat_system + " heat")
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Bus",
|
"Bus",
|
||||||
nodes + f" {name} heat",
|
nodes + f" {heat_system} heat",
|
||||||
location=nodes,
|
location=nodes,
|
||||||
carrier=name + " heat",
|
carrier=heat_system + " heat",
|
||||||
unit="MWh_th",
|
unit="MWh_th",
|
||||||
)
|
)
|
||||||
|
|
||||||
if name == "urban central" and options.get("central_heat_vent"):
|
if heat_system == "urban central" and options.get("central_heat_vent"):
|
||||||
n.madd(
|
n.madd(
|
||||||
"Generator",
|
"Generator",
|
||||||
nodes + f" {name} heat vent",
|
nodes + f" {heat_system} heat vent",
|
||||||
bus=nodes + f" {name} heat",
|
bus=nodes + f" {heat_system} heat",
|
||||||
location=nodes,
|
location=nodes,
|
||||||
carrier=name + " heat vent",
|
carrier=heat_system + " heat vent",
|
||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
p_max_pu=0,
|
p_max_pu=0,
|
||||||
p_min_pu=-1,
|
p_min_pu=-1,
|
||||||
@ -1886,18 +1870,18 @@ def add_heat(n, costs):
|
|||||||
|
|
||||||
for sector in sectors:
|
for sector in sectors:
|
||||||
# heat demand weighting
|
# heat demand weighting
|
||||||
if "rural" in name:
|
if "rural" in heat_system:
|
||||||
factor = 1 - urban_fraction[nodes]
|
factor = 1 - urban_fraction[nodes]
|
||||||
elif "urban central" in name:
|
elif "urban central" in heat_system:
|
||||||
factor = dist_fraction[nodes]
|
factor = dist_fraction[nodes]
|
||||||
elif "urban decentral" in name:
|
elif "urban decentral" in heat_system:
|
||||||
factor = urban_fraction[nodes] - dist_fraction[nodes]
|
factor = urban_fraction[nodes] - dist_fraction[nodes]
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
f" {name} not in " f"heat systems: {heat_systems}"
|
f" {heat_system} not in " f"heat systems: {heat_systems}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if sector in name:
|
if sector in heat_system:
|
||||||
heat_load = (
|
heat_load = (
|
||||||
heat_demand[[sector + " water", sector + " space"]]
|
heat_demand[[sector + " water", sector + " space"]]
|
||||||
.T.groupby(level=1)
|
.T.groupby(level=1)
|
||||||
@ -1906,7 +1890,7 @@ def add_heat(n, costs):
|
|||||||
.multiply(factor)
|
.multiply(factor)
|
||||||
)
|
)
|
||||||
|
|
||||||
if name == "urban central":
|
if heat_system == "urban central":
|
||||||
heat_load = (
|
heat_load = (
|
||||||
heat_demand.T.groupby(level=1)
|
heat_demand.T.groupby(level=1)
|
||||||
.sum()
|
.sum()
|
||||||
@ -1919,20 +1903,17 @@ def add_heat(n, costs):
|
|||||||
n.madd(
|
n.madd(
|
||||||
"Load",
|
"Load",
|
||||||
nodes,
|
nodes,
|
||||||
suffix=f" {name} heat",
|
suffix=f" {heat_system} heat",
|
||||||
bus=nodes + f" {name} heat",
|
bus=nodes + f" {heat_system} heat",
|
||||||
carrier=name + " heat",
|
carrier=heat_system + " heat",
|
||||||
p_set=heat_load,
|
p_set=heat_load,
|
||||||
)
|
)
|
||||||
|
|
||||||
## Add heat pumps
|
## Add heat pumps
|
||||||
|
for heat_source in snakemake.params.heat_pump_sources[system_type]:
|
||||||
heat_pump_types = ["air"] if "urban" in name else ["ground", "air"]
|
costs_name = f"{system_type} {heat_source}-sourced heat pump"
|
||||||
|
|
||||||
for heat_pump_type in heat_pump_types:
|
|
||||||
costs_name = f"{name_type} {heat_pump_type}-sourced heat pump"
|
|
||||||
efficiency = (
|
efficiency = (
|
||||||
cop[f"{heat_pump_type} {name_type}"][nodes]
|
cop.sel(heat_system=system_type, heat_source=heat_source, name=nodes).to_pandas().reindex(index=n.snapshots)
|
||||||
if options["time_dep_hp_cop"]
|
if options["time_dep_hp_cop"]
|
||||||
else costs.at[costs_name, "efficiency"]
|
else costs.at[costs_name, "efficiency"]
|
||||||
)
|
)
|
||||||
@ -1940,10 +1921,10 @@ def add_heat(n, costs):
|
|||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes,
|
nodes,
|
||||||
suffix=f" {name} {heat_pump_type} heat pump",
|
suffix=f" {heat_system} {heat_source} heat pump",
|
||||||
bus0=nodes,
|
bus0=nodes,
|
||||||
bus1=nodes + f" {name} heat",
|
bus1=nodes + f" {heat_system} heat",
|
||||||
carrier=f"{name} {heat_pump_type} heat pump",
|
carrier=f"{heat_system} {heat_source} heat pump",
|
||||||
efficiency=efficiency,
|
efficiency=efficiency,
|
||||||
capital_cost=costs.at[costs_name, "efficiency"]
|
capital_cost=costs.at[costs_name, "efficiency"]
|
||||||
* costs.at[costs_name, "fixed"]
|
* costs.at[costs_name, "fixed"]
|
||||||
@ -1953,59 +1934,59 @@ def add_heat(n, costs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if options["tes"]:
|
if options["tes"]:
|
||||||
n.add("Carrier", name + " water tanks")
|
n.add("Carrier", heat_system + " water tanks")
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Bus",
|
"Bus",
|
||||||
nodes + f" {name} water tanks",
|
nodes + f" {heat_system} water tanks",
|
||||||
location=nodes,
|
location=nodes,
|
||||||
carrier=name + " water tanks",
|
carrier=heat_system + " water tanks",
|
||||||
unit="MWh_th",
|
unit="MWh_th",
|
||||||
)
|
)
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes + f" {name} water tanks charger",
|
nodes + f" {heat_system} water tanks charger",
|
||||||
bus0=nodes + f" {name} heat",
|
bus0=nodes + f" {heat_system} heat",
|
||||||
bus1=nodes + f" {name} water tanks",
|
bus1=nodes + f" {heat_system} water tanks",
|
||||||
efficiency=costs.at["water tank charger", "efficiency"],
|
efficiency=costs.at["water tank charger", "efficiency"],
|
||||||
carrier=name + " water tanks charger",
|
carrier=heat_system + " water tanks charger",
|
||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes + f" {name} water tanks discharger",
|
nodes + f" {heat_system} water tanks discharger",
|
||||||
bus0=nodes + f" {name} water tanks",
|
bus0=nodes + f" {heat_system} water tanks",
|
||||||
bus1=nodes + f" {name} heat",
|
bus1=nodes + f" {heat_system} heat",
|
||||||
carrier=name + " water tanks discharger",
|
carrier=heat_system + " water tanks discharger",
|
||||||
efficiency=costs.at["water tank discharger", "efficiency"],
|
efficiency=costs.at["water tank discharger", "efficiency"],
|
||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
tes_time_constant_days = options["tes_tau"][name_type]
|
tes_time_constant_days = options["tes_tau"][system_type]
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Store",
|
"Store",
|
||||||
nodes + f" {name} water tanks",
|
nodes + f" {heat_system} water tanks",
|
||||||
bus=nodes + f" {name} water tanks",
|
bus=nodes + f" {heat_system} water tanks",
|
||||||
e_cyclic=True,
|
e_cyclic=True,
|
||||||
e_nom_extendable=True,
|
e_nom_extendable=True,
|
||||||
carrier=name + " water tanks",
|
carrier=heat_system + " water tanks",
|
||||||
standing_loss=1 - np.exp(-1 / 24 / tes_time_constant_days),
|
standing_loss=1 - np.exp(-1 / 24 / tes_time_constant_days),
|
||||||
capital_cost=costs.at[name_type + " water tank storage", "fixed"],
|
capital_cost=costs.at[system_type + " water tank storage", "fixed"],
|
||||||
lifetime=costs.at[name_type + " water tank storage", "lifetime"],
|
lifetime=costs.at[system_type + " water tank storage", "lifetime"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if options["resistive_heaters"]:
|
if options["resistive_heaters"]:
|
||||||
key = f"{name_type} resistive heater"
|
key = f"{system_type} resistive heater"
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes + f" {name} resistive heater",
|
nodes + f" {heat_system} resistive heater",
|
||||||
bus0=nodes,
|
bus0=nodes,
|
||||||
bus1=nodes + f" {name} heat",
|
bus1=nodes + f" {heat_system} heat",
|
||||||
carrier=name + " resistive heater",
|
carrier=heat_system + " resistive heater",
|
||||||
efficiency=costs.at[key, "efficiency"],
|
efficiency=costs.at[key, "efficiency"],
|
||||||
capital_cost=costs.at[key, "efficiency"]
|
capital_cost=costs.at[key, "efficiency"]
|
||||||
* costs.at[key, "fixed"]
|
* costs.at[key, "fixed"]
|
||||||
@ -2015,16 +1996,16 @@ def add_heat(n, costs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if options["boilers"]:
|
if options["boilers"]:
|
||||||
key = f"{name_type} gas boiler"
|
key = f"{system_type} gas boiler"
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes + f" {name} gas boiler",
|
nodes + f" {heat_system} gas boiler",
|
||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
bus0=spatial.gas.df.loc[nodes, "nodes"].values,
|
bus0=spatial.gas.df.loc[nodes, "nodes"].values,
|
||||||
bus1=nodes + f" {name} heat",
|
bus1=nodes + f" {heat_system} heat",
|
||||||
bus2="co2 atmosphere",
|
bus2="co2 atmosphere",
|
||||||
carrier=name + " gas boiler",
|
carrier=heat_system + " gas boiler",
|
||||||
efficiency=costs.at[key, "efficiency"],
|
efficiency=costs.at[key, "efficiency"],
|
||||||
efficiency2=costs.at["gas", "CO2 intensity"],
|
efficiency2=costs.at["gas", "CO2 intensity"],
|
||||||
capital_cost=costs.at[key, "efficiency"]
|
capital_cost=costs.at[key, "efficiency"]
|
||||||
@ -2034,22 +2015,22 @@ def add_heat(n, costs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if options["solar_thermal"]:
|
if options["solar_thermal"]:
|
||||||
n.add("Carrier", name + " solar thermal")
|
n.add("Carrier", heat_system + " solar thermal")
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Generator",
|
"Generator",
|
||||||
nodes,
|
nodes,
|
||||||
suffix=f" {name} solar thermal collector",
|
suffix=f" {heat_system} solar thermal collector",
|
||||||
bus=nodes + f" {name} heat",
|
bus=nodes + f" {heat_system} heat",
|
||||||
carrier=name + " solar thermal",
|
carrier=heat_system + " solar thermal",
|
||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
capital_cost=costs.at[name_type + " solar thermal", "fixed"]
|
capital_cost=costs.at[system_type + " solar thermal", "fixed"]
|
||||||
* overdim_factor,
|
* overdim_factor,
|
||||||
p_max_pu=solar_thermal[nodes],
|
p_max_pu=solar_thermal[nodes],
|
||||||
lifetime=costs.at[name_type + " solar thermal", "lifetime"],
|
lifetime=costs.at[system_type + " solar thermal", "lifetime"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if options["chp"] and name == "urban central":
|
if options["chp"] and heat_system == "urban central":
|
||||||
# add gas CHP; biomass CHP is added in biomass section
|
# add gas CHP; biomass CHP is added in biomass section
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
@ -2106,16 +2087,16 @@ def add_heat(n, costs):
|
|||||||
lifetime=costs.at["central gas CHP", "lifetime"],
|
lifetime=costs.at["central gas CHP", "lifetime"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if options["chp"] and options["micro_chp"] and name != "urban central":
|
if options["chp"] and options["micro_chp"] and heat_system != "urban central":
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes + f" {name} micro gas CHP",
|
nodes + f" {heat_system} micro gas CHP",
|
||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
bus0=spatial.gas.df.loc[nodes, "nodes"].values,
|
bus0=spatial.gas.df.loc[nodes, "nodes"].values,
|
||||||
bus1=nodes,
|
bus1=nodes,
|
||||||
bus2=nodes + f" {name} heat",
|
bus2=nodes + f" {heat_system} heat",
|
||||||
bus3="co2 atmosphere",
|
bus3="co2 atmosphere",
|
||||||
carrier=name + " micro gas CHP",
|
carrier=heat_system + " micro gas CHP",
|
||||||
efficiency=costs.at["micro CHP", "efficiency"],
|
efficiency=costs.at["micro CHP", "efficiency"],
|
||||||
efficiency2=costs.at["micro CHP", "efficiency-heat"],
|
efficiency2=costs.at["micro CHP", "efficiency-heat"],
|
||||||
efficiency3=costs.at["gas", "CO2 intensity"],
|
efficiency3=costs.at["gas", "CO2 intensity"],
|
||||||
@ -2150,27 +2131,27 @@ def add_heat(n, costs):
|
|||||||
heat_demand["services space"] + heat_demand["residential space"]
|
heat_demand["services space"] + heat_demand["residential space"]
|
||||||
) / heat_demand.T.groupby(level=[1]).sum().T
|
) / heat_demand.T.groupby(level=[1]).sum().T
|
||||||
|
|
||||||
for name in n.loads[
|
for heat_system in n.loads[
|
||||||
n.loads.carrier.isin([x + " heat" for x in heat_systems])
|
n.loads.carrier.isin([x + " heat" for x in heat_systems])
|
||||||
].index:
|
].index:
|
||||||
node = n.buses.loc[name, "location"]
|
node = n.buses.loc[heat_system, "location"]
|
||||||
ct = pop_layout.loc[node, "ct"]
|
ct = pop_layout.loc[node, "ct"]
|
||||||
|
|
||||||
# weighting 'f' depending on the size of the population at the node
|
# weighting 'f' depending on the size of the population at the node
|
||||||
if "urban central" in name:
|
if "urban central" in heat_system:
|
||||||
f = dist_fraction[node]
|
f = dist_fraction[node]
|
||||||
elif "urban decentral" in name:
|
elif "urban decentral" in heat_system:
|
||||||
f = urban_fraction[node] - dist_fraction[node]
|
f = urban_fraction[node] - dist_fraction[node]
|
||||||
else:
|
else:
|
||||||
f = 1 - urban_fraction[node]
|
f = 1 - urban_fraction[node]
|
||||||
if f == 0:
|
if f == 0:
|
||||||
continue
|
continue
|
||||||
# get sector name ("residential"/"services"/or both "tot" for urban central)
|
# get sector name ("residential"/"services"/or both "tot" for urban central)
|
||||||
if "urban central" in name:
|
if "urban central" in heat_system:
|
||||||
sec = "tot"
|
sec = "tot"
|
||||||
if "residential" in name:
|
if "residential" in heat_system:
|
||||||
sec = "residential"
|
sec = "residential"
|
||||||
if "services" in name:
|
if "services" in heat_system:
|
||||||
sec = "services"
|
sec = "services"
|
||||||
|
|
||||||
# get floor aread at node and region (urban/rural) in m^2
|
# get floor aread at node and region (urban/rural) in m^2
|
||||||
@ -2178,7 +2159,7 @@ def add_heat(n, costs):
|
|||||||
pop_layout.loc[node].fraction * floor_area.loc[ct, "value"] * 10**6
|
pop_layout.loc[node].fraction * floor_area.loc[ct, "value"] * 10**6
|
||||||
).loc[sec] * f
|
).loc[sec] * f
|
||||||
# total heat demand at node [MWh]
|
# total heat demand at node [MWh]
|
||||||
demand = n.loads_t.p_set[name]
|
demand = n.loads_t.p_set[heat_system]
|
||||||
|
|
||||||
# space heat demand at node [MWh]
|
# space heat demand at node [MWh]
|
||||||
space_heat_demand = demand * w_space[sec][node]
|
space_heat_demand = demand * w_space[sec][node]
|
||||||
@ -2219,12 +2200,12 @@ def add_heat(n, costs):
|
|||||||
|
|
||||||
# add for each retrofitting strength a generator with heat generation profile following the profile of the heat demand
|
# add for each retrofitting strength a generator with heat generation profile following the profile of the heat demand
|
||||||
for strength in strengths:
|
for strength in strengths:
|
||||||
node_name = " ".join(name.split(" ")[2::])
|
node_name = " ".join(heat_system.split(" ")[2::])
|
||||||
n.madd(
|
n.madd(
|
||||||
"Generator",
|
"Generator",
|
||||||
[node],
|
[node],
|
||||||
suffix=" retrofitting " + strength + " " + node_name,
|
suffix=" retrofitting " + strength + " " + node_name,
|
||||||
bus=name,
|
bus=heat_system,
|
||||||
carrier="retrofitting",
|
carrier="retrofitting",
|
||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
p_nom_max=dE_diff[strength]
|
p_nom_max=dE_diff[strength]
|
||||||
|
Loading…
Reference in New Issue
Block a user