Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional fixes on plots #56

Merged
merged 22 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,39 @@ rule plot_electricity_for_heats:
),


rule plot_heat_saving:
params:
clusters=config["plotting"]["clusters"],
planning_horizon=config["plotting"]["planning_horizon"],
output:
figure=RESULTS+"plot_heat_savings_{clusters}_{planning_horizon}.png",
figure_full=RESULTS+"plot_heat_savings_full_year_{clusters}_{planning_horizon}.png",
figure_flexibility=RESULTS+"plot_heat_flexibility_{clusters}_{planning_horizon}.png",
resources:
mem_mb=10000,
script:
"plots/plot_heat_savings.py"


rule plot_heat_savings:
input:
expand(
RESULTS
+ "plot_heat_savings_{clusters}_{planning_horizon}.png",
**config["plotting"],
),
expand(
RESULTS
+ "plot_heat_savings_full_year_{clusters}_{planning_horizon}.png",
**config["plotting"],
),
expand(
RESULTS
+ "plot_heat_flexibility_{clusters}_{planning_horizon}.png",
**config["plotting"],
),


rule plot_electricity_generation:
params:
clusters=config["plotting"]["clusters"],
Expand Down Expand Up @@ -366,6 +399,21 @@ rule plot_all:
+ "plot_electricity_for_heat_{clusters}_{planning_horizon}.png",
**config["plotting"],
),
expand(
RESULTS
+ "plot_heat_savings_{clusters}_{planning_horizon}.png",
**config["plotting"],
),
expand(
RESULTS
+ "plot_heat_savings_full_year_{clusters}_{planning_horizon}.png",
**config["plotting"],
),
expand(
RESULTS
+ "plot_heat_flexibility_{clusters}_{planning_horizon}.png",
**config["plotting"],
),
expand(
RESULTS
+ "table_heat_pumps_{clusters}.csv",
Expand Down
1 change: 1 addition & 0 deletions configs/EEE_study/config.retro_tes-industry_2050.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,4 @@ solving:
threads: 8
BarConvTol: 1.e-4
BarHomogeneous: 1
NumericFocus: 3
7 changes: 7 additions & 0 deletions plots/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,13 @@
]
)

# day-ahead prices for 2021 URL:https://www.ffe.de/en/publications/european-day-ahead-electricity-prices-in-2022/
HISTORIC_PRICES = {"AT": 106.9, "BE": 104.1, "CH": 114.9, "CZ": 100.7, "DE": 96.8,
"DK": 88.1, "EE": 86.7, "ES": 111.9, "FI": 72.3, "FR": 109.2,
"GR": 116.4, "HU": 113.9, "IT": 125.2, "LT": 90.5, "LV": 88.8,
"NL": 103.0, "NO": 74.7, "PL": 87.0, "PT": 112.0, "RO": 110.9,
"RS": 114.0, "SE": 66.0, "SI": 115.0, "SK": 102.8}


def rename_techs(label):

Expand Down
22 changes: 16 additions & 6 deletions plots/plot_capacity_expansion.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,29 @@ def plot_capacities(caps_df, clusters, planning_horizon, plot_width=7):
df = df[df.index != 'solid biomass transport']

# convert to GW
df = df / 1e3
df = df / 1e6
df = df.groupby(df.index.map(rename_techs)).sum()

caps_threshold = 10
caps_threshold = 10e-3
to_drop = df.index[df.max(axis=1) < caps_threshold] #df <

logger.info(
f"Dropping technology with capacity below {caps_threshold} GW"
f"Dropping technology with capacity below {caps_threshold} TW"
)
logger.debug(df.loc[to_drop])

df = df.drop(to_drop)

# remove extra technologies that are not expanded
drop_techs = ["gas boiler", "process emissions",
"solid biomass", "solid biomass CHP",
"gas storage",
"kerosene for aviation", "land transport oil", "naphtha for industry",
"shipping methanol", "shipping oil",
"coal", "lignite", "oil",
"coal for industry", "gas for industry"]
df = df.drop(set(df.index).intersection(set(drop_techs)))

logger.info(f"Total optimal capacity is {round(df.sum())} GW")

new_index = PREFERRED_ORDER.intersection(df.index).append(
Expand All @@ -75,11 +85,11 @@ def plot_capacities(caps_df, clusters, planning_horizon, plot_width=7):

plt.xticks(rotation=0, fontsize=10)

ax.set_ylabel("Capacity expansion [GW]")
ax.set_ylabel("Capacity expansion [TW]")

ax.set_xlabel("")
ax.set_ylim([0,16000])
ax.set_yticks(np.arange(0, 17000, 2000))
ax.set_ylim([0,16])
ax.set_yticks(np.arange(0, 17, 2))

x_ticks = list(df.columns)
if planning_horizon in ["2040", "2050"] and "Limited \nRenovation &\nCost-Optimal Heating" in x_ticks:
Expand Down
36 changes: 15 additions & 21 deletions plots/plot_co2_level.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,18 @@
"solid biomass for industry",
"gas for industry",
"coal for industry",
"methanol",
"oil",
"lignite",
"coal",
"shipping oil",
"shipping methanol",
"naphtha for industry",
"land transport oil",
"kerosene for aviation",

"transmission lines",
"distribution lines",
"process emissions",
"SMR",
"coal",
"lignite",
"methanol",
"oil",

"gas pipeline",
"H2 pipeline",

Expand All @@ -132,26 +132,17 @@
"methanation",
"BEV charger",
"V2G",
"SMR",
"methanolisation",

"battery storage",
"gas storage",
"H2 storage",
"TES",

"hydroelectricity",
"OCGT",
"CCGT",
"onshore wind",
"offshore wind",
"solar PV",
"solar thermal",
"solar rooftop",

"co2",
"CO2 sequestration",
"process emissions",

"gas CHP",
"resistive heater",
Expand Down Expand Up @@ -195,12 +186,14 @@ def get_co2_balance(n, nice_name):


def plot_co2_balance(co2_df, clusters, planning_horizon, plot_width=7):
# convert to Billion tCO2_eq
co2_df = co2_df / 1e9
# filter out technologies with very small emission
max_emissions = co2_df.abs().sum().max() / 2
co2_threshold = max_emissions / 100 # 1% of max
to_drop = co2_df.index[co2_df.abs().max(axis=1) < co2_threshold]
logger.info(
f"Dropping technology with co2 balance below {co2_threshold} ton CO2_eq per year"
f"Dropping technology with co2 balance below {co2_threshold} Bton CO2_eq per year"
)
logger.debug(co2_df.loc[to_drop])
co2_df = co2_df.drop(to_drop)
Expand Down Expand Up @@ -229,10 +222,11 @@ def plot_co2_balance(co2_df, clusters, planning_horizon, plot_width=7):
labels = labels[:-neg_co2_length] + labels[-neg_co2_length:][::-1]

plt.xticks(rotation=0, fontsize=10)
ax.set_ylabel("CO$_2$ emissions [tCO$_{2-eq}$]")
ax.set_ylabel("CO$_2$ emissions [BtCO$_{2-eq}$]")
ax.set_xlabel("")
ax.set_ylim([-4e9,4e9])
ax.set_yticks(np.arange(-4.0e9, 4.0e9, 5e8))
ax.set_yticks(np.arange(-4.0, 4.0, 0.5))
ax.set_ylim([-3.6,3.6])

x_ticks = list(co2_df.columns)
if planning_horizon in ["2040", "2050"] and "Limited \nRenovation &\nOptimal Heating" in x_ticks:
# replace name for Limited Renovation scenario for 2030 to be LROH
Expand Down Expand Up @@ -372,7 +366,7 @@ def fill_table_df(df, planning_horizon, scenarios, values):
co2_savings_df = co2_emission_BAU - table_emissions_df
co2_savings_df.index = ["CO2 emission savings [tCO2_eq]"]
# saving in cubic meter of gas (1 m3 natural gas = 1,9 kg CO2) Source: https://www.eeagrants.gov.pt/media/2776/conversion-guidelines.pdf
co2_savings_df.loc["Equivalent gas savings [m3]"] = co2_savings_df.loc["CO2 emission savings [tCO2_eq]", :] * 1000 / 1.9
co2_savings_df.loc["Equivalent gas savings [trillion m3]"] = co2_savings_df.loc["CO2 emission savings [tCO2_eq]", :] * 1000 / 1.9 / 1e12


# move to base directory
Expand Down
23 changes: 17 additions & 6 deletions plots/plot_electricity_bills.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
warnings.filterwarnings("ignore")
from _helpers import mock_snakemake, update_config_from_wildcards, load_network, \
change_path_to_pypsa_eur, change_path_to_base, \
CO2L_LIMITS, LINE_LIMITS, BAU_HORIZON
CO2L_LIMITS, LINE_LIMITS, BAU_HORIZON, HISTORIC_PRICES


def get_households():
Expand Down Expand Up @@ -123,6 +123,10 @@ def electricity_bills(network, households):
total_cost_country += total_gas_cost_country
# electricity bill per household [EUR/household] (households given in thousands)
elec_bills_household = total_cost_country / (households*1e3)

# add EU average bills
average_bills_household = total_cost_country.sum() / (households.sum() * 1e3)
elec_bills_household["EUR"] = average_bills_household

return elec_bills_household

Expand All @@ -141,7 +145,14 @@ def plot_electricity_cost(df_prices, name):
"Optimal Renovation and Electric Heating":"limegreen",
"Limited Renovation and Cost-Optimal Heating":"royalblue",
"No Renovation and Electric Heating":"#f4b609",
"BAU": "grey"}
"BAU": "grey",
"Historic data": '#900C3F'}

# add historic electricity price for BAU plot
if "BAU" in df_prices.index and name == "prices":
historic_prices = pd.Series(HISTORIC_PRICES).to_frame().T
historic_prices.index = ["Historic data"]
sorted_df_prices = pd.concat([sorted_df_prices, historic_prices], axis=0)

# plot as bar plot
fig, ax = plt.subplots(figsize=(7,3))
Expand Down Expand Up @@ -243,9 +254,9 @@ def electricity_prices(network, households):
# electricity bill per MWh [EUR/MWh]
energy_price_MWh = prices / total_load_country

# drop EU
if "EU" in energy_price_MWh.index:
energy_price_MWh.drop("EU", axis=0, inplace=True)
# add EU average
average_price_MWh = total_cost.sum() / total_load_country.sum()
energy_price_MWh["EUR"] = average_price_MWh

return energy_price_MWh

Expand All @@ -256,7 +267,7 @@ def electricity_prices(network, households):
snakemake = mock_snakemake(
"plot_electricity_bill",
clusters="48",
planning_horizon="2030",
planning_horizon="2020",
)
# update config based on wildcards
config = update_config_from_wildcards(snakemake.config, snakemake.wildcards)
Expand Down
26 changes: 13 additions & 13 deletions plots/plot_electricity_for_heat.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ def get_elec_consumption_for_heat(n):
return elec_demand_f_heating


def plot_elec_consumption_for_heat(dict_elec):
def plot_elec_consumption_for_heat(dict_elec, horizon):
# set heights for each subplots
if "BAU" in dict_elec.keys():
heights = [1.4]
heights = [1.5]
else:
heights = [1.4] * 4
fig = plt.figure(figsize=(6.4, sum(heights)))
Expand All @@ -85,7 +85,7 @@ def plot_elec_consumption_for_heat(dict_elec):
ax.set_facecolor("whitesmoke")

print("Hard coded coordinates on x-axis, selected for 3H granularity")
where = [359, 527]
where = [359, 695]

elec_demand_f_heating = elec_demand_f_heating.reset_index()[["ground heat pump", "air heat pump", "resistive heater", "gas boiler"]]
colors = ["#2fb537", "#48f74f", "#d8f9b8", "#db6a25"]
Expand All @@ -95,20 +95,20 @@ def plot_elec_consumption_for_heat(dict_elec):
linewidth=0, ax=ax
)

cumulative = (elec_demand_f_heating / 1e3).cumsum(axis=1)
ax.plot(cumulative.iloc[where[0]:where[1]], color='black', linewidth=0.5)

ax.set_xlabel("", fontsize=12)
ax.set_ylim([1,2000])
ax.set_yscale("log") # Set the y-axis to logarithmic scale
# get in y limits for all horizons
y_limits = {'2020':1600, '2030':1100, '2040':900, '2050': 900}

# Custom y-ticks for logarithmic scale
ax.yaxis.set_major_locator(ticker.LogLocator(base=10.0, numticks=10))
ax.yaxis.set_minor_locator(ticker.LogLocator(base=10.0, subs='auto'))
ax.yaxis.set_minor_formatter(ticker.NullFormatter())
ax.set_ylim([1, y_limits[horizon]])

if i < 3:
ax.set_xticks([])
ax.set_xlabel("")
if i == 3 or "BAU" in dict_elec.keys():
ticks = [i for i in range(where[0], where[1], 24)]
ticks = [i for i in range(where[0], where[1], 48)]
ax.set_xticks(ticks) # Set the tick positions
ticks = [
str(n.snapshots[i]).split(" ")[0].split("-")[2]+"."+str(n.snapshots[i]).split(" ")[0].split("-")[1]
Expand Down Expand Up @@ -136,10 +136,10 @@ def plot_elec_consumption_for_heat(dict_elec):
loc=[1.02, -.2], fontsize=10
)
if len(dict_elec.keys()) == 1:
ylabel = "Electricity and Gas \nConsumption to Cover \nHeating Demands [GW]"
ylabel = "Electricity and Gas \nConsumption to Cover \nHeating Demands [$GW_{el}$]"
axes[0].set_ylabel(ylabel, fontsize=10)
else:
ylabel = "Electricity and Gas Consumption to \n Cover Heating Demands [GW]"
ylabel = "Electricity and Gas Consumption to \n Cover Heating Demands [$GW_{el}$]"
axes[2].set_ylabel(ylabel, fontsize=10)
axes[2].yaxis.set_label_coords(-0.1, 1)
plt.subplots_adjust(hspace=0.3)
Expand Down Expand Up @@ -203,5 +203,5 @@ def plot_elec_consumption_for_heat(dict_elec):
total_elec_consumption_for_heat[name] = elec_consumption_for_heat

# plot and store electricity prices
plot_elec_consumption_for_heat(total_elec_consumption_for_heat)
plot_elec_consumption_for_heat(total_elec_consumption_for_heat, planning_horizon)

Loading
Loading