Descriptive statistics of electricity generation by fuel (Table 2.7)

Notebook sr15_2.4.2.2_electricity_generation_statistics

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.4.2.2_electricity_generation_statistics

IPCC SR15 scenario assessment

Descriptive statistics of electricity generation

This notebook computes indicators and diagnostics of the primary-energy timeseries by fuel for Table 2.7 in 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

In [1]:
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
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)

rc = pyam.run_control()
for item in specs.pop('run_control').items():
    rc.update({item[0]: item[1]})
cats = specs.pop('cats')
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

In [5]:
years = [2020, 2030, 2050]
In [6]:
df = sr1p5.filter(category=cats_15, year=years)

Initialize a pyam.Statistics instance

In [7]:
stats = pyam.Statistics(df=df,
                        filters=[('all 1.5', {}),
                                 ('no & lo os 1.5', {'category': cats_15_no_lo}),
                                 ('hi os 1.5', {'category': ['1.5C high overshoot']})
                                ], rows=True)
In [8]:
header='Electricity generation (EJ)'
header_share='Share in electricity generation (%)'
header_growth='Growth (factor)'

statistics_settings = dict(
    header=header,
    header_share='Share in electricity generation (%)',
    header_growth='Growth (factor)',
    growth_year=2050,
    base_year=2020
)
In [9]:
def add_statistics(data, base, row, growth_year, base_year,
                   header, header_share, header_growth):
    stats.add(data, header=header, row=row)
    if base is not None:
        stats.add(data / base * 100, header=header_share, row=row)
    stats.add(data[growth_year] / data[base_year] - 1,
              header=header_growth, row=row,
              subheader='{}-{}'.format(base_year, growth_year))

Extract total electricity generation timeseries and add summary statistics

In [10]:
se = df.filter(variable='Secondary Energy|Electricity').timeseries()
se.index = se.index.droplevel([2, 3, 4])
In [11]:
add_statistics(se, None, 'total generation', **statistics_settings)

Compute share of renewables by various types in electricity generation

Only use scenarios for this indicator that report both biomass and the aggregate non-biomass timeseries - otherwise, the share would be distorted.

All renewables (biomass and non-biomass)

In [12]:
df_pe_res = df.filter()
df_pe_res.require_variable('Secondary Energy|Electricity|Non-Biomass Renewables', exclude_on_fail=True)
df_pe_res.require_variable('Secondary Energy|Electricity|Biomass', exclude_on_fail=True)
df_pe_res.filter(exclude=False, inplace=True)
pyam.core - INFO: 5 scenarios do not include required variable `Secondary Energy|Electricity|Non-Biomass Renewables`, marked as `exclude: True` in metadata
pyam.core - INFO: 5 scenarios do not include required variable `Secondary Energy|Electricity|Biomass`, marked as `exclude: True` in metadata
In [13]:
res = (
    df_pe_res.filter(variable=['Secondary Energy|Electricity|Biomass',
                               'Secondary Energy|Electricity|Non-Biomass Renewables'])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [14]:
add_statistics(res, se, 'renewables', **statistics_settings)

Biomass

In [15]:
res_bio = (
    df_pe_res.filter(variable=['Secondary Energy|Electricity|Biomass'])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [16]:
add_statistics(res_bio, se, 'biomass', **statistics_settings)

Non-biomass renewables

In [17]:
res_non_bio = (
    df_pe_res.filter(variable=['Secondary Energy|Electricity|Non-Biomass Renewables'])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [18]:
add_statistics(res_non_bio, se, 'non-biomass', **statistics_settings)

Renewable energy from wind and solar

As above, verify that scenarios report values for both 'Wind' and 'Solar'

In [19]:
df_win_sol = df.filter()
df_win_sol.require_variable('Secondary Energy|Electricity|Solar', exclude_on_fail=True)
df_win_sol.require_variable('Secondary Energy|Electricity|Wind', exclude_on_fail=True)
df_win_sol.filter(exclude=False, inplace=True)
pyam.core - INFO: 5 scenarios do not include required variable `Secondary Energy|Electricity|Solar`, marked as `exclude: True` in metadata
pyam.core - INFO: 5 scenarios do not include required variable `Secondary Energy|Electricity|Wind`, marked as `exclude: True` in metadata
In [20]:
win_sol = (
    df_win_sol.filter(variable=['Secondary Energy|Electricity|Solar',
                                'Secondary Energy|Electricity|Wind '])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [21]:
add_statistics(win_sol, se, 'wind & solar', **statistics_settings)

Compute share of nuclear in electricity generation

In [22]:
nuc = (
    df.filter(variable=['Secondary Energy|Electricity|Nuclear'])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [23]:
add_statistics(nuc, se, 'nuclear', **statistics_settings)

Compute share of fossil in electricity generation

In [24]:
df_fossil = df.filter()
df_fossil.require_variable('Secondary Energy|Electricity|Coal', exclude_on_fail=True)
df_fossil.require_variable('Secondary Energy|Electricity|Gas', exclude_on_fail=True)
df_fossil.require_variable('Secondary Energy|Electricity|Oil', exclude_on_fail=True)
df_fossil.filter(exclude=False, inplace=True)
pyam.core - INFO: 5 scenarios do not include required variable `Secondary Energy|Electricity|Coal`, marked as `exclude: True` in metadata
pyam.core - INFO: 5 scenarios do not include required variable `Secondary Energy|Electricity|Gas`, marked as `exclude: True` in metadata
pyam.core - INFO: 5 scenarios do not include required variable `Secondary Energy|Electricity|Oil`, marked as `exclude: True` in metadata
In [25]:
fossil = (
    df.filter(variable=['Secondary Energy|Electricity|Coal',
                        'Secondary Energy|Electricity|Gas',
                        'Secondary Energy|Electricity|Oil'])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [26]:
add_statistics(fossil, se, 'fossil', **statistics_settings)
In [27]:
coal = (
    df_fossil.filter(variable=['Secondary Energy|Electricity|Coal'])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [28]:
add_statistics(coal, se, 'coal', **statistics_settings)
In [29]:
gas = (
    df_fossil.filter(variable=['Secondary Energy|Electricity|Gas'])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [30]:
add_statistics(gas, se, 'gas', **statistics_settings)
In [31]:
oil = (
    df_fossil.filter(variable=['Secondary Energy|Electricity|Oil'])
    .timeseries()
    .groupby(['model', 'scenario']).sum()
)
In [32]:
add_statistics(oil, se, 'oil', **statistics_settings)

Display and export summary statistics for all 1.5°C pathways to xlsx

In [33]:
summary = (
    stats.summarize(center='median', fullrange=True)
    .reindex(columns=['count', header, header_share, header_growth], level=0)
)
summary
Out[33]:
count Electricity generation (EJ) Share in electricity generation (%) Growth (factor)
median (max, min) 2020 2030 2050 2020 2030 2050 2020-2050
all 1.5 total generation 85 100.09 (113.98, 83.53) 120.01 (177.51, 81.28) 224.78 (363.10, 126.96) 1.31 (2.55, 0.28)
renewables 85 26.38 (41.80, 18.26) 59.50 (111.70, 30.06) 153.72 (324.26, 84.69) 27.95 (41.84, 17.38) 51.51 (79.67, 25.11) 77.52 (96.65, 35.58) 5.08 (10.88, 2.37)
biomass 85 1.52 (7.00, 0.66) 3.55 (11.96, 0.79) 16.32 (40.32, 0.21) 1.55 (7.30, 0.63) 2.77 (13.29, 0.72) 8.02 (30.28, 0.08) 6.53 (38.14, -0.93)
non-biomass 85 24.48 (35.72, 17.60) 55.68 (101.90, 25.79) 136.40 (323.91, 53.79) 25.00 (40.43, 16.75) 47.16 (78.27, 23.10) 66.75 (96.46, 27.51) 4.75 (10.64, 1.38)
wind & solar 85 1.66 (6.60, 0.38) 8.95 (48.04, 0.60) 43.20 (208.97, 2.68) 1.67 (7.90, 0.38) 8.15 (41.72, 0.53) 19.70 (61.24, 1.65) 28.02 (169.66, 4.87)
nuclear 85 10.84 (18.55, 8.52) 15.49 (41.73, 6.80) 22.64 (115.80, 3.09) 10.91 (18.34, 8.62) 14.34 (31.63, 5.14) 8.87 (39.61, 1.02) 1.21 (7.22, -0.64)
fossil 85 61.35 (76.76, 39.48) 38.41 (87.54, 2.25) 14.10 (118.12, 0.00) 61.55 (71.03, 47.26) 33.96 (59.48, 1.95) 8.05 (33.19, 0.00) -0.76 (0.54, -1.00)
coal 85 32.37 (46.20, 14.40) 10.41 (43.12, 0.00) 1.29 (46.72, 0.00) 32.39 (40.88, 17.23) 8.95 (29.93, 0.00) 0.59 (12.87, 0.00) -0.96 (0.01, -1.00)
gas 85 24.70 (41.20, 13.44) 25.00 (51.99, 2.01) 11.92 (67.94, 0.00) 24.71 (39.20, 11.80) 21.03 (43.43, 1.75) 6.78 (32.59, 0.00) -0.52 (1.63, -1.00)
oil 85 1.82 (13.36, 1.12) 0.92 (7.56, 0.24) 0.08 (8.78, 0.00) 2.04 (11.73, 1.01) 0.71 (6.20, 0.21) 0.04 (3.80, 0.00) -0.97 (0.98, -1.00)
no & lo os 1.5 total generation 50 98.45 (113.98, 83.53) 115.82 (152.40, 81.28) 215.58 (354.48, 126.96) 1.15 (2.55, 0.28)
renewables 50 26.28 (41.80, 18.50) 63.30 (111.70, 32.41) 145.50 (324.26, 90.66) 26.32 (41.84, 18.99) 53.68 (79.67, 37.30) 77.12 (96.65, 58.89) 4.48 (10.88, 2.65)
biomass 50 2.02 (7.00, 0.76) 4.29 (11.96, 0.79) 20.35 (39.28, 0.24) 1.97 (6.87, 0.82) 3.69 (13.29, 0.73) 8.77 (30.28, 0.10) 6.42 (38.14, -0.93)
non-biomass 50 24.21 (35.72, 17.70) 57.12 (101.90, 25.79) 135.04 (323.91, 53.79) 24.38 (40.43, 17.75) 49.88 (78.27, 29.30) 64.68 (96.46, 41.78) 4.64 (10.64, 1.45)
wind & solar 50 1.66 (6.60, 0.38) 8.91 (48.04, 0.60) 39.04 (208.97, 2.68) 1.62 (7.90, 0.38) 8.36 (41.72, 0.53) 19.10 (60.11, 1.65) 26.31 (169.66, 5.23)
nuclear 50 10.84 (18.55, 8.52) 15.46 (36.80, 6.80) 21.97 (64.72, 3.09) 12.09 (18.34, 8.62) 14.33 (31.63, 5.24) 8.10 (27.53, 1.02) 0.71 (4.97, -0.64)
fossil 50 59.43 (68.75, 39.48) 36.51 (66.07, 2.25) 14.81 (57.76, 0.00) 61.32 (67.40, 47.26) 30.04 (52.86, 1.95) 8.61 (25.18, 0.00) -0.74 (0.01, -1.00)
coal 50 31.02 (42.00, 14.40) 8.83 (34.11, 0.00) 1.38 (17.39, 0.00) 32.32 (40.38, 17.23) 7.28 (27.29, 0.00) 0.82 (7.53, 0.00) -0.96 (-0.56, -1.00)
gas 50 24.70 (32.46, 13.44) 22.59 (42.08, 2.01) 12.79 (53.17, 0.00) 24.39 (35.08, 11.80) 20.18 (37.23, 1.75) 6.93 (24.87, 0.00) -0.47 (1.27, -1.00)
oil 50 2.48 (13.36, 1.12) 1.89 (7.56, 0.24) 0.10 (8.78, 0.00) 2.82 (11.73, 1.01) 1.95 (5.67, 0.21) 0.05 (3.80, 0.00) -0.92 (0.36, -1.00)
hi os 1.5 total generation 35 101.44 (113.96, 88.55) 125.26 (177.51, 89.60) 251.50 (363.10, 140.65) 1.38 (2.19, 0.39)
renewables 35 26.38 (31.83, 18.26) 53.32 (86.85, 30.06) 173.29 (273.92, 84.69) 28.37 (32.96, 17.38) 42.73 (65.73, 25.11) 82.39 (94.66, 35.58) 5.97 (8.68, 2.37)
biomass 35 1.23 (6.47, 0.66) 2.14 (7.23, 0.86) 10.49 (40.32, 0.21) 1.22 (7.30, 0.63) 1.59 (6.73, 0.72) 3.75 (28.09, 0.08) 7.93 (33.32, -0.81)
non-biomass 35 24.56 (30.70, 17.60) 47.96 (85.83, 27.39) 144.13 (271.17, 55.72) 26.77 (31.79, 16.75) 40.07 (64.96, 23.10) 69.72 (94.58, 27.51) 5.78 (8.70, 1.38)
wind & solar 35 2.24 (5.07, 0.42) 8.95 (36.52, 1.18) 65.08 (183.38, 13.79) 2.21 (5.25, 0.41) 7.48 (27.90, 0.99) 25.88 (61.24, 8.71) 30.70 (106.95, 4.87)
nuclear 35 10.84 (14.08, 8.52) 16.12 (41.73, 6.80) 22.91 (115.80, 3.09) 10.91 (13.67, 8.62) 14.65 (23.51, 5.14) 11.19 (39.61, 1.12) 1.49 (7.22, -0.64)
fossil 35 62.49 (76.76, 49.09) 48.08 (87.54, 30.99) 11.84 (118.12, 0.78) 61.58 (71.03, 54.01) 42.02 (59.48, 24.27) 6.33 (33.19, 0.27) -0.80 (0.54, -0.99)
coal 35 32.37 (46.20, 26.00) 16.22 (43.12, 1.32) 1.18 (46.72, 0.01) 32.39 (40.88, 24.41) 14.23 (29.93, 1.19) 0.55 (12.87, 0.00) -0.96 (0.01, -1.00)
gas 35 26.20 (41.20, 20.11) 26.45 (51.99, 16.45) 10.66 (67.94, 0.76) 26.97 (39.20, 19.58) 22.29 (43.43, 14.03) 5.29 (32.59, 0.26) -0.57 (1.63, -0.97)
oil 35 1.51 (6.28, 1.12) 0.61 (7.54, 0.36) 0.04 (7.47, 0.00) 1.51 (6.27, 1.01) 0.55 (6.20, 0.26) 0.02 (3.31, 0.00) -0.99 (0.98, -1.00)
In [34]:
summary.to_excel('output/table_2.7_electricity_generation.xlsx')
In [ ]: