2022-09-16 13:04:04 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2023-02-16 10:50:55 +00:00
|
|
|
# SPDX-FileCopyrightText: : 2017-2023 The PyPSA-Eur Authors
|
2020-05-29 07:50:55 +00:00
|
|
|
#
|
2021-09-14 14:37:41 +00:00
|
|
|
# SPDX-License-Identifier: MIT
|
2020-05-29 07:50:55 +00:00
|
|
|
|
2019-08-08 13:02:28 +00:00
|
|
|
"""
|
2019-08-11 20:34:18 +00:00
|
|
|
Plots energy and cost summaries for solved networks.
|
2019-08-11 09:40:47 +00:00
|
|
|
|
|
|
|
Relevant Settings
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
Inputs
|
|
|
|
------
|
|
|
|
|
|
|
|
Outputs
|
|
|
|
-------
|
|
|
|
|
|
|
|
Description
|
|
|
|
-----------
|
2019-08-08 13:02:28 +00:00
|
|
|
"""
|
|
|
|
|
2019-11-28 07:22:52 +00:00
|
|
|
import logging
|
2022-09-16 13:04:04 +00:00
|
|
|
import os
|
2019-11-28 07:22:52 +00:00
|
|
|
|
2018-08-02 14:14:38 +00:00
|
|
|
import matplotlib.pyplot as plt
|
2022-09-16 13:04:04 +00:00
|
|
|
import pandas as pd
|
|
|
|
from _helpers import configure_logging
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2020-12-03 18:50:53 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2018-08-02 14:14:38 +00:00
|
|
|
def rename_techs(label):
|
2020-12-03 18:50:53 +00:00
|
|
|
if "H2" in label:
|
2018-08-02 14:14:38 +00:00
|
|
|
label = "hydrogen storage"
|
2018-10-26 08:28:54 +00:00
|
|
|
elif label == "solar":
|
2018-08-02 14:14:38 +00:00
|
|
|
label = "solar PV"
|
2019-01-16 11:08:46 +00:00
|
|
|
elif label == "offwind-ac":
|
|
|
|
label = "offshore wind ac"
|
|
|
|
elif label == "offwind-dc":
|
|
|
|
label = "offshore wind dc"
|
2018-10-26 08:28:54 +00:00
|
|
|
elif label == "onwind":
|
2018-08-02 14:14:38 +00:00
|
|
|
label = "onshore wind"
|
2018-10-26 08:28:54 +00:00
|
|
|
elif label == "ror":
|
2018-08-02 14:14:38 +00:00
|
|
|
label = "hydroelectricity"
|
2018-10-26 08:28:54 +00:00
|
|
|
elif label == "hydro":
|
2018-08-02 14:14:38 +00:00
|
|
|
label = "hydroelectricity"
|
2018-10-26 08:28:54 +00:00
|
|
|
elif label == "PHS":
|
2018-08-02 14:14:38 +00:00
|
|
|
label = "hydroelectricity"
|
2018-10-26 08:28:54 +00:00
|
|
|
elif "battery" in label:
|
2018-08-02 14:14:38 +00:00
|
|
|
label = "battery storage"
|
|
|
|
|
|
|
|
return label
|
|
|
|
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
preferred_order = pd.Index(
|
|
|
|
[
|
|
|
|
"transmission lines",
|
|
|
|
"hydroelectricity",
|
|
|
|
"hydro reservoir",
|
|
|
|
"run of river",
|
|
|
|
"pumped hydro storage",
|
|
|
|
"onshore wind",
|
|
|
|
"offshore wind ac",
|
|
|
|
"offshore wind dc",
|
|
|
|
"solar PV",
|
|
|
|
"solar thermal",
|
|
|
|
"OCGT",
|
|
|
|
"hydrogen storage",
|
|
|
|
"battery storage",
|
|
|
|
]
|
|
|
|
)
|
2020-12-03 18:50:53 +00:00
|
|
|
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2022-01-14 12:44:33 +00:00
|
|
|
def plot_costs(infn, config, fn=None):
|
2018-10-26 08:28:54 +00:00
|
|
|
## For now ignore the simpl header
|
2022-09-16 13:04:04 +00:00
|
|
|
cost_df = pd.read_csv(infn, index_col=list(range(3)), header=[1, 2, 3])
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
df = cost_df.groupby(cost_df.index.get_level_values(2)).sum()
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
# convert to billions
|
|
|
|
df = df / 1e9
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
df = df.groupby(df.index.map(rename_techs)).sum()
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
to_drop = df.index[df.max(axis=1) < config["plotting"]["costs_threshold"]]
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
print("dropping")
|
|
|
|
|
|
|
|
print(df.loc[to_drop])
|
|
|
|
|
|
|
|
df = df.drop(to_drop)
|
|
|
|
|
|
|
|
print(df.sum())
|
|
|
|
|
2022-09-28 18:33:50 +00:00
|
|
|
new_index = (preferred_order.intersection(df.index)).append(
|
2022-09-16 13:04:04 +00:00
|
|
|
df.index.difference(preferred_order)
|
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
new_columns = df.sum().sort_values().index
|
|
|
|
|
|
|
|
fig, ax = plt.subplots()
|
2022-09-16 13:04:04 +00:00
|
|
|
fig.set_size_inches((12, 8))
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
df.loc[new_index, new_columns].T.plot(
|
|
|
|
kind="bar",
|
|
|
|
ax=ax,
|
|
|
|
stacked=True,
|
|
|
|
color=[config["plotting"]["tech_colors"][i] for i in new_index],
|
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
handles, labels = ax.get_legend_handles_labels()
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
handles.reverse()
|
|
|
|
labels.reverse()
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
ax.set_ylim([0, config["plotting"]["costs_max"]])
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
ax.set_ylabel("System Cost [EUR billion per year]")
|
|
|
|
|
|
|
|
ax.set_xlabel("")
|
|
|
|
|
|
|
|
ax.grid(axis="y")
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
ax.legend(handles, labels, ncol=4, loc="upper left")
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
fig.tight_layout()
|
|
|
|
|
2018-10-26 08:28:54 +00:00
|
|
|
if fn is not None:
|
|
|
|
fig.savefig(fn, transparent=True)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
|
2022-01-14 12:44:33 +00:00
|
|
|
def plot_energy(infn, config, fn=None):
|
2022-09-16 13:04:04 +00:00
|
|
|
energy_df = pd.read_csv(infn, index_col=list(range(2)), header=[1, 2, 3])
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
df = energy_df.groupby(energy_df.index.get_level_values(1)).sum()
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
# convert MWh to TWh
|
|
|
|
df = df / 1e6
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
df = df.groupby(df.index.map(rename_techs)).sum()
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
to_drop = df.index[df.abs().max(axis=1) < config["plotting"]["energy_threshold"]]
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
print("dropping")
|
|
|
|
|
|
|
|
print(df.loc[to_drop])
|
|
|
|
|
|
|
|
df = df.drop(to_drop)
|
|
|
|
|
|
|
|
print(df.sum())
|
|
|
|
|
2022-09-28 18:33:50 +00:00
|
|
|
new_index = (preferred_order.intersection(df.index)).append(
|
2022-09-16 13:04:04 +00:00
|
|
|
df.index.difference(preferred_order)
|
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
new_columns = df.columns.sort_values()
|
|
|
|
|
|
|
|
fig, ax = plt.subplots()
|
2022-09-16 13:04:04 +00:00
|
|
|
fig.set_size_inches((12, 8))
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
df.loc[new_index, new_columns].T.plot(
|
|
|
|
kind="bar",
|
|
|
|
ax=ax,
|
|
|
|
stacked=True,
|
|
|
|
color=[config["plotting"]["tech_colors"][i] for i in new_index],
|
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
handles, labels = ax.get_legend_handles_labels()
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
handles.reverse()
|
|
|
|
labels.reverse()
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
ax.set_ylim([config["plotting"]["energy_min"], config["plotting"]["energy_max"]])
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
ax.set_ylabel("Energy [TWh/a]")
|
|
|
|
|
|
|
|
ax.set_xlabel("")
|
|
|
|
|
|
|
|
ax.grid(axis="y")
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
ax.legend(handles, labels, ncol=4, loc="upper left")
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
fig.tight_layout()
|
|
|
|
|
2018-10-26 08:28:54 +00:00
|
|
|
if fn is not None:
|
|
|
|
fig.savefig(fn, transparent=True)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2022-09-16 13:04:04 +00:00
|
|
|
if "snakemake" not in globals():
|
2019-12-09 20:29:15 +00:00
|
|
|
from _helpers import mock_snakemake
|
2022-09-16 13:04:04 +00:00
|
|
|
|
|
|
|
snakemake = mock_snakemake(
|
|
|
|
"plot_summary",
|
|
|
|
summary="energy",
|
|
|
|
simpl="",
|
|
|
|
clusters=5,
|
|
|
|
ll="copt",
|
|
|
|
opts="Co2L-24H",
|
|
|
|
attr="",
|
|
|
|
ext="png",
|
|
|
|
country="all",
|
|
|
|
)
|
2019-11-28 07:22:52 +00:00
|
|
|
configure_logging(snakemake)
|
|
|
|
|
2022-06-08 13:49:06 +00:00
|
|
|
config = snakemake.config
|
2022-01-14 12:44:33 +00:00
|
|
|
|
2022-06-08 13:49:06 +00:00
|
|
|
summary = snakemake.wildcards.summary
|
2018-10-26 08:28:54 +00:00
|
|
|
try:
|
|
|
|
func = globals()[f"plot_{summary}"]
|
|
|
|
except KeyError:
|
|
|
|
raise RuntimeError(f"plotting function for {summary} has not been defined")
|
|
|
|
|
2022-09-16 13:04:04 +00:00
|
|
|
func(
|
|
|
|
os.path.join(snakemake.input[0], f"{summary}.csv"), config, snakemake.output[0]
|
|
|
|
)
|