ARCO ERA5

This notebook demonstrates how to load ARCO ERA5 data from Google Cloud Storage through the pycontrails ERA5ARCO interface.

[1]:
import dask.config
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import xarray as xr

from pycontrails import Flight, MetDataset
from pycontrails.datalib.ecmwf import ERA5ARCO
from pycontrails.models.cocip import Cocip
from pycontrails.models.humidity_scaling import ConstantHumidityScaling
from pycontrails.models.issr import ISSR
from pycontrails.models.ps_model import PSFlight
from pycontrails.physics import units

Load 13 hours of pressure level and single level data from the ARCO ERA5 dataset. Select all the variables needed for the Cocip model.

Remove the cachestore=None keyword parameter to cache a copy of the data locally. This will make re-running the notebook much faster.

[2]:
time = ("2019-01-01T00", "2019-01-01T12")

era5_pl = ERA5ARCO(
    time=time,
    variables=(*Cocip.met_variables, *Cocip.optional_met_variables),
    cachestore=None,
)
met = era5_pl.open_metdataset()


era5_sl = ERA5ARCO(
    time=time,
    variables=Cocip.rad_variables,
    pressure_levels=-1,
    cachestore=None,
)
rad = era5_sl.open_metdataset()
[3]:
# Materialize the data into memory.
# We run the computation in single-threaded mode to use a bit less memory
# at the expense of a slower computation time.
# Under the hood, this computes the model level to pressure level conversion
# on one zarr chunk at a time rather than computing several across threads

with dask.config.set(scheduler="single-threaded"):
    met.data.load()
    rad.data.load()

ISSRs

Visualize ISSRs over common cruise altitudes over the continental US.

[9]:
issr = ISSR(met=met, humidity_scaling=ConstantHumidityScaling(rhi_adj=0.95))
source = MetDataset(
    xr.Dataset(
        coords={
            "time": ["2019-01-01T00"],
            "longitude": np.arange(-125, -60, 0.25),
            "latitude": np.arange(25, 50, 0.25),
            "level": units.ft_to_pl(np.arange(27000, 45000, 1000)),
        }
    )
)
da = issr.eval(source).data["issr"]

# Use altitude_ft as the vertical coordinate for plotting
da["altitude_ft"] = units.pl_to_ft(da["level"]).round().astype(int)
da = da.swap_dims(level="altitude_ft")
da = da.sel(altitude_ft=da["altitude_ft"].values[::-1])
da = da.squeeze()

da.plot(x="longitude", y="latitude", col="altitude_ft", col_wrap=4, add_colorbar=False);
../_images/notebooks_ARCO-ERA5_6_0.png

CoCiP

Run CoCiP on a collection of synthetic flights at different cruise altitudes over the continental US.

The flights constructed below are in no way realistic. They are simply used to showcase running CoCiP with model level met data.

[10]:
jfk = 40.64, -73.78
lax = 33.94, -118.40

fl_list = [
    Flight(
        longitude=[lax[1], jfk[1]],
        latitude=[lax[0], jfk[0]],
        altitude_ft=[altitude_ft, altitude_ft],
        time=[np.datetime64("2019-01-01T00"), np.datetime64("2019-01-01T04:30")],
        aircraft_type="B738",
        flight_id=f"cruise {altitude_ft} ft",
        origin="LAX",
        destination="JFK",
    ).resample_and_fill()
    for altitude_ft in range(27000, 45000, 1000)
]
[11]:
cocip = Cocip(
    met=met,
    rad=rad,
    dt_integration="1min",
    max_age="8h",
    aircraft_performance=PSFlight(),
    humidity_scaling=ConstantHumidityScaling(rhi_adj=0.95),
)
fl_list = cocip.eval(fl_list)

Visualize CoCiP results

Visualize the results of CoCiP on the synthetic flights.

[12]:
summary = {fl.attrs["flight_id"]: fl["ef"].sum() / 1e12 for fl in fl_list}
pd.Series(summary).to_frame("Energy Forcing [TJ]").astype(int)
[12]:
Energy Forcing [TJ]
cruise 27000 ft 0
cruise 28000 ft 0
cruise 29000 ft 44
cruise 30000 ft 18
cruise 31000 ft 0
cruise 32000 ft 0
cruise 33000 ft 0
cruise 34000 ft 0
cruise 35000 ft 51
cruise 36000 ft 92
cruise 37000 ft 216
cruise 38000 ft 193
cruise 39000 ft 156
cruise 40000 ft 186
cruise 41000 ft 42
cruise 42000 ft 8
cruise 43000 ft 0
cruise 44000 ft 0
[13]:
fig, ax = plt.subplots(figsize=(10, 6))

for fl in fl_list:
    x = fl["time"]
    y = fl["ef"]
    ax.plot(x, y, label=fl.attrs["flight_id"])
    ax.fill_between(x, y, alpha=0.1)

ax.set_ylabel("Energy forcing [J]")
ax.set_xlabel("Waypoint time")

for tick in ax.get_xticklabels():
    tick.set_rotation(45)

ax.set_yscale("symlog", linthresh=1e10)
ax.set_ylim(-1e9, 3e13)

ax.legend();
../_images/notebooks_ARCO-ERA5_12_0.png