Skip to content

Commit 1490f47

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 7ce649c commit 1490f47

File tree

3 files changed

+276
-154
lines changed

3 files changed

+276
-154
lines changed

Snakefile

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ CDIR = Path(cutout_dir).joinpath("" if run["shared_cutouts"] else RDIR)
4343
RESULTS = "results/" + RDIR
4444

4545
run_prefix = config["run"]["prefix"]
46-
regret_scenarios = ["AriadneDemand", "LowDemand"]
47-
horizons = [2025, 2030, 2035]
46+
regret_scenarios = ["AriadneDemand", "LowDemand"]
47+
horizons = [2025, 2030, 2035]
4848

4949

5050
localrules:
@@ -1081,9 +1081,8 @@ rule regret_all:
10811081
decision=config_provider("run", "name"),
10821082
**config["scenario"],
10831083
),
1084-
elec_capa_comp_de_2025 = f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand_LT/elec_capa_comp_de_2025.png",
1085-
elec_price_comp_de = f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand/elec_price_comp_de.png",
1086-
1084+
elec_capa_comp_de_2025=f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand_LT/elec_capa_comp_de_2025.png",
1085+
elec_price_comp_de=f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand/elec_price_comp_de.png",
10871086

10881087

10891088
rule regret_all_variables:
@@ -1103,23 +1102,24 @@ rule regret_plots_lt:
11031102
planning_horizons=config_provider("scenario", "planning_horizons"),
11041103
plotting=config_provider("plotting"),
11051104
input:
1106-
networks = expand(
1105+
networks=expand(
11071106
"results/{run}/{scenario}/networks/base_s_27__none_{year}.nc",
11081107
run=run_prefix,
11091108
scenario=regret_scenarios,
1110-
year=horizons
1109+
year=horizons,
11111110
),
11121111
regret_variables=expand(
11131112
"results/{run}/{scenario}/regret_variables/regret_variables_{scenario}_full.xlsx",
11141113
run=run_prefix,
11151114
scenario=regret_scenarios,
11161115
),
11171116
output:
1118-
elec_capa_comp_de_2025 = f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand_LT/elec_capa_comp_de_2025.png",
1117+
elec_capa_comp_de_2025=f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand_LT/elec_capa_comp_de_2025.png",
11191118
dir=directory(f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand_LT"),
11201119
script:
11211120
"scripts/pypsa-de/regret_plots_lt.py"
11221121

1122+
11231123
rule regret_plots:
11241124
params:
11251125
scenarios=get_scenarios(run),
@@ -1134,7 +1134,7 @@ rule regret_plots:
11341134
**config["scenario"],
11351135
),
11361136
output:
1137-
elec_price_comp_de = f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand/elec_price_comp_de.png",
1137+
elec_price_comp_de=f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand/elec_price_comp_de.png",
11381138
dir=directory(f"results/{run_prefix}/regret_plots/Ariadne_vs_LowDemand"),
11391139
script:
11401140
"scripts/pypsa-de/regret_plots.py"

scripts/pypsa-de/regret_plots.py

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
1-
import logging
21
import os
32
import sys
43

5-
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
6-
sys.path.append(
7-
os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
8-
)
4+
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
5+
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
6+
7+
import collections
8+
import itertools
9+
import os
10+
import re
911

1012
import matplotlib.pyplot as plt
1113
import numpy as np
1214
import pandas as pd
1315
import pypsa
14-
import os, re, collections
15-
import itertools
16-
1716
from _helpers import configure_logging, mock_snakemake
1817

1918
groups = {
2019
"gas": ["gas CHP", "OCGT", "CCGT", "gas"],
2120
"heat vent": ["heat vent"],
2221
"water tanks": ["water tank", "water pit"],
23-
"heat pump" : ["heat pump"],
24-
"resistive heater" : ["resistive heater"],
22+
"heat pump": ["heat pump"],
23+
"resistive heater": ["resistive heater"],
2524
"biomass": ["biomass"],
2625
"lignite": ["lignite"],
2726
"coal": ["coal"],
@@ -31,18 +30,19 @@
3130
"offwind": ["offwind"],
3231
}
3332

33+
3434
def aggregate_by_keywords(opex_comp_agg, groups):
3535
"""
3636
Aggregate rows in opex_comp_agg according to keyword groups.
37-
37+
3838
Parameters
3939
----------
4040
opex_comp_agg : pd.DataFrame
4141
DataFrame with row index as technology names.
4242
groups : dict
43-
Keys = new aggregated name,
43+
Keys = new aggregated name,
4444
Values = list of substrings to match in the index.
45-
45+
4646
Returns
4747
-------
4848
pd.DataFrame
@@ -57,7 +57,6 @@ def aggregate_by_keywords(opex_comp_agg, groups):
5757
return df_out
5858

5959

60-
6160
if __name__ == "__main__":
6261
if "snakemake" not in globals():
6362
import os
@@ -72,21 +71,21 @@ def aggregate_by_keywords(opex_comp_agg, groups):
7271
configure_logging(snakemake)
7372
config = snakemake.config
7473
planning_horizons = snakemake.params.planning_horizons
75-
scenarios = ["AriadneDemand", "LowDemand"]
74+
scenarios = ["AriadneDemand", "LowDemand"]
7675
tech_colors = snakemake.params.plotting["tech_colors"]
7776

7877
# Nested dict: networks[year][scenario][decision] = Network
79-
networks = collections.defaultdict(
80-
lambda: collections.defaultdict(dict)
81-
)
78+
networks = collections.defaultdict(lambda: collections.defaultdict(dict))
8279

8380
for fn in snakemake.input.regret_networks:
8481
parts = fn.split(os.sep)
8582

8683
# scenario is the folder name 2 levels up
8784
scenario = parts[-3]
8885
if scenario not in scenarios:
89-
raise ValueError(f"Unexpected scenario '{scenario}' in {fn}. Allowed: {scenarios}")
86+
raise ValueError(
87+
f"Unexpected scenario '{scenario}' in {fn}. Allowed: {scenarios}"
88+
)
9089

9190
# extract year (4 digits before .nc)
9291
m = re.search(r"_(\d{4})\.nc$", fn)
@@ -121,17 +120,21 @@ def aggregate_by_keywords(opex_comp_agg, groups):
121120

122121
for i, year in enumerate(years):
123122
for scenario, decision in itertools.product(scenarios, decisions):
124-
125-
n = networks[year][scenario][decision]
126-
lmps = n.buses_t.marginal_price.loc[:,
127-
(n.buses.carrier == "AC") & (n.buses.index.str.startswith("DE"))]
128-
lmps_sorted = pd.DataFrame(lmps.values.flatten(), columns=["lmp"]).sort_values(by="lmp", ascending=False)
129-
lmps_sorted["percentage"] = np.arange(len(lmps_sorted)) / len(lmps_sorted) * 100
123+
n = networks[year][scenario][decision]
124+
lmps = n.buses_t.marginal_price.loc[
125+
:, (n.buses.carrier == "AC") & (n.buses.index.str.startswith("DE"))
126+
]
127+
lmps_sorted = pd.DataFrame(
128+
lmps.values.flatten(), columns=["lmp"]
129+
).sort_values(by="lmp", ascending=False)
130+
lmps_sorted["percentage"] = (
131+
np.arange(len(lmps_sorted)) / len(lmps_sorted) * 100
132+
)
130133

131134
ax[i].plot(
132-
lmps_sorted["percentage"],
133-
lmps_sorted["lmp"],
134-
label=f"{scenario}_{decision} (avg: {lmps_sorted['lmp'].mean():.2f})"
135+
lmps_sorted["percentage"],
136+
lmps_sorted["lmp"],
137+
label=f"{scenario}_{decision} (avg: {lmps_sorted['lmp'].mean():.2f})",
135138
)
136139

137140
ax[i].legend()
@@ -143,17 +146,15 @@ def aggregate_by_keywords(opex_comp_agg, groups):
143146
plt.savefig(snakemake.output.elec_price_comp_de, bbox_inches="tight")
144147
plt.close()
145148

146-
147149
# Print CO2 prices
148-
150+
149151
# for i, year in enumerate(years):
150152
# for scenario, decision in itertools.product(scenarios, decisions):
151153

152-
# n = networks[year][scenario][decision]
154+
# n = networks[year][scenario][decision]
153155

154156
# print(f"CO2 price for {year}, {scenario}, {decision}: {n.global_constraints.loc["CO2Limit", "mu"] + n.global_constraints.loc["co2_limit-DE", "mu"]}")
155157

156-
157158
# Plot OPEX
158159

159160
kwargs = {
@@ -166,7 +167,9 @@ def aggregate_by_keywords(opex_comp_agg, groups):
166167
axes = axes.flatten()
167168

168169
for i, year in enumerate(years):
169-
opex_comp = pd.DataFrame(columns=["_".join(tup) for tup in itertools.product(scenarios, decisions)])
170+
opex_comp = pd.DataFrame(
171+
columns=["_".join(tup) for tup in itertools.product(scenarios, decisions)]
172+
)
170173

171174
# Collect OPEX for all scenario-decision combinations
172175
for scenario, decision in itertools.product(scenarios, decisions):
@@ -175,7 +178,8 @@ def aggregate_by_keywords(opex_comp_agg, groups):
175178
opex = (
176179
n.statistics.opex(**kwargs)
177180
.filter(like="DE")
178-
.groupby("carrier").sum()
181+
.groupby("carrier")
182+
.sum()
179183
.multiply(1e-9) # to billion €
180184
)
181185
opex_comp[f"{scenario}_{decision}"] = opex
@@ -185,43 +189,59 @@ def aggregate_by_keywords(opex_comp_agg, groups):
185189
small_rows = opex_comp_agg.abs().max(axis=1) < 0.1
186190
other_row = opex_comp_agg[small_rows].sum(axis=0)
187191
opex_comp_agg = opex_comp_agg.loc[~small_rows]
188-
opex_comp_agg.loc['Other'] = other_row
192+
opex_comp_agg.loc["Other"] = other_row
189193

190194
# Prepare labels with line breaks
191-
labels = [col.replace('_', '\n') for col in opex_comp_agg.columns]
195+
labels = [col.replace("_", "\n") for col in opex_comp_agg.columns]
192196

193197
# Plot stacked bar
194198
ax = axes[i]
195199
bottom = np.zeros(len(opex_comp_agg.columns))
196200

197201
for tech in opex_comp_agg.index:
198202
values = opex_comp_agg.loc[tech].values
199-
ax.bar(labels, values, bottom=bottom, color=tech_colors.get(tech, '#333333'), label=tech)
203+
ax.bar(
204+
labels,
205+
values,
206+
bottom=bottom,
207+
color=tech_colors.get(tech, "#333333"),
208+
label=tech,
209+
)
200210

201211
# Add numbers in the middle, except for 'Other'
202-
if tech != 'Other':
212+
if tech != "Other":
203213
for j, val in enumerate(values):
204214
if val > 0: # only if positive
205215
ax.text(
206-
j,
207-
bottom[j] + val/2, # middle of the segment
208-
f'{val:.2f}',
209-
ha='center', va='center', fontsize=8, color='white'
216+
j,
217+
bottom[j] + val / 2, # middle of the segment
218+
f"{val:.2f}",
219+
ha="center",
220+
va="center",
221+
fontsize=8,
222+
color="white",
210223
)
211224

212225
bottom += values
213226

214227
# Add total sum labels on top of bars
215228
totals = opex_comp_agg.sum(axis=0)
216229
for j, total in enumerate(totals):
217-
ax.text(j, total + total*0.02, f'{total:.2f}', ha='center', va='bottom', fontsize=10)
230+
ax.text(
231+
j,
232+
total + total * 0.02,
233+
f"{total:.2f}",
234+
ha="center",
235+
va="bottom",
236+
fontsize=10,
237+
)
218238

219239
# Adjust y-limit
220-
ax.set_ylim(0, max(totals)*1.08)
221-
ax.set_ylabel('OPEX [billion €]')
222-
ax.set_title(f'Stacked OPEX composition by technology, {year}')
240+
ax.set_ylim(0, max(totals) * 1.08)
241+
ax.set_ylabel("OPEX [billion €]")
242+
ax.set_title(f"Stacked OPEX composition by technology, {year}")
223243

224244
# Legend outside
225-
axes[-1].legend(loc='upper left', bbox_to_anchor=(1,1))
226-
plt.savefig(snakemake.output[-1] + f"/opex_comp_de.png", bbox_inches="tight")
245+
axes[-1].legend(loc="upper left", bbox_to_anchor=(1, 1))
246+
plt.savefig(snakemake.output[-1] + "/opex_comp_de.png", bbox_inches="tight")
227247
plt.close()

0 commit comments

Comments
 (0)