Skip to content

Commit

Permalink
move calculation of district heating share to its own script
Browse files Browse the repository at this point in the history
Now the script build_district_heat_share.py does what the old function
create_nodes_for_heating() in prepare_sector_networks.py did.

There is no need to build nodes lists for each heating sector, since
all nodes have district heating now.
  • Loading branch information
nworbmot committed Jan 15, 2024
1 parent 15488ed commit 0022a88
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 107 deletions.
22 changes: 22 additions & 0 deletions rules/build_sector.smk
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,27 @@ rule build_transport_demand:
"../scripts/build_transport_demand.py"




rule build_district_heat_share:
params:
sector=config["sector"],
input:
district_heat_share=RESOURCES + "district_heat_share.csv",
clustered_pop_layout=RESOURCES + "pop_layout_elec_s{simpl}_{clusters}.csv",
output:
district_heat_share=RESOURCES + "district_heat_share_elec_s{simpl}_{clusters}_{planning_horizons}.csv",
threads: 1
resources:
mem_mb=1000,
log:
LOGS + "build_district_heat_share_s{simpl}_{clusters}_{planning_horizons}.log",
conda:
"../envs/environment.yaml"
script:
"../scripts/build_district_heat_share.py"


rule prepare_sector_network:
params:
co2_budget=config["co2_budget"],
Expand Down Expand Up @@ -777,6 +798,7 @@ rule prepare_sector_network:
industrial_demand=RESOURCES
+ "industrial_energy_demand_elec_s{simpl}_{clusters}_{planning_horizons}.csv",
hourly_heat_demand_total=RESOURCES + "hourly_heat_demand_total_elec_s{simpl}_{clusters}.nc",
district_heat_share=RESOURCES + "district_heat_share_elec_s{simpl}_{clusters}_{planning_horizons}.csv",
temp_soil_total=RESOURCES + "temp_soil_total_elec_s{simpl}_{clusters}.nc",
temp_soil_rural=RESOURCES + "temp_soil_rural_elec_s{simpl}_{clusters}.nc",
temp_soil_urban=RESOURCES + "temp_soil_urban_elec_s{simpl}_{clusters}.nc",
Expand Down
77 changes: 77 additions & 0 deletions scripts/build_district_heat_share.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: : 2020-2023 The PyPSA-Eur Authors
#
# SPDX-License-Identifier: MIT
"""
Build district heat shares at each node, depending on investment year.
"""

import pandas as pd

from prepare_sector_network import get

import logging


logger = logging.getLogger(__name__)


if __name__ == "__main__":
if "snakemake" not in globals():
from _helpers import mock_snakemake

snakemake = mock_snakemake(
"build_heat_demands",
simpl="",
clusters=48,
)

investment_year = int(snakemake.wildcards.planning_horizons[-4:])

pop_layout = pd.read_csv(snakemake.input.clustered_pop_layout,
index_col=0)

district_heat_share = pd.read_csv(snakemake.input.district_heat_share,

This comment has been minimized.

Copy link
@lisazeyen

lisazeyen Jan 16, 2024

Contributor

the csv should be only used in combination with the data from the IDEES. We made the conservative approach and took the minimum value of the two data-sets. That is why it was calculated in energy_totals before.

This comment has been minimized.

Copy link
@nworbmot

nworbmot Jan 19, 2024

Author Member

That logic is still there, I didn't change it.

index_col=0).squeeze()

# make ct-based share nodal
district_heat_share = district_heat_share.loc[pop_layout.ct]
district_heat_share.index = pop_layout.index

# total urban population per country
ct_urban = pop_layout.urban.groupby(pop_layout.ct).sum()

# distribution of urban population within a country
pop_layout["urban_ct_fraction"] = pop_layout.urban / pop_layout.ct.map(ct_urban.get)

# fraction of node that is urban
urban_fraction = pop_layout.urban / pop_layout[["rural", "urban"]].sum(axis=1)

# maximum potential of urban demand covered by district heating
central_fraction = snakemake.config["sector"]["district_heating"]["potential"]

# district heating share at each node
dist_fraction_node = (
district_heat_share * pop_layout["urban_ct_fraction"] / pop_layout["fraction"]
)

# if district heating share larger than urban fraction -> set urban
# fraction to district heating share
urban_fraction = pd.concat([urban_fraction, dist_fraction_node], axis=1).max(axis=1)

# difference of max potential and today's share of district heating
diff = (urban_fraction * central_fraction) - dist_fraction_node
progress = get(snakemake.config["sector"]["district_heating"]["progress"], investment_year)
dist_fraction_node += diff * progress
logger.info(
f"Increase district heating share by a progress factor of {progress:.2%} "
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.to_csv(snakemake.output.district_heat_share)
6 changes: 4 additions & 2 deletions scripts/build_energy_totals.py
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ def build_energy_totals(countries, eurostat, swiss, idees):
return df


def build_district_heat_share(idees):
def build_district_heat_share(countries, idees):

# district heating share
district_heat = idees[
Expand All @@ -581,6 +581,8 @@ def build_district_heat_share(idees):

district_heat_share = district_heat/total_heat

district_heat_share = district_heat_share.reindex(countries)

# Missing district heating share
dh_share = pd.read_csv(
snakemake.input.district_heat_share, index_col=0, usecols=[0, 1]
Expand Down Expand Up @@ -761,7 +763,7 @@ def build_transport_data(countries, population, idees):
energy = build_energy_totals(countries, eurostat, swiss, idees)
energy.to_csv(snakemake.output.energy_name)

district_heat_share = build_district_heat_share(idees)
district_heat_share = build_district_heat_share(countries, idees)
district_heat_share.to_csv(snakemake.output.district_heat_share)

base_year_emissions = params["base_emissions_year"]
Expand Down
5 changes: 0 additions & 5 deletions scripts/build_population_weighted_energy_totals.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,4 @@
nodal_energy_totals.index = pop_layout.index
nodal_energy_totals = nodal_energy_totals.multiply(pop_layout.fraction, axis=0)

# district heating share should not be divided by population fraction
dh_share = energy_totals["district heat share"].loc[pop_layout.ct].fillna(0.0)
dh_share.index = pop_layout.index
nodal_energy_totals["district heat share"] = dh_share

nodal_energy_totals.to_csv(snakemake.output[0])
Loading

0 comments on commit 0022a88

Please sign in to comment.