2022-09-16 13:04:04 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2024-02-19 15:21:48 +00:00
|
|
|
# SPDX-FileCopyrightText: : 2020-2024 The PyPSA-Eur Authors
|
2023-03-06 17:49:23 +00:00
|
|
|
#
|
|
|
|
# SPDX-License-Identifier: MIT
|
2023-03-09 11:45:43 +00:00
|
|
|
"""
|
|
|
|
Creates plots from summary CSV files.
|
|
|
|
"""
|
|
|
|
|
2023-02-23 09:30:32 +00:00
|
|
|
import logging
|
2023-03-06 08:27:45 +00:00
|
|
|
|
2023-03-06 08:35:40 +00:00
|
|
|
import matplotlib.gridspec as gridspec
|
2019-04-18 09:39:17 +00:00
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
import pandas as pd
|
2024-02-12 10:53:20 +00:00
|
|
|
from _helpers import configure_logging, set_scenario_config
|
2024-01-19 11:16:07 +00:00
|
|
|
from prepare_sector_network import co2_emissions_year
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2024-01-19 09:47:58 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
2021-07-01 18:09:04 +00:00
|
|
|
plt.style.use("ggplot")
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2019-07-16 14:00:21 +00:00
|
|
|
|
2019-04-18 09:39:17 +00:00
|
|
|
# consolidate and rename
|
|
|
|
def rename_techs(label):
|
2021-07-01 18:09:04 +00:00
|
|
|
prefix_to_remove = [
|
|
|
|
"residential ",
|
|
|
|
"services ",
|
|
|
|
"urban ",
|
|
|
|
"rural ",
|
|
|
|
"central ",
|
|
|
|
"decentral ",
|
|
|
|
]
|
|
|
|
|
|
|
|
rename_if_contains = [
|
|
|
|
"CHP",
|
|
|
|
"gas boiler",
|
|
|
|
"biogas",
|
|
|
|
"solar thermal",
|
|
|
|
"air heat pump",
|
|
|
|
"ground heat pump",
|
|
|
|
"resistive heater",
|
|
|
|
"Fischer-Tropsch",
|
|
|
|
]
|
|
|
|
|
|
|
|
rename_if_contains_dict = {
|
|
|
|
"water tanks": "hot water storage",
|
|
|
|
"retrofitting": "building retrofitting",
|
2021-10-23 19:16:05 +00:00
|
|
|
# "H2 Electrolysis": "hydrogen storage",
|
|
|
|
# "H2 Fuel Cell": "hydrogen storage",
|
|
|
|
# "H2 pipeline": "hydrogen storage",
|
2021-07-01 18:09:04 +00:00
|
|
|
"battery": "battery storage",
|
2023-08-23 11:26:27 +00:00
|
|
|
"H2 for industry": "H2 for industry",
|
|
|
|
"land transport fuel cell": "land transport fuel cell",
|
|
|
|
"land transport oil": "land transport oil",
|
|
|
|
"oil shipping": "shipping oil",
|
2021-10-23 19:16:05 +00:00
|
|
|
# "CC": "CC"
|
2021-07-01 18:09:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rename = {
|
|
|
|
"solar": "solar PV",
|
|
|
|
"Sabatier": "methanation",
|
|
|
|
"offwind": "offshore wind",
|
|
|
|
"offwind-ac": "offshore wind (AC)",
|
|
|
|
"offwind-dc": "offshore wind (DC)",
|
2023-11-06 14:46:46 +00:00
|
|
|
"offwind-float": "offshore wind (Float)",
|
2021-07-01 18:09:04 +00:00
|
|
|
"onwind": "onshore wind",
|
|
|
|
"ror": "hydroelectricity",
|
|
|
|
"hydro": "hydroelectricity",
|
|
|
|
"PHS": "hydroelectricity",
|
2022-06-23 13:17:41 +00:00
|
|
|
"NH3": "ammonia",
|
2021-07-01 18:09:04 +00:00
|
|
|
"co2 Store": "DAC",
|
|
|
|
"co2 stored": "CO2 sequestration",
|
|
|
|
"AC": "transmission lines",
|
|
|
|
"DC": "transmission lines",
|
|
|
|
"B2B": "transmission lines",
|
|
|
|
}
|
2019-07-16 14:00:21 +00:00
|
|
|
|
|
|
|
for ptr in prefix_to_remove:
|
|
|
|
if label[: len(ptr)] == ptr:
|
|
|
|
label = label[len(ptr) :]
|
|
|
|
|
|
|
|
for rif in rename_if_contains:
|
|
|
|
if rif in label:
|
|
|
|
label = rif
|
|
|
|
|
|
|
|
for old, new in rename_if_contains_dict.items():
|
|
|
|
if old in label:
|
|
|
|
label = new
|
|
|
|
|
|
|
|
for old, new in rename.items():
|
|
|
|
if old == label:
|
|
|
|
label = new
|
2018-08-02 14:14:38 +00:00
|
|
|
return label
|
|
|
|
|
|
|
|
|
2020-12-03 18:50:53 +00:00
|
|
|
preferred_order = pd.Index(
|
2022-09-16 13:04:04 +00:00
|
|
|
[
|
2020-12-03 18:50:53 +00:00
|
|
|
"transmission lines",
|
|
|
|
"hydroelectricity",
|
|
|
|
"hydro reservoir",
|
|
|
|
"run of river",
|
|
|
|
"pumped hydro storage",
|
2021-07-01 18:09:04 +00:00
|
|
|
"solid biomass",
|
|
|
|
"biogas",
|
|
|
|
"onshore wind",
|
|
|
|
"offshore wind",
|
|
|
|
"offshore wind (AC)",
|
|
|
|
"offshore wind (DC)",
|
|
|
|
"solar PV",
|
|
|
|
"solar thermal",
|
2021-10-23 19:16:05 +00:00
|
|
|
"solar rooftop",
|
2021-07-01 18:09:04 +00:00
|
|
|
"solar",
|
|
|
|
"building retrofitting",
|
|
|
|
"ground heat pump",
|
|
|
|
"air heat pump",
|
|
|
|
"heat pump",
|
|
|
|
"resistive heater",
|
|
|
|
"power-to-heat",
|
|
|
|
"gas-to-power/heat",
|
|
|
|
"CHP",
|
|
|
|
"OCGT",
|
|
|
|
"gas boiler",
|
|
|
|
"gas",
|
|
|
|
"natural gas",
|
|
|
|
"methanation",
|
2022-06-10 12:57:03 +00:00
|
|
|
"ammonia",
|
2021-07-01 18:09:04 +00:00
|
|
|
"hydrogen storage",
|
|
|
|
"power-to-gas",
|
|
|
|
"power-to-liquid",
|
|
|
|
"battery storage",
|
|
|
|
"hot water storage",
|
|
|
|
"CO2 sequestration",
|
2022-09-16 13:04:04 +00:00
|
|
|
]
|
2020-12-03 18:50:53 +00:00
|
|
|
)
|
|
|
|
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2019-04-18 09:39:17 +00:00
|
|
|
def plot_costs():
|
2021-07-01 18:09:04 +00:00
|
|
|
cost_df = pd.read_csv(
|
|
|
|
snakemake.input.costs, index_col=list(range(3)), header=list(range(n_header))
|
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
df = cost_df.groupby(cost_df.index.get_level_values(2)).sum()
|
|
|
|
|
|
|
|
# convert to billions
|
|
|
|
df = df / 1e9
|
|
|
|
|
|
|
|
df = df.groupby(df.index.map(rename_techs)).sum()
|
|
|
|
|
2023-06-15 16:52:25 +00:00
|
|
|
to_drop = df.index[df.max(axis=1) < snakemake.params.plotting["costs_threshold"]]
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2023-02-24 13:42:51 +00:00
|
|
|
logger.info(
|
2023-05-15 08:33:17 +00:00
|
|
|
f"Dropping technology with costs below {snakemake.params['plotting']['costs_threshold']} EUR billion per year"
|
2023-02-24 13:42:51 +00:00
|
|
|
)
|
2023-02-23 09:30:32 +00:00
|
|
|
logger.debug(df.loc[to_drop])
|
2019-04-18 09:39:17 +00:00
|
|
|
|
|
|
|
df = df.drop(to_drop)
|
|
|
|
|
2024-01-17 17:28:37 +00:00
|
|
|
logger.info(f"Total system cost of {round(df.sum().iloc[0])} EUR billion per year")
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2021-04-29 15:11:10 +00:00
|
|
|
new_index = preferred_order.intersection(df.index).append(
|
2018-08-02 14:14:38 +00:00
|
|
|
df.index.difference(preferred_order)
|
2022-09-16 13:04:04 +00:00
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2023-08-23 11:26:27 +00:00
|
|
|
# new_columns = df.sum().sort_values().index
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
fig, ax = plt.subplots(figsize=(12, 8))
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2023-08-23 11:26:27 +00:00
|
|
|
df.loc[new_index].T.plot(
|
2022-01-14 12:44:33 +00:00
|
|
|
kind="bar",
|
2022-09-16 13:04:04 +00:00
|
|
|
ax=ax,
|
2022-01-14 12:44:33 +00:00
|
|
|
stacked=True,
|
2023-06-15 16:52:25 +00:00
|
|
|
color=[snakemake.params.plotting["tech_colors"][i] for i in new_index],
|
2022-09-16 13:04:04 +00:00
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
handles, labels = ax.get_legend_handles_labels()
|
|
|
|
|
|
|
|
handles.reverse()
|
|
|
|
labels.reverse()
|
|
|
|
|
2023-06-15 16:52:25 +00:00
|
|
|
ax.set_ylim([0, snakemake.params.plotting["costs_max"]])
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
ax.set_ylabel("System Cost [EUR billion per year]")
|
|
|
|
|
|
|
|
ax.set_xlabel("")
|
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
ax.grid(axis="x")
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
ax.legend(
|
|
|
|
handles, labels, ncol=1, loc="upper left", bbox_to_anchor=[1, 1], frameon=False
|
|
|
|
)
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
fig.savefig(snakemake.output.costs, bbox_inches="tight")
|
2019-04-18 09:39:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
def plot_energy():
|
2021-07-01 18:09:04 +00:00
|
|
|
energy_df = pd.read_csv(
|
|
|
|
snakemake.input.energy, index_col=list(range(2)), header=list(range(n_header))
|
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
df = energy_df.groupby(energy_df.index.get_level_values(1)).sum()
|
|
|
|
|
|
|
|
# convert MWh to TWh
|
|
|
|
df = df / 1e6
|
|
|
|
|
|
|
|
df = df.groupby(df.index.map(rename_techs)).sum()
|
|
|
|
|
2019-04-18 09:39:17 +00:00
|
|
|
to_drop = df.index[
|
2023-06-15 16:52:25 +00:00
|
|
|
df.abs().max(axis=1) < snakemake.params.plotting["energy_threshold"]
|
2023-03-06 08:27:45 +00:00
|
|
|
]
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2023-02-24 13:42:51 +00:00
|
|
|
logger.info(
|
2023-05-15 08:33:17 +00:00
|
|
|
f"Dropping all technology with energy consumption or production below {snakemake.params['plotting']['energy_threshold']} TWh/a"
|
2023-02-24 13:42:51 +00:00
|
|
|
)
|
2023-02-23 09:30:32 +00:00
|
|
|
logger.debug(df.loc[to_drop])
|
2019-04-18 09:39:17 +00:00
|
|
|
|
|
|
|
df = df.drop(to_drop)
|
|
|
|
|
2024-01-17 17:28:37 +00:00
|
|
|
logger.info(f"Total energy of {round(df.sum().iloc[0])} TWh/a")
|
2019-12-19 10:39:38 +00:00
|
|
|
|
2023-04-05 16:18:53 +00:00
|
|
|
if df.empty:
|
|
|
|
fig, ax = plt.subplots(figsize=(12, 8))
|
|
|
|
fig.savefig(snakemake.output.energy, bbox_inches="tight")
|
|
|
|
return
|
|
|
|
|
2021-04-29 15:11:10 +00:00
|
|
|
new_index = preferred_order.intersection(df.index).append(
|
2018-08-02 14:14:38 +00:00
|
|
|
df.index.difference(preferred_order)
|
2022-09-16 13:04:04 +00:00
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2023-08-23 11:26:27 +00:00
|
|
|
# new_columns = df.columns.sort_values()
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
fig, ax = plt.subplots(figsize=(12, 8))
|
2019-12-19 10:39:38 +00:00
|
|
|
|
2023-08-23 11:26:27 +00:00
|
|
|
logger.debug(df.loc[new_index])
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2023-08-23 11:26:27 +00:00
|
|
|
df.loc[new_index].T.plot(
|
2022-01-14 12:44:33 +00:00
|
|
|
kind="bar",
|
|
|
|
ax=ax,
|
|
|
|
stacked=True,
|
2023-06-15 16:52:25 +00:00
|
|
|
color=[snakemake.params.plotting["tech_colors"][i] for i in new_index],
|
2022-01-14 12:44:33 +00:00
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
handles, labels = ax.get_legend_handles_labels()
|
|
|
|
|
|
|
|
handles.reverse()
|
|
|
|
labels.reverse()
|
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
ax.set_ylim(
|
2023-03-06 08:27:45 +00:00
|
|
|
[
|
2023-06-15 16:52:25 +00:00
|
|
|
snakemake.params.plotting["energy_min"],
|
|
|
|
snakemake.params.plotting["energy_max"],
|
2023-03-06 08:27:45 +00:00
|
|
|
]
|
2021-07-01 18:09:04 +00:00
|
|
|
)
|
2018-08-02 14:14:38 +00:00
|
|
|
|
|
|
|
ax.set_ylabel("Energy [TWh/a]")
|
|
|
|
|
|
|
|
ax.set_xlabel("")
|
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
ax.grid(axis="x")
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
ax.legend(
|
|
|
|
handles, labels, ncol=1, loc="upper left", bbox_to_anchor=[1, 1], frameon=False
|
|
|
|
)
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
fig.savefig(snakemake.output.energy, bbox_inches="tight")
|
2019-04-18 09:39:17 +00:00
|
|
|
|
2020-05-13 11:40:00 +00:00
|
|
|
|
|
|
|
def plot_balances():
|
2021-07-01 18:09:04 +00:00
|
|
|
co2_carriers = ["co2", "co2 stored", "process emissions"]
|
2020-05-13 11:40:00 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
balances_df = pd.read_csv(
|
|
|
|
snakemake.input.balances, index_col=list(range(3)), header=list(range(n_header))
|
|
|
|
)
|
2020-05-13 11:40:00 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
balances = {i.replace(" ", "_"): [i] for i in balances_df.index.levels[0]}
|
2021-05-24 20:11:24 +00:00
|
|
|
balances["energy"] = [
|
|
|
|
i for i in balances_df.index.levels[0] if i not in co2_carriers
|
|
|
|
]
|
2020-05-13 11:40:00 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
for k, v in balances.items():
|
2020-05-13 11:40:00 +00:00
|
|
|
df = balances_df.loc[v]
|
|
|
|
df = df.groupby(df.index.get_level_values(2)).sum()
|
|
|
|
|
|
|
|
# convert MWh to TWh
|
2021-07-01 18:09:04 +00:00
|
|
|
df = df / 1e6
|
2020-05-13 11:40:00 +00:00
|
|
|
|
|
|
|
# remove trailing link ports
|
2022-06-23 13:17:41 +00:00
|
|
|
df.index = [
|
2024-01-29 18:31:03 +00:00
|
|
|
(
|
2022-06-23 13:17:41 +00:00
|
|
|
i[:-1]
|
2024-01-24 14:48:33 +00:00
|
|
|
if (
|
|
|
|
(i not in ["co2", "NH3", "H2"])
|
|
|
|
and (i[-1:] in ["0", "1", "2", "3", "4"])
|
2024-01-29 18:31:03 +00:00
|
|
|
)
|
|
|
|
else i
|
2024-01-24 14:48:33 +00:00
|
|
|
)
|
2022-06-23 13:17:41 +00:00
|
|
|
for i in df.index
|
|
|
|
]
|
2020-05-13 11:40:00 +00:00
|
|
|
|
|
|
|
df = df.groupby(df.index.map(rename_techs)).sum()
|
|
|
|
|
2020-08-21 10:15:01 +00:00
|
|
|
to_drop = df.index[
|
2023-06-15 16:52:25 +00:00
|
|
|
df.abs().max(axis=1) < snakemake.params.plotting["energy_threshold"] / 10
|
2023-03-06 08:27:45 +00:00
|
|
|
]
|
2020-05-13 11:40:00 +00:00
|
|
|
|
2023-10-08 09:20:36 +00:00
|
|
|
units = "MtCO2/a" if v[0] in co2_carriers else "TWh/a"
|
2023-03-01 11:29:36 +00:00
|
|
|
logger.debug(
|
2023-05-15 08:33:17 +00:00
|
|
|
f"Dropping technology energy balance smaller than {snakemake.params['plotting']['energy_threshold']/10} {units}"
|
2023-03-01 11:29:36 +00:00
|
|
|
)
|
2023-02-23 09:30:32 +00:00
|
|
|
logger.debug(df.loc[to_drop])
|
2020-05-13 11:40:00 +00:00
|
|
|
|
|
|
|
df = df.drop(to_drop)
|
2020-08-21 10:15:01 +00:00
|
|
|
|
2024-01-17 17:28:37 +00:00
|
|
|
logger.debug(
|
|
|
|
f"Total energy balance for {v} of {round(df.sum().iloc[0],2)} {units}"
|
|
|
|
)
|
2020-05-13 11:40:00 +00:00
|
|
|
|
|
|
|
if df.empty:
|
|
|
|
continue
|
|
|
|
|
2021-04-29 15:11:10 +00:00
|
|
|
new_index = preferred_order.intersection(df.index).append(
|
|
|
|
df.index.difference(preferred_order)
|
2023-03-06 08:27:45 +00:00
|
|
|
)
|
2020-05-13 11:40:00 +00:00
|
|
|
|
|
|
|
new_columns = df.columns.sort_values()
|
2023-08-30 10:05:16 +00:00
|
|
|
|
2023-08-23 11:26:27 +00:00
|
|
|
fig, ax = plt.subplots(figsize=(12, 8))
|
2020-05-13 11:40:00 +00:00
|
|
|
|
|
|
|
df.loc[new_index, new_columns].T.plot(
|
|
|
|
kind="bar",
|
|
|
|
ax=ax,
|
|
|
|
stacked=True,
|
2023-06-15 16:52:25 +00:00
|
|
|
color=[snakemake.params.plotting["tech_colors"][i] for i in new_index],
|
2020-05-13 11:40:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
handles, labels = ax.get_legend_handles_labels()
|
|
|
|
|
|
|
|
handles.reverse()
|
|
|
|
labels.reverse()
|
|
|
|
|
|
|
|
if v[0] in co2_carriers:
|
|
|
|
ax.set_ylabel("CO2 [MtCO2/a]")
|
|
|
|
else:
|
|
|
|
ax.set_ylabel("Energy [TWh/a]")
|
|
|
|
|
|
|
|
ax.set_xlabel("")
|
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
ax.grid(axis="x")
|
2020-05-13 11:40:00 +00:00
|
|
|
|
2021-07-01 18:09:04 +00:00
|
|
|
ax.legend(
|
|
|
|
handles,
|
|
|
|
labels,
|
|
|
|
ncol=1,
|
|
|
|
loc="upper left",
|
|
|
|
bbox_to_anchor=[1, 1],
|
|
|
|
frameon=False,
|
|
|
|
)
|
2020-05-13 11:40:00 +00:00
|
|
|
|
2024-06-11 13:10:12 +00:00
|
|
|
fig.savefig(snakemake.output.balances[:-10] + k + ".svg", bbox_inches="tight")
|
2020-05-13 11:40:00 +00:00
|
|
|
|
|
|
|
|
2023-03-09 07:36:18 +00:00
|
|
|
def historical_emissions(countries):
|
2021-01-14 09:06:29 +00:00
|
|
|
"""
|
|
|
|
Read historical emissions to add them to the carbon budget plot.
|
|
|
|
"""
|
|
|
|
# https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16
|
|
|
|
# downloaded 201228 (modified by EEA last on 201221)
|
2023-08-24 12:19:34 +00:00
|
|
|
df = pd.read_csv(snakemake.input.co2, encoding="latin-1", low_memory=False)
|
2021-01-14 09:06:29 +00:00
|
|
|
df.loc[df["Year"] == "1985-1987", "Year"] = 1986
|
|
|
|
df["Year"] = df["Year"].astype(int)
|
|
|
|
df = df.set_index(
|
|
|
|
["Year", "Sector_name", "Country_code", "Pollutant_name"]
|
|
|
|
).sort_index()
|
|
|
|
|
|
|
|
e = pd.Series()
|
|
|
|
e["electricity"] = "1.A.1.a - Public Electricity and Heat Production"
|
|
|
|
e["residential non-elec"] = "1.A.4.b - Residential"
|
|
|
|
e["services non-elec"] = "1.A.4.a - Commercial/Institutional"
|
|
|
|
e["rail non-elec"] = "1.A.3.c - Railways"
|
|
|
|
e["road non-elec"] = "1.A.3.b - Road Transportation"
|
|
|
|
e["domestic navigation"] = "1.A.3.d - Domestic Navigation"
|
|
|
|
e["international navigation"] = "1.D.1.b - International Navigation"
|
|
|
|
e["domestic aviation"] = "1.A.3.a - Domestic Aviation"
|
2021-06-21 10:36:40 +00:00
|
|
|
e["international aviation"] = "1.D.1.a - International Aviation"
|
2021-01-14 09:06:29 +00:00
|
|
|
e["total energy"] = "1 - Energy"
|
|
|
|
e["industrial processes"] = "2 - Industrial Processes and Product Use"
|
|
|
|
e["agriculture"] = "3 - Agriculture"
|
|
|
|
e["LULUCF"] = "4 - Land Use, Land-Use Change and Forestry"
|
|
|
|
e["waste management"] = "5 - Waste management"
|
|
|
|
e["other"] = "6 - Other Sector"
|
|
|
|
e["indirect"] = "ind_CO2 - Indirect CO2"
|
2023-08-24 12:19:34 +00:00
|
|
|
e["other LULUCF"] = "4.H - Other LULUCF"
|
|
|
|
|
2021-06-21 10:36:40 +00:00
|
|
|
pol = ["CO2"] # ["All greenhouse gases - (CO2 equivalent)"]
|
2023-03-09 07:36:18 +00:00
|
|
|
if "GB" in countries:
|
|
|
|
countries.remove("GB")
|
|
|
|
countries.append("UK")
|
2021-06-21 10:36:40 +00:00
|
|
|
|
2023-08-24 12:19:34 +00:00
|
|
|
year = df.index.levels[0][df.index.levels[0] >= 1990]
|
2023-08-30 10:05:16 +00:00
|
|
|
|
2023-08-24 12:19:34 +00:00
|
|
|
missing = pd.Index(countries).difference(df.index.levels[2])
|
|
|
|
if not missing.empty:
|
|
|
|
logger.warning(
|
|
|
|
f"The following countries are missing and not considered when plotting historic CO2 emissions: {missing}"
|
|
|
|
)
|
|
|
|
countries = pd.Index(df.index.levels[2]).intersection(countries)
|
2023-08-30 10:05:16 +00:00
|
|
|
|
2021-01-14 09:06:29 +00:00
|
|
|
idx = pd.IndexSlice
|
2021-06-21 10:36:40 +00:00
|
|
|
co2_totals = (
|
2023-03-09 07:36:18 +00:00
|
|
|
df.loc[idx[year, e.values, countries, pol], "emissions"]
|
2021-06-21 10:36:40 +00:00
|
|
|
.unstack("Year")
|
|
|
|
.rename(index=pd.Series(e.index, e.values))
|
2021-01-14 09:06:29 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
co2_totals = (1 / 1e6) * co2_totals.groupby(level=0, axis=0).sum() # Gton CO2
|
2023-03-06 08:27:45 +00:00
|
|
|
|
2021-01-14 09:06:29 +00:00
|
|
|
co2_totals.loc["industrial non-elec"] = (
|
|
|
|
co2_totals.loc["total energy"]
|
|
|
|
- co2_totals.loc[
|
2023-03-06 08:27:45 +00:00
|
|
|
[
|
2021-01-14 09:06:29 +00:00
|
|
|
"electricity",
|
|
|
|
"services non-elec",
|
|
|
|
"residential non-elec",
|
|
|
|
"road non-elec",
|
|
|
|
"rail non-elec",
|
|
|
|
"domestic aviation",
|
|
|
|
"international aviation",
|
|
|
|
"domestic navigation",
|
|
|
|
"international navigation",
|
2023-03-06 08:27:45 +00:00
|
|
|
]
|
2021-01-14 09:06:29 +00:00
|
|
|
].sum()
|
2023-03-06 08:27:45 +00:00
|
|
|
)
|
2021-01-14 09:06:29 +00:00
|
|
|
|
2021-06-21 10:36:40 +00:00
|
|
|
emissions = co2_totals.loc["electricity"]
|
2024-02-17 22:38:00 +00:00
|
|
|
if options["transport"]:
|
2021-01-14 09:06:29 +00:00
|
|
|
emissions += co2_totals.loc[[i + " non-elec" for i in ["rail", "road"]]].sum()
|
2024-02-17 22:38:00 +00:00
|
|
|
if options["heating"]:
|
2021-01-14 09:06:29 +00:00
|
|
|
emissions += co2_totals.loc[
|
|
|
|
[i + " non-elec" for i in ["residential", "services"]]
|
|
|
|
].sum()
|
2024-02-17 22:38:00 +00:00
|
|
|
if options["industry"]:
|
2021-01-14 09:06:29 +00:00
|
|
|
emissions += co2_totals.loc[
|
2023-03-06 08:27:45 +00:00
|
|
|
[
|
2021-01-14 09:06:29 +00:00
|
|
|
"industrial non-elec",
|
|
|
|
"industrial processes",
|
|
|
|
"domestic aviation",
|
|
|
|
"international aviation",
|
2021-06-21 10:36:40 +00:00
|
|
|
"domestic navigation",
|
|
|
|
"international navigation",
|
2023-03-06 08:27:45 +00:00
|
|
|
]
|
2021-06-21 10:36:40 +00:00
|
|
|
].sum()
|
2021-01-14 09:06:29 +00:00
|
|
|
return emissions
|
|
|
|
|
|
|
|
|
2024-02-17 22:38:00 +00:00
|
|
|
def plot_carbon_budget_distribution(input_eurostat, options):
|
2021-01-14 09:06:29 +00:00
|
|
|
"""
|
|
|
|
Plot historical carbon emissions in the EU and decarbonization path.
|
2021-06-21 10:36:40 +00:00
|
|
|
"""
|
2021-01-14 09:06:29 +00:00
|
|
|
import seaborn as sns
|
2023-03-06 08:27:45 +00:00
|
|
|
|
2021-01-14 09:06:29 +00:00
|
|
|
sns.set()
|
|
|
|
sns.set_style("ticks")
|
|
|
|
plt.rcParams["xtick.direction"] = "in"
|
|
|
|
plt.rcParams["ytick.direction"] = "in"
|
|
|
|
plt.rcParams["xtick.labelsize"] = 20
|
2021-06-21 10:36:40 +00:00
|
|
|
plt.rcParams["ytick.labelsize"] = 20
|
2023-08-31 07:56:04 +00:00
|
|
|
|
2023-08-31 07:55:38 +00:00
|
|
|
emissions_scope = snakemake.params.emissions_scope
|
|
|
|
input_co2 = snakemake.input.co2
|
2021-01-14 09:06:29 +00:00
|
|
|
|
2023-08-24 12:19:34 +00:00
|
|
|
# historic emissions
|
|
|
|
countries = snakemake.params.countries
|
2023-08-31 07:55:38 +00:00
|
|
|
e_1990 = co2_emissions_year(
|
|
|
|
countries,
|
|
|
|
input_eurostat,
|
2024-02-17 22:38:00 +00:00
|
|
|
options,
|
2023-08-31 07:55:38 +00:00
|
|
|
emissions_scope,
|
|
|
|
input_co2,
|
|
|
|
year=1990,
|
|
|
|
)
|
2023-08-24 12:19:34 +00:00
|
|
|
emissions = historical_emissions(countries)
|
|
|
|
# add other years https://sdi.eea.europa.eu/data/0569441f-2853-4664-a7cd-db969ef54de0
|
2024-05-16 15:06:28 +00:00
|
|
|
emissions.loc[2019] = 3.414362
|
|
|
|
emissions.loc[2020] = 3.092434
|
|
|
|
emissions.loc[2021] = 3.290418
|
|
|
|
emissions.loc[2022] = 3.213025
|
2023-08-30 10:05:16 +00:00
|
|
|
|
2023-08-24 12:19:34 +00:00
|
|
|
if snakemake.config["foresight"] == "myopic":
|
|
|
|
path_cb = "results/" + snakemake.params.RDIR + "/csvs/"
|
|
|
|
co2_cap = pd.read_csv(path_cb + "carbon_budget_distribution.csv", index_col=0)[
|
|
|
|
["cb"]
|
2023-08-30 10:05:16 +00:00
|
|
|
]
|
2023-08-24 12:19:34 +00:00
|
|
|
co2_cap *= e_1990
|
|
|
|
else:
|
|
|
|
supply_energy = pd.read_csv(
|
|
|
|
snakemake.input.balances, index_col=[0, 1, 2], header=[0, 1, 2, 3]
|
|
|
|
)
|
|
|
|
co2_cap = (
|
|
|
|
supply_energy.loc["co2"].droplevel(0).drop("co2").sum().unstack().T / 1e9
|
2023-08-30 10:05:16 +00:00
|
|
|
)
|
2023-08-24 12:19:34 +00:00
|
|
|
co2_cap.rename(index=lambda x: int(x), inplace=True)
|
2023-08-30 10:05:16 +00:00
|
|
|
|
2021-01-14 09:06:29 +00:00
|
|
|
plt.figure(figsize=(10, 7))
|
|
|
|
gs1 = gridspec.GridSpec(1, 1)
|
|
|
|
ax1 = plt.subplot(gs1[0, 0])
|
2023-08-24 12:19:34 +00:00
|
|
|
ax1.set_ylabel("CO$_2$ emissions \n [Gt per year]", fontsize=22)
|
|
|
|
# ax1.set_ylim([0, 5])
|
2023-06-15 16:52:25 +00:00
|
|
|
ax1.set_xlim([1990, snakemake.params.planning_horizons[-1] + 1])
|
2021-06-21 10:36:40 +00:00
|
|
|
|
|
|
|
ax1.plot(emissions, color="black", linewidth=3, label=None)
|
|
|
|
|
2023-08-24 12:19:34 +00:00
|
|
|
# plot committed and under-discussion targets
|
2021-01-14 09:06:29 +00:00
|
|
|
# (notice that historical emissions include all countries in the
|
|
|
|
# network, but targets refer to EU)
|
|
|
|
ax1.plot(
|
|
|
|
[2020],
|
|
|
|
[0.8 * emissions[1990]],
|
|
|
|
marker="*",
|
|
|
|
markersize=12,
|
|
|
|
markerfacecolor="black",
|
2021-06-21 10:36:40 +00:00
|
|
|
markeredgecolor="black",
|
|
|
|
)
|
|
|
|
|
2021-01-14 09:06:29 +00:00
|
|
|
ax1.plot(
|
2023-08-24 12:19:34 +00:00
|
|
|
[2030],
|
|
|
|
[0.45 * emissions[1990]],
|
|
|
|
marker="*",
|
|
|
|
markersize=12,
|
|
|
|
markerfacecolor="black",
|
|
|
|
markeredgecolor="black",
|
|
|
|
)
|
2021-06-21 10:36:40 +00:00
|
|
|
|
2021-01-14 09:06:29 +00:00
|
|
|
ax1.plot(
|
|
|
|
[2030],
|
|
|
|
[0.6 * emissions[1990]],
|
|
|
|
marker="*",
|
|
|
|
markersize=12,
|
|
|
|
markerfacecolor="black",
|
|
|
|
markeredgecolor="black",
|
|
|
|
)
|
2021-06-21 10:36:40 +00:00
|
|
|
|
2021-01-14 09:06:29 +00:00
|
|
|
ax1.plot(
|
|
|
|
[2050, 2050],
|
|
|
|
[x * emissions[1990] for x in [0.2, 0.05]],
|
2021-06-21 10:36:40 +00:00
|
|
|
color="gray",
|
|
|
|
linewidth=2,
|
|
|
|
marker="_",
|
|
|
|
alpha=0.5,
|
|
|
|
)
|
|
|
|
|
2021-01-14 09:06:29 +00:00
|
|
|
ax1.plot(
|
2023-08-24 12:19:34 +00:00
|
|
|
[2050],
|
|
|
|
[0.0 * emissions[1990]],
|
|
|
|
marker="*",
|
|
|
|
markersize=12,
|
|
|
|
markerfacecolor="black",
|
|
|
|
markeredgecolor="black",
|
2023-10-05 10:03:06 +00:00
|
|
|
label="EU committed target",
|
2023-08-24 12:19:34 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
for col in co2_cap.columns:
|
|
|
|
ax1.plot(co2_cap[col], linewidth=3, label=col)
|
2021-06-21 10:36:40 +00:00
|
|
|
|
|
|
|
ax1.legend(
|
|
|
|
fancybox=True, fontsize=18, loc=(0.01, 0.01), facecolor="white", frameon=True
|
|
|
|
)
|
2023-08-30 10:05:16 +00:00
|
|
|
|
2023-08-24 12:19:34 +00:00
|
|
|
plt.grid(axis="y")
|
2024-06-11 13:10:12 +00:00
|
|
|
path = snakemake.output.balances.split("balances")[0] + "carbon_budget.svg"
|
2023-08-24 12:43:36 +00:00
|
|
|
plt.savefig(path, bbox_inches="tight")
|
2018-08-02 14:14:38 +00:00
|
|
|
|
2023-08-30 10:05:16 +00:00
|
|
|
|
2018-08-02 14:14:38 +00:00
|
|
|
if __name__ == "__main__":
|
2019-12-09 20:29:15 +00:00
|
|
|
if "snakemake" not in globals():
|
2023-03-06 18:09:45 +00:00
|
|
|
from _helpers import mock_snakemake
|
2022-08-01 14:04:14 +00:00
|
|
|
|
2023-08-24 12:43:36 +00:00
|
|
|
snakemake = mock_snakemake("plot_summary")
|
2023-03-06 08:27:45 +00:00
|
|
|
|
2024-02-12 10:53:20 +00:00
|
|
|
configure_logging(snakemake)
|
|
|
|
set_scenario_config(snakemake)
|
2022-07-20 09:35:12 +00:00
|
|
|
|
2020-11-30 12:21:38 +00:00
|
|
|
n_header = 4
|
|
|
|
|
2019-04-18 09:39:17 +00:00
|
|
|
plot_costs()
|
|
|
|
|
|
|
|
plot_energy()
|
2020-08-21 10:15:01 +00:00
|
|
|
|
|
|
|
plot_balances()
|
2021-06-21 10:36:40 +00:00
|
|
|
|
2024-02-17 16:51:26 +00:00
|
|
|
co2_budget = snakemake.params["co2_budget"]
|
2024-02-17 10:57:16 +00:00
|
|
|
if (
|
2024-02-17 16:51:26 +00:00
|
|
|
isinstance(co2_budget, str) and co2_budget.startswith("cb")
|
|
|
|
) or snakemake.params["foresight"] == "perfect":
|
2024-02-17 22:38:00 +00:00
|
|
|
options = snakemake.params.sector
|
|
|
|
plot_carbon_budget_distribution(snakemake.input.eurostat, options)
|