Merge branch 'update-district-heating-cops' of https://github.com/PyPSA/pypsa-eur into update-district-heating-cops
This commit is contained in:
commit
10e0b30a40
@ -965,7 +965,7 @@ rule prepare_sector_network:
|
|||||||
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"),
|
heat_pump_sources=config_provider("sector", "heat_pump_sources"),
|
||||||
heat_systems=config_provider("sector", "heat_systems")
|
heat_systems=config_provider("sector", "heat_systems"),
|
||||||
input:
|
input:
|
||||||
unpack(input_profile_offwind),
|
unpack(input_profile_offwind),
|
||||||
**rules.cluster_gas_network.output,
|
**rules.cluster_gas_network.output,
|
||||||
|
@ -7,11 +7,15 @@ import numpy as np
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import xarray as xr
|
import xarray as xr
|
||||||
from _helpers import set_scenario_config
|
from _helpers import set_scenario_config
|
||||||
import sys; sys.path.append("..")
|
|
||||||
from scripts.enums.HeatSystemType import HeatSystemType
|
|
||||||
from CentralHeatingCopApproximator import CentralHeatingCopApproximator
|
from CentralHeatingCopApproximator import CentralHeatingCopApproximator
|
||||||
from DecentralHeatingCopApproximator import DecentralHeatingCopApproximator
|
from DecentralHeatingCopApproximator import DecentralHeatingCopApproximator
|
||||||
|
|
||||||
|
from scripts.enums.HeatSystemType import HeatSystemType
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append("..")
|
||||||
|
|
||||||
|
|
||||||
def get_cop(
|
def get_cop(
|
||||||
heat_system_type: str,
|
heat_system_type: str,
|
||||||
@ -52,7 +56,6 @@ def get_cop(
|
|||||||
).approximate_cop()
|
).approximate_cop()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class HeatSector(Enum):
|
class HeatSector(Enum):
|
||||||
"""
|
"""
|
||||||
Enumeration class representing different heat sectors.
|
Enumeration class representing different heat sectors.
|
||||||
@ -22,4 +24,3 @@ class HeatSector(Enum):
|
|||||||
str: The string representation of the heat sector.
|
str: The string representation of the heat sector.
|
||||||
"""
|
"""
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from .HeatSystemType import HeatSystemType
|
from scripts.enums.HeatSector import HeatSector
|
||||||
from .HeatSector import HeatSector
|
from scripts.enums.HeatSystemType import HeatSystemType
|
||||||
|
|
||||||
|
|
||||||
class HeatSystem(Enum):
|
class HeatSystem(Enum):
|
||||||
"""
|
"""
|
||||||
@ -99,7 +100,10 @@ class HeatSystem(Enum):
|
|||||||
"""
|
"""
|
||||||
if self == HeatSystem.URBAN_CENTRAL:
|
if self == HeatSystem.URBAN_CENTRAL:
|
||||||
return HeatSystemType.URBAN_CENTRAL
|
return HeatSystemType.URBAN_CENTRAL
|
||||||
elif self == HeatSystem.RESIDENTIAL_URBAN_DECENTRAL or self == HeatSystem.SERVICES_URBAN_DECENTRAL:
|
elif (
|
||||||
|
self == HeatSystem.RESIDENTIAL_URBAN_DECENTRAL
|
||||||
|
or self == HeatSystem.SERVICES_URBAN_DECENTRAL
|
||||||
|
):
|
||||||
return HeatSystemType.URBAN_DECENTRAL
|
return HeatSystemType.URBAN_DECENTRAL
|
||||||
elif self == HeatSystem.RESIDENTIAL_RURAL or self == HeatSystem.SERVICES_RURAL:
|
elif self == HeatSystem.RESIDENTIAL_RURAL or self == HeatSystem.SERVICES_RURAL:
|
||||||
return HeatSystemType.RURAL
|
return HeatSystemType.RURAL
|
||||||
@ -127,7 +131,7 @@ class HeatSystem(Enum):
|
|||||||
):
|
):
|
||||||
return HeatSector.SERVICES
|
return HeatSector.SERVICES
|
||||||
else:
|
else:
|
||||||
'tot'
|
"tot"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_rural(self) -> bool:
|
def is_rural(self) -> bool:
|
||||||
@ -154,7 +158,10 @@ class HeatSystem(Enum):
|
|||||||
bool
|
bool
|
||||||
True if the heat system is for urban decentralized areas, False otherwise.
|
True if the heat system is for urban decentralized areas, False otherwise.
|
||||||
"""
|
"""
|
||||||
if self == HeatSystem.RESIDENTIAL_URBAN_DECENTRAL or self == HeatSystem.SERVICES_URBAN_DECENTRAL:
|
if (
|
||||||
|
self == HeatSystem.RESIDENTIAL_URBAN_DECENTRAL
|
||||||
|
or self == HeatSystem.SERVICES_URBAN_DECENTRAL
|
||||||
|
):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -166,12 +173,14 @@ class HeatSystem(Enum):
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
bool True if the heat system is for urban areas, False otherwise. """
|
bool True if the heat system is for urban areas, False otherwise.
|
||||||
|
"""
|
||||||
return not self.is_rural
|
return not self.is_rural
|
||||||
|
|
||||||
def heat_demand_weighting(self, urban_fraction=None, dist_fraction=None) -> float:
|
def heat_demand_weighting(self, urban_fraction=None, dist_fraction=None) -> float:
|
||||||
"""
|
"""
|
||||||
Calculates the heat demand weighting based on urban fraction and distribution fraction.
|
Calculates the heat demand weighting based on urban fraction and
|
||||||
|
distribution fraction.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -214,5 +223,3 @@ class HeatSystem(Enum):
|
|||||||
The name for the heat pump costs.
|
The name for the heat pump costs.
|
||||||
"""
|
"""
|
||||||
return f"{self.central_or_decentral} {heat_source}-sourced heat pump"
|
return f"{self.central_or_decentral} {heat_source}-sourced heat pump"
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class HeatSystemType(Enum):
|
class HeatSystemType(Enum):
|
||||||
"""
|
"""
|
||||||
Enumeration representing different types of heat systems.
|
Enumeration representing different types of heat systems.
|
||||||
@ -32,4 +33,3 @@ class HeatSystemType(Enum):
|
|||||||
bool: True if the heat system type is central, False otherwise.
|
bool: True if the heat system type is central, False otherwise.
|
||||||
"""
|
"""
|
||||||
return self == HeatSystemType.URBAN_CENTRAL
|
return self == HeatSystemType.URBAN_CENTRAL
|
||||||
|
|
||||||
|
@ -22,9 +22,6 @@ from _helpers import (
|
|||||||
set_scenario_config,
|
set_scenario_config,
|
||||||
update_config_from_wildcards,
|
update_config_from_wildcards,
|
||||||
)
|
)
|
||||||
from scripts.enums.HeatSystem import HeatSystem
|
|
||||||
from scripts.enums.HeatSystemType import HeatSystemType
|
|
||||||
from scripts.enums.HeatSector import HeatSector
|
|
||||||
from add_electricity import calculate_annuity, sanitize_carriers, sanitize_locations
|
from add_electricity import calculate_annuity, sanitize_carriers, sanitize_locations
|
||||||
from build_energy_totals import (
|
from build_energy_totals import (
|
||||||
build_co2_totals,
|
build_co2_totals,
|
||||||
@ -40,6 +37,10 @@ from pypsa.geo import haversine_pts
|
|||||||
from pypsa.io import import_components_from_dataframe
|
from pypsa.io import import_components_from_dataframe
|
||||||
from scipy.stats import beta
|
from scipy.stats import beta
|
||||||
|
|
||||||
|
from scripts.enums.HeatSector import HeatSector
|
||||||
|
from scripts.enums.HeatSystem import HeatSystem
|
||||||
|
from scripts.enums.HeatSystemType import HeatSystemType
|
||||||
|
|
||||||
spatial = SimpleNamespace()
|
spatial = SimpleNamespace()
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -1833,7 +1834,11 @@ def add_heat(n, costs):
|
|||||||
solar_thermal = options["solar_cf_correction"] * solar_thermal / 1e3
|
solar_thermal = options["solar_cf_correction"] * solar_thermal / 1e3
|
||||||
|
|
||||||
cop = xr.open_dataarray(snakemake.input.cop_profiles)
|
cop = xr.open_dataarray(snakemake.input.cop_profiles)
|
||||||
for heat_system in HeatSystem: #this loops through all heat systems defined in _entities.HeatSystem
|
for (
|
||||||
|
heat_system
|
||||||
|
) in (
|
||||||
|
HeatSystem
|
||||||
|
): # this loops through all heat systems defined in _entities.HeatSystem
|
||||||
|
|
||||||
if heat_system == HeatSystem.URBAN_CENTRAL:
|
if heat_system == HeatSystem.URBAN_CENTRAL:
|
||||||
nodes = dist_fraction.index[dist_fraction > 0]
|
nodes = dist_fraction.index[dist_fraction > 0]
|
||||||
@ -1864,17 +1869,23 @@ def add_heat(n, costs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
## Add heat load
|
## Add heat load
|
||||||
factor = heat_system.heat_demand_weighting(urban_fraction=urban_fraction[nodes], dist_fraction=dist_fraction[nodes])
|
factor = heat_system.heat_demand_weighting(
|
||||||
|
urban_fraction=urban_fraction[nodes], dist_fraction=dist_fraction[nodes]
|
||||||
|
)
|
||||||
if not heat_system == HeatSystem.URBAN_CENTRAL:
|
if not heat_system == HeatSystem.URBAN_CENTRAL:
|
||||||
heat_load = (
|
heat_load = (
|
||||||
heat_demand[[heat_system.sector.value + " water", heat_system.sector.value + " space"]]
|
heat_demand[
|
||||||
|
[
|
||||||
|
heat_system.sector.value + " water",
|
||||||
|
heat_system.sector.value + " space",
|
||||||
|
]
|
||||||
|
]
|
||||||
.T.groupby(level=1)
|
.T.groupby(level=1)
|
||||||
.sum()
|
.sum()
|
||||||
.T[nodes]
|
.T[nodes]
|
||||||
.multiply(factor)
|
.multiply(factor)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if heat_system == HeatSystem.URBAN_CENTRAL:
|
if heat_system == HeatSystem.URBAN_CENTRAL:
|
||||||
heat_load = (
|
heat_load = (
|
||||||
heat_demand.T.groupby(level=1)
|
heat_demand.T.groupby(level=1)
|
||||||
@ -1895,10 +1906,16 @@ def add_heat(n, costs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
## Add heat pumps
|
## Add heat pumps
|
||||||
for heat_source in snakemake.params.heat_pump_sources[heat_system.system_type.value]:
|
for heat_source in snakemake.params.heat_pump_sources[
|
||||||
|
heat_system.system_type.value
|
||||||
|
]:
|
||||||
costs_name = heat_system.heat_pump_costs_name(heat_source)
|
costs_name = heat_system.heat_pump_costs_name(heat_source)
|
||||||
efficiency = (
|
efficiency = (
|
||||||
cop.sel(heat_system=heat_system.system_type.value, heat_source=heat_source, name=nodes)
|
cop.sel(
|
||||||
|
heat_system=heat_system.system_type.value,
|
||||||
|
heat_source=heat_source,
|
||||||
|
name=nodes,
|
||||||
|
)
|
||||||
.to_pandas()
|
.to_pandas()
|
||||||
.reindex(index=n.snapshots)
|
.reindex(index=n.snapshots)
|
||||||
if options["time_dep_hp_cop"]
|
if options["time_dep_hp_cop"]
|
||||||
@ -1951,7 +1968,9 @@ def add_heat(n, costs):
|
|||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
tes_time_constant_days = options["tes_tau"][heat_system.central_or_decentral]
|
tes_time_constant_days = options["tes_tau"][
|
||||||
|
heat_system.central_or_decentral
|
||||||
|
]
|
||||||
|
|
||||||
n.madd(
|
n.madd(
|
||||||
"Store",
|
"Store",
|
||||||
@ -1961,8 +1980,12 @@ def add_heat(n, costs):
|
|||||||
e_nom_extendable=True,
|
e_nom_extendable=True,
|
||||||
carrier=f"{heat_system} water tanks",
|
carrier=f"{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[heat_system.central_or_decentral + " water tank storage", "fixed"],
|
capital_cost=costs.at[
|
||||||
lifetime=costs.at[heat_system.central_or_decentral + " water tank storage", "lifetime"],
|
heat_system.central_or_decentral + " water tank storage", "fixed"
|
||||||
|
],
|
||||||
|
lifetime=costs.at[
|
||||||
|
heat_system.central_or_decentral + " water tank storage", "lifetime"
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
if options["resistive_heaters"]:
|
if options["resistive_heaters"]:
|
||||||
@ -2011,10 +2034,14 @@ def add_heat(n, costs):
|
|||||||
bus=nodes + f" {heat_system} heat",
|
bus=nodes + f" {heat_system} heat",
|
||||||
carrier=f"{heat_system} solar thermal",
|
carrier=f"{heat_system} solar thermal",
|
||||||
p_nom_extendable=True,
|
p_nom_extendable=True,
|
||||||
capital_cost=costs.at[heat_system.central_or_decentral + " solar thermal", "fixed"]
|
capital_cost=costs.at[
|
||||||
|
heat_system.central_or_decentral + " solar thermal", "fixed"
|
||||||
|
]
|
||||||
* overdim_factor,
|
* overdim_factor,
|
||||||
p_max_pu=solar_thermal[nodes],
|
p_max_pu=solar_thermal[nodes],
|
||||||
lifetime=costs.at[heat_system.central_or_decentral + " solar thermal", "lifetime"],
|
lifetime=costs.at[
|
||||||
|
heat_system.central_or_decentral + " solar thermal", "lifetime"
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
if options["chp"] and heat_system == HeatSystem.URBAN_CENTRAL:
|
if options["chp"] and heat_system == HeatSystem.URBAN_CENTRAL:
|
||||||
@ -2074,7 +2101,11 @@ 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 heat_system.value != "urban central":
|
if (
|
||||||
|
options["chp"]
|
||||||
|
and options["micro_chp"]
|
||||||
|
and heat_system.value != "urban central"
|
||||||
|
):
|
||||||
n.madd(
|
n.madd(
|
||||||
"Link",
|
"Link",
|
||||||
nodes + f" {heat_system} micro gas CHP",
|
nodes + f" {heat_system} micro gas CHP",
|
||||||
|
Loading…
Reference in New Issue
Block a user