Figures and indicators for SPM Figure 3b of illustrative pathways¶
Notebook spm_sr15_figure_3b_illustrative_pathways¶
This notebook is based on the Release 1.1 of the IAMC 1.5C Scenario Explorer and Data and refers to the published version of the IPCC Special Report on Global Warming of 1.5C (SR15).
The notebook is run with pyam release 0.5.0.
The source code of this notebook is available on GitHub (release 2.0.2).
IPCC SR15 scenario assessment¶
Characteristics of four illustrative model pathways¶
Figure 3b of the Summary for Policymakers¶
This notebook derives the figure panels and indicators for the table in Figure 3b in the Summary for Policymakers of the IPCC's "Special Report on Global Warming of 1.5°C".
The scenario data used in this analysis can be accessed and downloaded at https://data.ene.iiasa.ac.at/iamc-1.5c-explorer.
Load pyam
package and other dependencies¶
import pandas as pd
import numpy as np
import io
import itertools
import yaml
import math
import matplotlib.pyplot as plt
plt.style.use('style_sr15.mplstyle')
%matplotlib inline
import pyam
Import scenario data, categorization and specifications files¶
The metadata file with scenario categorisation and quantitative indicators can be downloaded at https://data.ene.iiasa.ac.at/iamc-1.5c-explorer.
Alternatively, it can be re-created using the notebook sr15_2.0_categories_indicators
.
The last cell of this section loads and assigns a number of auxiliary lists as defined in the categorization notebook.
sr1p5 = pyam.IamDataFrame(data='../data/iamc15_scenario_data_world_r2.0.xlsx')
sr1p5.load_meta('sr15_metadata_indicators.xlsx')
with open("sr15_specs.yaml", 'r') as stream:
specs = yaml.load(stream, Loader=yaml.FullLoader)
rc = pyam.run_control()
for item in specs.pop('run_control').items():
rc.update({item[0]: item[1]})
cats_15 = specs.pop('cats_15')
cats_15_no_lo = specs.pop('cats_15_no_lo')
marker = specs.pop('marker')
Downselect scenario ensemble to categories of interest for this assessment¶
sr1p5.meta.rename(columns={'Kyoto-GHG|2010 (SAR)': 'kyoto_ghg_2010'}, inplace=True)
df = sr1p5.filter(category=cats_15)
Global carbon dioxide emissions in four illustrative pathways¶
Figure SPM3b shows the contribution to CO2 emissions and removal by three categories in the four illustrative pathways.
This illustration does not use the emissions timeseries as reported by the models. This is because the variable Emissions|CO2|Energy and Industrial Processes
represents net emissions, incorporating carbon dioxide removal in this sector.
The steps below compute the gross emissions. The long variable names are mapped to short variables for easier readibility.
afolu_var = 'Emissions|CO2|AFOLU'
ene_ind_var = 'Emissions|CO2|Energy and Industrial Processes'
beccs_var ='Carbon Sequestration|CCS|Biomass'
We downselect the entire data to the four illustrative pathways (marker
scenarios) and the three variables of interest. For consistency with the figure in the SPM, the units are converted to Gt CO2.
pw = df.filter(marker=marker, variable=[afolu_var, ene_ind_var, beccs_var],
year=range(2010, 2101, 10))
pw.convert_unit('Mt CO2/yr', 'Gt CO2/yr', inplace=True)
As a first step, we extract the timeseries for the AFOLU emissions and rename the variable for brevity. This data will be used as is in this figure.
afolu = (
pw.filter(variable=afolu_var)
.rename(variable={afolu_var: 'AFOLU'})
)
The energy-and-industry and BECCS timeseries data needs some processing. It is first separated into two distinct dataframes, and the BECCS variable is renamed for brevity.
ene_ind = pw.filter(variable=ene_ind_var)
beccs = (
pw.filter(variable=beccs_var)
.rename(variable={beccs_var: 'BECCS'})
)
The variable Carbon Sequestration|CCS|Biomass
reports removed carbon dioxide as positive values. For use in this figure, the sign needs to be reversed.
beccs.data.value = - beccs.data.value
The LED
marker scenario does not use any BECCS by assumption of the scenario design. For this reason, the variable Carbon Sequestration|CCS|Biomass
was not defined when the MESSAGE team submitted the scenario results to the IAMC 1.5°C Scenario Data ensemble.
For easier computation, we add this data series manually here.
years = beccs.timeseries().columns
beccs.append(
pyam.IamDataFrame(
pd.DataFrame([0] * len(years), index=years).T,
model='MESSAGEix-GLOBIOM 1.0', scenario='LowEnergyDemand',
region='World', variable='BECCS', unit='Gt CO2/yr'),
inplace=True
)
As a third step, we compute the difference between net CO2 emissions from the energy sector & industry and BECCS to obtain gross CO2 emissions in that sector.
def get_value(df):
cols = ['model', 'scenario', 'region', 'year', 'unit']
return df.data.set_index(cols)['value']
diff = get_value(ene_ind) - get_value(beccs)
ene_ind_gross = pyam.IamDataFrame(diff, variable='Fossil fuel and industry')
We now combine the three contribution dataframes into one joint dataframe for plotting. Because the beccs
IamDataFrame was partially altered, concatenating directly causes an issue, so we remove all meta
columns from that dataframe beforehand.
beccs.meta = beccs.meta.drop(columns=beccs.meta.columns)
co2 = pyam.concat([ene_ind_gross, afolu, beccs])
We now proceed to plot the four illustrative pathways.
fig, ax = plt.subplots(1, 4, figsize=(14, 4), sharey=True)
for i, m in enumerate(['LED', 'S1', 'S2', 'S5']):
co2.filter(marker=m).stack_plot(ax=ax[i], total=True, legend=False)
ax[i].title.set_text(m)
ax[3].legend(loc=1)
base_year = 2010
compare_years = [2030, 2050]
years = [base_year] + compare_years
stats = pyam.Statistics(df=df, groupby={'marker': ['LED', 'S1', 'S2', 'S5']},
filters=[(('pathways', 'no & lo os 1.5'), {'category': cats_15_no_lo})])
CO2 and Kyoto GHG emissions reductions¶
co2 = (
df.filter(kyoto_ghg_2010='in range', variable='Emissions|CO2', year=years)
.convert_unit('Mt CO2/yr', 'Gt CO2/yr')
.timeseries()
)
for y in compare_years:
stats.add((co2[y] / co2[2010] - 1) * 100,
'CO2 emission reduction (% relative to 2010)',
subheader=y)
kyoto_ghg = (
df.filter(kyoto_ghg_2010='in range', variable='Emissions|Kyoto Gases (SAR-GWP100)', year=years)
.rename(unit={'Mt CO2-equiv/yr': 'Mt CO2e/yr'})
.convert_unit('Mt CO2e/yr','Gt CO2e/yr')
.timeseries()
)
for y in compare_years:
stats.add((kyoto_ghg[y] / kyoto_ghg[base_year] - 1) * 100,
'Kyoto-GHG emission reduction (SAR-GWP100), % relative to {})'.format(base_year),
subheader=y)
Final energy demand reduction relative to 2010¶
fe = df.filter(variable='Final Energy', year=years).timeseries()
for y in compare_years:
stats.add((fe[y] / fe[base_year] - 1) * 100,
'Final energy demand reduction relative to {} (%)'.format(base_year),
subheader=y)
Share of renewables in electricity generation¶
def add_stats_share(stats, var_list, name, total, total_name, years, df=df):
_df = df.filter(variable=var_list)
for v in var_list:
_df.require_variable(v, exclude_on_fail=True)
_df.filter(exclude=False, inplace=True)
component = (
_df.timeseries()
.groupby(['model', 'scenario']).sum()
)
share = component / total * 100
for y in years:
stats.add(share[y], header='Share of {} in {} (%)'.format(name, total_name),
subheader=y)
ele = df.filter(variable='Secondary Energy|Electricity', year=compare_years).timeseries()
ele.index = ele.index.droplevel([2, 3, 4])
ele_re_vars = [
'Secondary Energy|Electricity|Biomass',
'Secondary Energy|Electricity|Non-Biomass Renewables'
]
add_stats_share(stats, ele_re_vars, 'renewables', ele, 'electricity', compare_years)
Changes in primary energy mix¶
mapping = [
('coal', 'Coal'),
('oil', 'Oil'),
('gas', 'Gas'),
('nuclear', 'Nuclear'),
('bioenergy', 'Biomass'),
('non-biomass renewables', 'Non-Biomass Renewables')
]
for (n, v) in mapping:
data = df.filter(variable='Primary Energy|{}'.format(v), year=years).timeseries()
for y in compare_years:
stats.add((data[y] / data[base_year] - 1) * 100,
header='Primary energy from {} (% rel to {})'.format(n, base_year),
subheader=y)
Cumulative carbon capture and sequestration until the end of the century¶
def cumulative_ccs(variable, name, first_year=2016, last_year=2100):
data = (
df.filter(variable=variable)
.convert_unit('Mt CO2/yr', 'Gt CO2/yr')
.timeseries()
)
stats.add(
data.apply(pyam.cumulative, raw=False, axis=1,
first_year=first_year, last_year=last_year),
header='Cumulative {} until {} (GtCO2)'.format(name, last_year), subheader='')
cumulative_ccs('Carbon Sequestration|CCS', 'CCS')
cumulative_ccs('Carbon Sequestration|CCS|Biomass', 'BECCS')
Land cover for energy crops¶
Convert unit to SI unit (million square kilometers).
energy_crops = (
df.filter(variable='Land Cover|Cropland|Energy Crops', year=2050)
.convert_unit('million ha', 'million km2', factor=0.01)
.timeseries()
)
stats.add(energy_crops[2050], header='Land are for energy crops (million km2)')
Emissions from land use¶
species = ['CH4', 'N2O']
for n in species:
data = df.filter(kyoto_ghg_2010='in range', variable='Emissions|{}|AFOLU'.format(n), year=years).timeseries()
for y in compare_years:
stats.add((data[y] / data[base_year] - 1) * 100,
header='Agricultural {} emissions (% rel to {})'.format(n, base_year),
subheader=y)
Display summary statistics and export to xlsx
¶
summary = stats.summarize(interquartile=True, custom_format='{:.0f}').T
summary
summary.to_excel('output/spm_sr15_figure3b_indicators_table.xlsx')