diff --git a/rules/postprocess.smk b/rules/postprocess.smk index 62d1bb49..6dd4c34a 100644 --- a/rules/postprocess.smk +++ b/rules/postprocess.smk @@ -153,7 +153,8 @@ rule plot_timeseries: timeseries_scotland_short=RESULTS + "graphs/timeseries-short-scotland_s{simpl}_{gb_regions}_ec_l{ll}_{opts}_{fes_scenario}_{planning_horizons}.pdf", timeseries_england_year=RESULTS + "graphs/timeseries-year-england_s{simpl}_{gb_regions}_ec_l{ll}_{opts}_{fes_scenario}_{planning_horizons}.pdf", timeseries_england_short=RESULTS + "graphs/timeseries-short-england_s{simpl}_{gb_regions}_ec_l{ll}_{opts}_{fes_scenario}_{planning_horizons}.pdf", - emission_timeseries=RESULTS + "graphs/timeseries-emissions_s{simpl}_{gb_regions}_ec_l{ll}_{opts}_{fes_scenario}_{planning_horizons}.pdf" + emission_timeseries=RESULTS + "graphs/timeseries-emissions_s{simpl}_{gb_regions}_ec_l{ll}_{opts}_{fes_scenario}_{planning_horizons}.pdf", + co2_barplot=RESULTS + "graphs/barplot-co2_s{simpl}_{gb_regions}_ec_l{ll}_{opts}_{fes_scenario}_{planning_horizons}.pdf", threads: 1 resources: mem_mb=10000, diff --git a/scripts/plot_timeseries.py b/scripts/plot_timeseries.py index 7ba37925..66756aa4 100644 --- a/scripts/plot_timeseries.py +++ b/scripts/plot_timeseries.py @@ -109,6 +109,81 @@ def plot_emission_timeseries(n): plt.show() +def get_store_interaction(n, store_name): + connect1 = n.links.query("bus1 == @store_name") + connect2 = n.links.query("bus2 == @store_name") + + connect_t = ( + pd.concat(( + n.links_t.p1[connect1.index], + n.links_t.p2[connect2.index] + ), axis=1) + .mul(-1.) + .groupby(n.links_t.p0.index.month).sum() + ) + connect = pd.concat((connect1, connect2)) + + connect_t = pd.concat(( + pd.DataFrame({ + "value": connect_t[connect.query("carrier == @carrier").index].sum(axis=1).mul(1e-6), # to MtCO2 + "carrier": carrier + }) + for carrier in connect.carrier.unique() + ), axis=0) + + connect_t["month"] = connect_t.index.map(lambda x: calendar.month_abbr[x]) + + return connect_t + + +def make_co2_barplot(n): + + bar_kwargs = { + "edgecolor": "black", + "linewidth": 1, + "alpha": 0.8, + "x": "month", + "y": "value", + "hue": "carrier", + "palette": "bright", + } + + storing_t = get_store_interaction(n, "gb co2 stored") + emitting_t = get_store_interaction(n, "gb co2 atmosphere") + + fig, axs = plt.subplots(1, 2, figsize=(16, 4)) + + sns.barplot( + data=emitting_t, + ax=axs[0], + **bar_kwargs + ) + + sns.barplot( + data=storing_t, + ax=axs[1], + **bar_kwargs + ) + + for ax in axs: + ax.set_xlabel("Month") + ax.legend(loc=9) + + axs[0].set_ylabel("Monthly CO2 Emissions by Tech [MtCO2]") + axs[1].set_ylabel("Monthly CO2 Removal by Tech [MtCO2]") + + total_stored = n.stores_t.e["gb co2 stored"].iloc[-1] * 1e-6 + total_emitted = n.stores_t.p["gb co2 atmosphere"].sum() * -1e-6 + + for ax, value, meaning in zip(axs[::-1], [total_stored, total_emitted], ["Stored", "Emitted"]): + ax.set_title(f"Total {meaning}: {value:.2f} MtCO2") + + plt.tight_layout() + plt.savefig(snakemake.output.co2_barplot) + plt.show() + + + if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake @@ -213,7 +288,6 @@ def intersection(lst1, lst2): fig, ax = plt.subplots(1, 1, figsize=(16, 6)) stackplot_to_ax( - # inflow.resample(freq).mean(), inflow.resample(freq).mean()[inflow.std().sort_values().index], ax=ax, color_mapper=tech_colors, @@ -305,3 +379,5 @@ def intersection(lst1, lst2): plt.savefig(snakemake.output[f"timeseries_{target}_short"]) plt.show() + + make_co2_barplot(n) diff --git a/scripts/prepare_network.py b/scripts/prepare_network.py index c0b615f5..6ec67a1c 100755 --- a/scripts/prepare_network.py +++ b/scripts/prepare_network.py @@ -386,25 +386,32 @@ def add_gas_ccs(n, costs): gb_buses = pd.Index(n.generators.loc[n.generators.bus.str.contains("GB")].bus.unique()) gb_buses = n.buses.loc[gb_buses].loc[n.buses.loc[gb_buses].carrier == "AC"].index - print("Adding gas ccs generation to buses") - print(gb_buses) - logger.warning("Current implementation of gas CCS should just be the Allam cycle") + logger.warning("Adding Allam cycle...") n.madd( "Link", gb_buses, - suffix=" gas CCS", + suffix=" allam", bus0=f"GB_gas_bus", bus1=gb_buses, - marginal_cost=costs.at["gas CCS", "efficiency"] - * costs.at["gas CCS", "VOM"], # NB: VOM is per MWel - capital_cost=costs.at["gas CCS", "efficiency"] - * costs.at["gas CCS", "fixed"], # NB: fixed cost is per MWel - carrier="GAS CCS", + bus2="gb co2 stored", + carrier="allam", p_nom_extendable=True, - efficiency=costs.at["gas CCS", "efficiency"], + # TODO: add costs to technology-data + capital_cost=0.6 * 1.5e6 * 0.1, # efficiency * EUR/MW * annuity + marginal_cost=2, + efficiency=0.6, + efficiency2=costs.at["gas", "CO2 intensity"], + lifetime=30., ) + """ + marginal_cost=costs.at["gas CCS", "efficiency"] + * costs.at["gas CCS", "VOM"], # NB: VOM is per MWel + capital_cost=costs.at["gas CCS", "efficiency"] + * costs.at["gas CCS", "fixed"], # NB: fixed cost is per MWel + efficiency=costs.at["gas CCS", "efficiency"], + """ # adapted from `add_heat` method in `scripts/prepare_sector_network.py` @@ -694,17 +701,17 @@ def add_dac(n, costs, daccs_removal_target): def add_biogas(n, costs): - biogas_potentials = pd.read_csv(snakemake.input.biomass_potentials, index_col=0) - biogas_potentials = biogas_potentials.loc[gb_buses.index].sum() - gb_buses = n.buses.loc[n.buses.index.str.contains("GB")] gb_buses = gb_buses.loc[gb_buses.carrier == "AC"] - + + biogas_potentials = pd.read_csv(snakemake.input.biomass_potentials, index_col=0) + biogas_potentials = biogas_potentials.loc[gb_buses.index, "biogas"].sum() + n.add("Bus", f"GB_biogas_bus", carrier="biogas") - n.madd( + n.add( "Store", "GB_biogas_store", bus="GB_biogas_bus", @@ -714,7 +721,7 @@ def add_biogas(n, costs): e_initial=biogas_potentials, ) - n.madd( + n.add( "Link", "biogas upgrading", bus0="GB_biogas_bus",