add release notes, minor code improvements

This commit is contained in:
Fabian Neumann 2024-01-22 09:18:26 +01:00
parent d98ad95332
commit 2183e742b2
10 changed files with 75 additions and 43 deletions

View File

@ -28,6 +28,24 @@ Upcoming Release
* Cluster residential and services heat buses by default. Can be disabled with ``cluster_heat_buses: false``.
* Bugfix: Do not reduce district heat share when building population-weighted
energy statistics. Previously the district heating share was being multiplied
by the population weighting, reducing the DH share with multiple nodes.
* Move building of daily heat profile to its own rule
:mod:`build_hourly_heat_demand` from :mod:`prepare_sector_network`.
* In :mod:`build_energy_totals`, district heating shares are now reported in a
separate file.
* Move calculation of district heating share to its own rule
:mod:`build_district_heat_share`.
* Move building of distribution of existing heating to own rule
:mod:`build_existing_heating_distribution`. This makes the distribution of
existing heating to urban/rural, residential/services and spatially more
transparent.
PyPSA-Eur 0.9.0 (5th January 2024)
==================================

View File

@ -20,6 +20,12 @@ Rule ``add_existing_baseyear``
.. automodule:: add_existing_baseyear
Rule ``build_existing_heating_distribution``
==============================================================================
.. automodule:: build_existing_heating_distribution
Rule ``build_ammonia_production``
==============================================================================
@ -60,10 +66,20 @@ Rule ``build_gas_network``
.. automodule:: build_gas_network
Rule ``build_heat_demand``
Rule ``build_daily_heat_demand``
==============================================================================
.. automodule:: build_heat_demand
.. automodule:: build_daily_heat_demand
Rule ``build_hourly_heat_demand``
==============================================================================
.. automodule:: build_hourly_heat_demand
Rule ``build_district_heat_share``
==============================================================================
.. automodule:: build_district_heat_share
Rule ``build_industrial_distribution_key``
==============================================================================

View File

@ -28,9 +28,10 @@ rule solve_sector_network:
+ "logs/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}_memory.log",
python=RESULTS
+ "logs/elec_s{simpl}_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}_python.log",
threads: config["solving"]["solver_options"][config["solving"]["solver"]["options"]].get(
"threads", 4
)
threads:
config["solving"]["solver_options"][
config["solving"]["solver"]["options"]
].get("threads", 4)
resources:
mem_mb=config["solving"]["mem"],
walltime=config["solving"].get("walltime", "12:00:00"),

View File

@ -451,7 +451,7 @@ def add_heating_capacities_installed_before_baseyear(
efficiency=efficiency,
capital_cost=costs.at[costs_name, "efficiency"]
* costs.at[costs_name, "fixed"],
p_nom=existing_heating[(name, f"{heat_pump_type} heat pump")][nodes] * ratio / costs.at[costs_name, "efficiency"],
p_nom=existing_heating.loc[nodes, (name, f"{heat_pump_type} heat pump")] * ratio / costs.at[costs_name, "efficiency"],
build_year=int(grouping_year),
lifetime=costs.at[costs_name, "lifetime"],
)
@ -470,7 +470,7 @@ def add_heating_capacities_installed_before_baseyear(
* costs.at[f"{name_type} resistive heater", "fixed"]
),
p_nom=(
existing_heating[(name, "resistive heater")][nodes]
existing_heating.loc[nodes, (name, "resistive heater")]
* ratio
/ costs.at[f"{name_type} resistive heater", "efficiency"]
),
@ -493,7 +493,7 @@ def add_heating_capacities_installed_before_baseyear(
* costs.at[f"{name_type} gas boiler", "fixed"]
),
p_nom=(
existing_heating[(name, "gas boiler")][nodes]
existing_heating.loc[nodes, (name, "gas boiler")]
* ratio
/ costs.at[f"{name_type} gas boiler", "efficiency"]
),
@ -514,7 +514,7 @@ def add_heating_capacities_installed_before_baseyear(
capital_cost=costs.at["decentral oil boiler", "efficiency"]
* costs.at["decentral oil boiler", "fixed"],
p_nom= (
existing_heating[(name, "oil boiler")][nodes]
existing_heating.loc[nodes, (name, "oil boiler")]
* ratio
/ costs.at["decentral oil boiler", "efficiency"]),
build_year=int(grouping_year),

View File

@ -18,7 +18,8 @@ if __name__ == "__main__":
from _helpers import mock_snakemake
snakemake = mock_snakemake(
"build_heat_demands",
"build_daily_heat_demands",
scope="total",
simpl="",
clusters=48,
)

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: : 2020-2023 The PyPSA-Eur Authors
# SPDX-FileCopyrightText: : 2020-2024 The PyPSA-Eur Authors
#
# SPDX-License-Identifier: MIT
"""
@ -21,9 +21,10 @@ if __name__ == "__main__":
from _helpers import mock_snakemake
snakemake = mock_snakemake(
"build_heat_demands",
"build_district_heat_share",
simpl="",
clusters=48,
planning_horizons="2050",
)
investment_year = int(snakemake.wildcards.planning_horizons[-4:])
@ -68,10 +69,10 @@ if __name__ == "__main__":
f"resulting in new average share of {dist_fraction_node.mean():.2%}"
)
df = pd.DataFrame(dtype=float)
df["original district heat share"] = district_heat_share
df["district fraction of node"] = dist_fraction_node
df["urban fraction"] = urban_fraction
df = pd.DataFrame({
"original district heat share": district_heat_share,
"district fraction of node": dist_fraction_node,
"urban fraction": urban_fraction
}, dtype=float)
df.to_csv(snakemake.output.district_heat_share)

View File

@ -583,10 +583,10 @@ def build_district_heat_share(countries, idees):
# Missing district heating share
dh_share = pd.read_csv(
snakemake.input.district_heat_share, index_col=0, usecols=[0, 1]
)
).div(100).squeeze()
# make conservative assumption and take minimum from both data sets
district_heat_share = pd.concat(
[district_heat_share, dh_share.reindex(index=district_heat_share.index) / 100], axis=1
[district_heat_share, dh_share.reindex_like(district_heat_share)], axis=1
).min(axis=1)
district_heat_share.name = "district heat share"

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: : 2020-2023 The PyPSA-Eur Authors
# SPDX-FileCopyrightText: : 2020-2024 The PyPSA-Eur Authors
#
# SPDX-License-Identifier: MIT
"""
@ -7,8 +7,6 @@ Builds table of existing heat generation capacities for initial planning
horizon.
"""
import pandas as pd
import sys
from pypsa.descriptors import Dict
import numpy as np
import country_converter as coco
@ -17,19 +15,13 @@ cc = coco.CountryConverter()
def build_existing_heating():
# retrieve existing heating capacities
techs = [
"gas boiler",
"oil boiler",
"resistive heater",
"air heat pump",
"ground heat pump",
]
existing_heating = pd.read_csv(snakemake.input.existing_heating,
index_col=0,
header=0)
# data for Albania, Montenegro and Macedonia not included in database existing_heating.loc["Albania"] = np.nan
# data for Albania, Montenegro and Macedonia not included in database
existing_heating.loc["Albania"] = np.nan
existing_heating.loc["Montenegro"] = np.nan
existing_heating.loc["Macedonia"] = np.nan
@ -104,5 +96,14 @@ def build_existing_heating():
if __name__ == "__main__":
if "snakemake" not in globals():
from _helpers import mock_snakemake
snakemake = mock_snakemake(
"build_existing_heating_distribution",
simpl="",
clusters=48,
planning_horizons=2050,
)
build_existing_heating()

View File

@ -6,19 +6,19 @@
Build hourly heat demand time series from daily ones.
"""
import pandas as pd
import xarray as xr
from _helpers import generate_periodic_profiles, update_config_with_sector_opts
from itertools import product
import pandas as pd
import xarray as xr
from _helpers import generate_periodic_profiles
if __name__ == "__main__":
if "snakemake" not in globals():
from _helpers import mock_snakemake
snakemake = mock_snakemake(
"build_heat_demands",
"build_hourly_heat_demands",
scope="total",
simpl="",
clusters=48,
)
@ -58,12 +58,6 @@ if __name__ == "__main__":
heat_demand.index.name="snapshots"
print(heat_demand)
print(heat_demand.stack())
ds = heat_demand.stack().to_xarray()#xr.Dataset.from_dataframe(heat_demand)
print(ds)
ds = heat_demand.stack().to_xarray()
ds.to_netcdf(snakemake.output.heat_demand)

View File

@ -1654,7 +1654,7 @@ def build_heat_demand(n):
heat_demand[name] = (
heat_demand_shape[name] / heat_demand_shape[name].sum()
).multiply(pop_weighted_energy_totals[f"total {sector} {use}"]) * 1e6
electric_heat_supply[f"{sector} {use}"] = (
electric_heat_supply[name] = (
heat_demand_shape[name] / heat_demand_shape[name].sum()
).multiply(pop_weighted_energy_totals[f"electricity {sector} {use}"]) * 1e6