Air traffic demand estimation from AR6 scenarios

Air traffic demand estimation from AR6 scenarios#

from jax import vmap
from matplotlib.pyplot import figure
from matplotlib.pyplot import show
from matplotlib.pyplot import subplots
from numpy import array as np_array
from numpy import linspace
from numpy import ones

from noads.application.background_scenario_data import get_ar6_input_data
from noads.application.background_scenario_data import get_scenario_color
from noads.application.background_scenario_data import lines_gen
from noads.core.models.interpolation import interpolate_data
from noads.core.models.traffic import AirTraffic

AR6 scenario data#

Let’s start by getting the AR6 scenario data and taking a look at it.

from noads.demand_calibration.calibration_utils import get_rpk_data

edge_time = linspace(2025.0, 2100.0, 13)
edge_ssp1 = np_array([
    8.525547445255475,
    11.094890510948904,
    14.131386861313867,
    17.05109489051095,
    19.38686131386861,
    20.905109489051092,
    21.956204379562042,
    22.773722627737225,
    22.656934306569344,
    21.956204379562042,
    20.905109489051092,
    19.73722627737226,
    18.56934306569343,
])
edge_ssp2 = np_array([
    9.10948905109489,
    11.562043795620438,
    13.664233576642335,
    16.11678832116788,
    18.56934306569343,
    21.37226277372263,
    23.824817518248175,
    26.394160583941606,
    28.846715328467152,
    31.065693430656932,
    32.81751824817518,
    34.33576642335766,
    35.270072992700726,
])
edge_ssp5 = np_array([
    10.978102189781021,
    16.233576642335766,
    23.240875912408757,
    31.64963503649635,
    39.591240875912405,
    48.46715328467153,
    57.57664233576642,
    64.7007299270073,
    71.47445255474452,
    76.4963503649635,
    79.64963503649635,
    81.16788321167883,
    80.35036496350365,
])

scenario_data, years_data = get_ar6_input_data(
    start_year=2000, end_year=2080, plot_data=True
)
Population, GDP (PPP) per capita, Electricity Emission Factor, Electricity Production, Biomass Production

Not all data is required for air traffic estimation, only Population and GDP per capita. Now we interpolate, for each scenario, to get values yearly.

Also, we consider COVID effects by delaying trend traffic of a fixed amount of years, here we must also include the assumption of end of COVID related traffic constraints.

Model vectorization#

When a model must be evaluated yearly, rather than once, we must vectorize its function to account for vectorized inputs. When running a TemporalScenario this is done automatically, but here we must to it manually.

model = AirTraffic()
model.discipline.jax_out_func = vmap(model.discipline.jax_out_func)

Results#

Now let’s visualize the results for each scenario Also we will make the paper plot with historical and COVID effects

outputs = {}
fig, axes = subplots(2, 2, layout="constrained")
vones = ones(years.shape)

years_hist, gdp_pc_hist, rpk_pc_hist, pop_hist = get_rpk_data(1970)
rpk_hist = rpk_pc_hist * pop_hist

fig_paper = figure(layout="constrained")

gs = fig_paper.add_gridspec(2, 3)
ax1 = fig_paper.add_subplot(gs[0, 0])
ax2 = fig_paper.add_subplot(gs[1, 0])
ax3 = fig_paper.add_subplot(gs[:, 1])
ax4 = fig_paper.add_subplot(gs[:, 2])

lines = lines_gen()
last_ssp_index = 0
for scenario in population:
    name_split = scenario.split("SSP")
    ssp_idx = int(name_split[1][0])
    if ssp_idx != last_ssp_index:
        lines = lines_gen()
    line = next(lines)
    last_ssp_index = ssp_idx

    capacity_factor = 1.0
    if ssp_idx == 1:
        capacity_factor = 0.9
    elif ssp_idx == 5:
        capacity_factor = 1.5

    model_input = {
        "year": years,
        "gdp_per_capita": gdp_per_capita[scenario],
        "population": population[scenario],
        "gdp_per_capita_covid_end": gdp_per_capita_end_covid[scenario] * vones,
        "gdp_per_capita_2019": gdp_per_capita_2019[scenario] * vones,
        "load_factor_end_year": 95.0 * vones,
        "end_year": 2100.0 * vones,
        "capacity_factor": capacity_factor * vones,
    }
    model_output = model.discipline.execute(model_input)
    outputs[scenario] = model_output

    axes[0, 0].plot(
        years,
        model_output["rpk_per_capita"],
        label=f"SSP{ssp_idx}",
        linestyle=line,
        color=get_scenario_color(scenario),
    )
    axes[0, 1].plot(
        years,
        1.0e-12 * model_output["rpk_trend"],
        linestyle=line,
        color=get_scenario_color(scenario),
    )
    axes[1, 0].plot(
        years,
        model_output["load_factor"],
        linestyle=line,
        color=get_scenario_color(scenario),
    )
    axes[1, 1].plot(
        years,
        1.0e-12 * model_output["ask_trend"],
        linestyle=line,
        color=get_scenario_color(scenario),
    )

    ax1.plot(
        years,
        population[scenario] * 1e-9,
        label=f"SSP{ssp_idx}",
        color=get_scenario_color(scenario),
        linestyle=line,
        linewidth=2,
    )
    ax2.plot(
        years,
        gdp_per_capita[scenario] * 1.0e-3,
        label=f"SSP{ssp_idx}",
        color=get_scenario_color(scenario),
        linestyle=line,
        linewidth=2,
    )
    ax3.plot(
        years,
        model_output["rpk_per_capita"],
        label=f"SSP{ssp_idx} (modeled)",
        color=get_scenario_color(scenario),
        linestyle=line,
        linewidth=2,
    )
    ax4.plot(
        years,
        model_output["rpk_trend"] * 1e-12,
        # label=f"SSP{ssp_idx}",
        color=get_scenario_color(scenario),
        linestyle=line,
        linewidth=2,
    )

axes[0, 0].set_xlabel("Year")
axes[0, 0].set_ylabel("pax-km per hab.")
axes[0, 0].set_title("RPK per capita")
axes[0, 1].set_xlabel("Year")
axes[0, 1].set_ylabel("trillion pax-km")
axes[0, 1].set_title("RPK")
axes[1, 0].set_xlabel("Year")
axes[1, 0].set_ylabel("pax/seat [%]")
axes[1, 0].set_title("Load factor")
axes[1, 1].set_xlabel("Year")
axes[1, 1].set_ylabel("trillion seat-km")
axes[1, 1].set_title("ASK")

fig_paper.set_size_inches(12, 6)
ax1.set_title("Population")
ax1.set_ylabel("billion hab.")
ax1.set_xlabel("Year")
ax1.set_xlim((2000, 2100))
ax1.set_ylim((5, 13))
ax2.set_title("GDP per capita")
ax2.set_ylabel("thousand US$2010 per hab.")
ax2.set_xlabel("Year")
ax2.set_xlim((2000, 2100))
ax2.set_ylim((5, 150))

ax3.plot(
    edge_time,
    1.0e12 * edge_ssp1 / interpolate_data(edge_time, years, population["SSP1-19"]),
    ":.",
    label="SSP1 (Franz 2022)",
    color=get_scenario_color("SSP1"),
    linewidth=1,
)
ax3.plot(
    edge_time,
    1.0e12 * edge_ssp2 / interpolate_data(edge_time, years, population["SSP2-26"]),
    ":.",
    label="SSP2 (Franz 2022)",
    color=get_scenario_color("SSP2"),
    linewidth=1,
)
ax3.plot(
    edge_time,
    1.0e12 * edge_ssp5 / interpolate_data(edge_time, years, population["SSP5-45"]),
    ":.",
    label="SSP5 (Franz 2022)",
    color=get_scenario_color("SSP5"),
    linewidth=1,
)
ax4.plot(
    edge_time,
    edge_ssp1,
    ":.",
    label="SSP1 (Franz 2022)",
    color=get_scenario_color("SSP1"),
    linewidth=1,
)
ax4.plot(
    edge_time,
    edge_ssp2,
    ":.",
    label="SSP2 (Franz 2022)",
    color=get_scenario_color("SSP2"),
    linewidth=1,
)
ax4.plot(
    edge_time,
    edge_ssp5,
    ":.",
    label="SSP5 (Franz 2022)",
    color=get_scenario_color("SSP5"),
    linewidth=1,
)

# ax4.legend(loc="upper left", framealpha=0.7)
ax4.set_title("RPK")
ax4.set_ylabel("trillion pax km")
ax4.set_xlabel("Year")
ax4.set_xlim((2000, 2100))
ax4.set_ylim((2, 85))

# Add hypothesis on COVID recovery
ax4.plot(
    [years_hist[-1], 2024],
    [rpk_hist[-1] * 1e6 * 1e-12, rpk_hist[-3] * 1e6 * 1e-12],
    "b--",
)
ax4.plot(
    2024,
    rpk_hist[-3] * 1e6 * 1e-12,
    "bs",
    # label="COVID recovery",
)

# Plot history
ax1.plot(
    years_hist,
    pop_hist * 1e-9,
    ".k",
    linestyle="-",
    label="History data",
)
ax2.plot(
    years_hist,
    gdp_pc_hist * 1.0e-3,
    ".k",
    linestyle="-",
    label="History data",
)
ax3.plot(
    years_hist,
    rpk_hist * 1.0e6 / pop_hist,
    "k.",
    linestyle="-",
    label="History data",
)

ax3.set_title("RPK per capita")
ax3.set_ylabel("pax km / hab.")
ax3.set_xlabel("Year")
ax3.set_xlim((2000, 2100))
ax3.set_ylim((0, 11000))

# Add hypothesis on COVID recovery
ax3.plot(
    [years_hist[-1], 2024],
    [rpk_hist[-1] * 1e6 / pop_hist[-1], rpk_hist[-3] * 1e6 / pop_hist[-3]],
    "b--",
)
ax3.plot(
    2024,
    rpk_hist[-3] * 1e6 / pop_hist[-3],
    "bs",
    label="COVID recovery",
)
ax3.legend(loc="upper left", framealpha=0.4)

ax4.plot(
    years_hist,
    rpk_hist * 1e6 * 1e-12,
    "k.",
    linestyle="-",
    # label="History data",
)

fig_paper.savefig("./rpk_ssps.pdf")
show()


# savefig(f"./rpk_summary.pdf")
# close(fig_paper)
  • RPK per capita, RPK, Load factor, ASK
  • Population, GDP per capita, RPK per capita, RPK

Total running time of the script: (0 minutes 2.784 seconds)

Gallery generated by Sphinx-Gallery