Geophysical characteristics of mitigation pathways (Supplementary Material, Table 2.SM.12)

Notebook sr15_2.SM.4_geophysical_characteristics

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).

sr15_2.SM.4_geophysical_characteristics

IPCC SR15 scenario assessment

Geophysical characteristics of mitigation pathways

This notebook computes Ggeophysical characteristics of mitigation pathways in the IPCC's "Special Report on Global Warming of 1.5°C". The notebook generates the data for Table 2.SM.12 in the Special Report.

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

In [1]:
import pandas as pd
import numpy as np
import yaml
import pyam
pyam - INFO: Running in a notebook, setting `pyam` logging level to `logging.INFO` and adding stderr handler

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.

In [2]:
sr1p5 = pyam.IamDataFrame(data='../data/iamc15_scenario_data_world_r2.0.xlsx')
pyam.utils - INFO: Reading `../data/iamc15_scenario_data_world_r2.0.xlsx`
In [3]:
sr1p5.load_meta('sr15_metadata_indicators.xlsx')
pyam.core - INFO: Importing metadata for 416 scenarios (for total of 416)
In [4]:
with open("sr15_specs.yaml", 'r') as stream:
    specs = yaml.load(stream, Loader=yaml.FullLoader)

cats = specs.pop('cats')

Downselect scenario ensemble to categories of interest for this assessment

In [5]:
sr1p5.meta.rename(columns={'Kyoto-GHG|2010 (SAR)': 'kyoto_ghg_2010'}, inplace=True)
In [6]:
filter_args_aim = dict(model='AIM*',
                       scenario=['SFCM*_1p5Degree', 'EMF33_Med2C_nofuel', 'EMF33_Med2C_none'],
                       keep=False)
In [7]:
df = (
    sr1p5
    .filter(kyoto_ghg_2010='in range', category=cats)
    .filter(**filter_args_aim)
)

Initialize a pyam.Statistics instance

In [8]:
stats = pyam.Statistics(df=df, groupby={'category': cats})
In [9]:
stats.add(df.meta['year of netzero CO2 emissions'],
          header='', subheader='Year of net-zero CO2 emissions')
In [10]:
header_peak = {'header': 'Geophysical characteristics at Peak Warming'}
header_2100 = {'header': 'Geophysical characteristics in 2100'}
In [11]:
stats.add(df.meta['median warming at peak (MAGICC6)'],
          **header_peak, subheader='Peak|Median warming')
In [12]:
peak_year = 'year of peak warming (MAGICC6)'
stats.add(df.meta[peak_year], **header_peak, subheader='Peak|Year')
In [13]:
def add_indicator(stats, data, subheader=None, df=df,
                  year=['Peak', 2100], headers=[header_peak, header_2100]):
    for y, h in zip(year, headers):
        if y == 'Peak':
            values = data.apply(lambda x: x[df.meta.loc[x.name[0:2]][peak_year]],
                              raw=False, axis=1)
        else:
            values = data.apply(lambda x: x[y], raw=False, axis=1)
        stats.add(values, **h, subheader='{}|{}'.format(y, subheader))
In [14]:
v = 'AR5 climate diagnostics|Concentration|CO2|MAGICC6|MED'
sh = 'CO2 [ppm]'
co2_concentation = df.filter(variable=v).timeseries()
add_indicator(stats, co2_concentation, sh)
In [15]:
v = 'AR5 climate diagnostics|Forcing|MAGICC6|MED'
sh = 'RF all [Wm2]'
rf_all = df.filter(variable=v).timeseries()
add_indicator(stats, rf_all, sh)
In [16]:
v = 'AR5 climate diagnostics|Forcing|CO2|MAGICC6|MED'
sh = 'RF CO2 [Wm2]'
rf_co2 = df.filter(variable=v).timeseries()
add_indicator(stats, rf_co2, sh)
In [17]:
sh = 'RF non-CO2 [Wm2]'
rf_all.index = rf_all.index.droplevel([2, 3, 4])
rf_co2.index = rf_co2.index.droplevel([2, 3, 4])
rf_non_co2 = rf_all - rf_co2
add_indicator(stats, rf_non_co2, sh)
In [18]:
for (h, n) in [(header_peak, '2016 to peak warming'),
               (header_2100, '2016-2100')]:

    stats.add(df.meta['cumulative CO2 emissions ({}, Gt CO2)'.format(n)], **h,
              subheader='cumulative CO2 emissions ({}, as submitted) [GtCO2]'.format(n))
In [19]:
harmonized_co2_vars = [
    'Diagnostics|MAGICC6|Harmonized Input|Emissions|CO2|Energy and Industrial Processes',
    'Diagnostics|MAGICC6|Harmonized Input|Emissions|CO2|AFOLU'
]

harmonized_co2 = (
    df.filter(variable=harmonized_co2_vars, year=range(2010, 2101, 10))
    .timeseries()
    .groupby(['model', 'scenario'])
    .sum()
)
In [20]:
baseyear = 2016
In [21]:
peak_harmonized_co2 = (
    harmonized_co2.apply(lambda x:
        pyam.cumulative(x, first_year=baseyear,
                        last_year=df.meta.loc[x.name[0:2]][peak_year]) / 1000,
        raw=False, axis=1
    )
)
stats.add(peak_harmonized_co2, **header_peak,
          subheader='cumulative CO2 emissions (2016 to peak warming, harmonized) [GtCO2]')
In [22]:
eoc_harmonized_co2 = (
    harmonized_co2.apply(lambda x:
        pyam.cumulative(x, first_year=baseyear, last_year=2100) / 1000,
        raw=False, axis=1
    )
)
stats.add(eoc_harmonized_co2, **header_2100,
          subheader='cumulative CO2 emissions (2016-2100, harmonized) [GtCO2]')
In [23]:
ex_prob = {}
for t in [1.5, 2.0, 2.5]:
    v = 'AR5 climate diagnostics|Temperature|Exceedance Probability|{} °C|MAGICC6'.format(t)
    sh = 'Exceedance Probability {} [%]'.format(t)
    ex_prob = df.filter(variable=v).timeseries() * 100
    add_indicator(stats, ex_prob, sh)

Overshoot severity

In [24]:
header_overshoot = {'header': 'Geophysical Characteristics of the Temperature Overshoot'}
In [25]:
variable = 'AR5 climate diagnostics|Temperature|Global Mean|MAGICC6|MED'

mean_temperature = (
    df.filter(variable=variable)
    .timeseries()
)
In [26]:
def exceedance(temperature, threshold):
    years = pyam.cross_threshold(temperature, threshold)
    
    exceedance_yr = years[0] if len(years) else np.nan
    return_yr = years[1] if len(years) > 1 else np.nan
    overshoot_yr_count = return_yr - exceedance_yr

    if not np.isnan(overshoot_yr_count):
         severity = (
             pyam.cumulative(temperature, exceedance_yr, return_yr)
             - (overshoot_yr_count + 1) * threshold)
    else:
        severity = np.nan

    return [exceedance_yr, return_yr, overshoot_yr_count, severity]
In [27]:
lst = []
for i in mean_temperature.index:
    lst.append(pd.DataFrame(exceedance(mean_temperature.loc[i], 1.5)).T)

ex_years_15 = pd.concat(lst)
ex_years_15.index = mean_temperature.index
ex_years_15.columns = ['Exceedance year', 'Return year', 'Overshoot years', 'Overshoot severity']
In [28]:
lst = []
for i in mean_temperature.index:
    lst.append(pd.DataFrame(exceedance(mean_temperature.loc[i], 2.0)).T)

ex_years_20 = pd.concat(lst)
ex_years_20.index = mean_temperature.index
ex_years_20.columns = ['Exceedance year', 'Return year', 'Overshoot years', 'Overshoot severity']
In [29]:
stats.add(ex_years_15['Exceedance year'], **header_overshoot,
          subheader='Exceedance year|1.5°C [year]')
In [30]:
stats.add(ex_years_20['Exceedance year'], **header_overshoot,
          subheader='Exceedance year|2.0°C [year]')
In [31]:
stats.add(ex_years_15['Overshoot years'], **header_overshoot,
          subheader='Overshoot duration|1.5°C [number of years]')
In [32]:
stats.add(ex_years_20['Overshoot years'], **header_overshoot,
          subheader='Overshoot duration|2.0°C [number of years]')
In [33]:
stats.add(ex_years_15['Overshoot severity'], **header_overshoot,
          subheader='Overshoot severity|1.5°C [temperature-years]')

Display and export summary statistics to xlsx

In [34]:
summary = stats.summarize(center='median', interquartile=True, custom_format='{:.1f}')
summary
Out[34]:
count Geophysical characteristics at Peak Warming ... Geophysical characteristics in 2100 Geophysical Characteristics of the Temperature Overshoot
median (interquartile range) Year of net-zero CO2 emissions Peak|Median warming Peak|Year Peak|CO2 [ppm] Peak|RF all [Wm2] Peak|RF CO2 [Wm2] Peak|RF non-CO2 [Wm2] cumulative CO2 emissions (2016 to peak warming, as submitted) [GtCO2] cumulative CO2 emissions (2016 to peak warming, harmonized) [GtCO2] ... cumulative CO2 emissions (2016-2100, as submitted) [GtCO2] cumulative CO2 emissions (2016-2100, harmonized) [GtCO2] 2100|Exceedance Probability 1.5 [%] 2100|Exceedance Probability 2.0 [%] 2100|Exceedance Probability 2.5 [%] Exceedance year|1.5°C [year] Exceedance year|2.0°C [year] Overshoot duration|1.5°C [number of years] Overshoot duration|2.0°C [number of years] Overshoot severity|1.5°C [temperature-years]
category Below 1.5C 5 2044.0 (2050.0, 2038.0) 1.5 (1.5, 1.5) 2041.0 (2046.0, 2040.0) 422.9 (424.1, 422.2) 2.9 (2.9, 2.8) 2.3 (2.3, 2.3) 0.6 (0.6, 0.6) 484.8 (489.5, 478.0) 461.1 (471.0, 455.9) ... 176.0 (182.5, 175.7) 150.3 (215.2, 148.0) 16.3 (18.7, 14.0) 3.2 (4.2, 2.5) 0.8 (1.0, 0.5)
1.5C low overshoot 37 2050.0 (2055.0, 2047.0) 1.6 (1.6, 1.5) 2048.0 (2050.0, 2045.0) 431.4 (435.3, 428.5) 3.0 (3.0, 2.9) 2.4 (2.4, 2.3) 0.6 (0.6, 0.5) 624.0 (672.2, 599.7) 624.4 (671.2, 593.0) ... 255.1 (361.4, 176.6) 271.0 (339.2, 144.1) 28.3 (32.3, 24.7) 7.2 (8.0, 6.2) 1.3 (1.5, 1.3) 2035.0 (2036.0, 2033.0) 27.0 (37.0, 21.0) 1.0 (2.1, 0.5)
1.5C high overshoot 36 2052.0 (2059.2, 2049.0) 1.7 (1.7, 1.6) 2051.0 (2053.0, 2048.0) 447.2 (454.3, 440.8) 3.2 (3.3, 3.1) 2.6 (2.7, 2.5) 0.6 (0.7, 0.6) 838.6 (933.0, 762.2) 864.7 (929.4, 764.0) ... 330.4 (629.6, 187.2) 356.2 (623.2, 174.5) 33.6 (44.8, 30.2) 8.4 (12.3, 7.6) 1.7 (2.7, 1.3) 2033.0 (2033.0, 2032.0) 52.0 (60.0, 43.0) 5.7 (7.9, 3.7)
Lower 2C 54 2069.5 (2078.8, 2063.2) 1.7 (1.8, 1.7) 2061.0 (2074.0, 2059.0) 453.9 (457.7, 445.6) 3.2 (3.3, 3.1) 2.6 (2.7, 2.5) 0.6 (0.7, 0.5) 986.8 (1079.0, 890.9) 997.2 (1068.9, 896.8) ... 842.8 (968.3, 783.3) 859.3 (974.0, 769.9) 65.6 (71.6, 58.5) 20.5 (25.8, 17.3) 7.0 (8.8, 5.7) 2033.0 (2034.0, 2032.0)
Higher 2C 54 2084.5 (inf, 2070.0) 1.9 (2.0, 1.9) 2077.5 (2099.8, 2069.2) 472.6 (478.4, 463.9) 3.4 (3.5, 3.3) 2.8 (2.9, 2.8) 0.5 (0.6, 0.5) 1320.2 (1453.4, 1165.9) 1323.6 (1488.5, 1152.1) ... 1262.1 (1453.4, 1002.8) 1262.1 (1472.5, 1001.9) 82.8 (85.9, 76.0) 37.8 (42.6, 31.1) 12.5 (15.3, 10.3) 2033.0 (2034.0, 2032.0)
Above 2C 182 inf (inf, inf) 3.1 (3.8, 2.2) 2100.0 (2100.0, 2100.0) 651.4 (777.4, 519.6) 5.4 (6.6, 3.9) 4.6 (5.5, 3.4) 0.8 (1.2, 0.6) 3545.3 (4790.2, 2000.5) 3527.3 (4782.8, 1984.0) ... 3545.3 (4790.2, 1977.4) 3527.3 (4782.8, 1969.9) 100.0 (100.0, 94.5) 96.4 (100.0, 68.0) 83.7 (96.6, 30.2) 2032.0 (2033.0, 2031.0) 2051.0 (2057.8, 2047.0) 35.0 (37.0, 26.0) [3]

6 rows × 27 columns

In [35]:
summary.to_excel('output/table_2.SM.12_geophysical_characteristics.xlsx')