ACCF¶
Interface to the ACCF (algorithmic climate change functions) from the DLR library climaccf.
References¶
Dietmüller, Simone. “Dlr-Pa/Climaccf: Dataset Update for GMDD.” Zenodo, September 13, 2022. https://doi.org/10.5281/zenodo.7074582.
Dietmüller, Simone, Sigrun Matthes, Katrin Dahlmann, Hiroshi Yamashita, Abolfazl Simorgh, Manuel Soler, Florian Linke, et al. “A Python Library for Computing Individual and Merged Non-CO2 Algorithmic Climate Change Functions: CLIMaCCF V1.0.” Preprint. Atmospheric sciences, October 17, 2022. https://doi.org/10.5194/gmd-2022-203.
[1]:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pycontrails import Flight
from pycontrails.datalib.ecmwf import ERA5
from pycontrails.models.accf import ACCF
from pycontrails.physics import units
Set Domain¶
time / altitude
[2]:
time_bounds = ("2022-01-01 12:00:00", "2022-01-01 15:00:00")
pressure_levels = [200, 225, 250]
Download meteorology data from ECMWF¶
This demo uses ERA5 via the Copernicus Data Store (CDS) for met data. This requires account with Copernicus Data Portal and local ~/.cdsapirc
file with credentials.
[3]:
# pressure level data
era5_pl = ERA5(
time=time_bounds,
variables=[
"air_temperature",
"specific_humidity",
"potential_vorticity",
"geopotential",
"relative_humidity",
"northward_wind",
"eastward_wind",
],
pressure_levels=pressure_levels,
)
# single level data (radiation)
era5_sl = ERA5(
time=time_bounds,
variables=["surface_solar_downward_radiation", "top_net_thermal_radiation"],
)
pl = era5_pl.open_metdataset()
sl = era5_sl.open_metdataset()
Create example flight¶
[4]:
# Note: ACCF output is in K/kg of fuel so you will need to provide fuel burn of the flight to get impact in K
n = 10000
longitude = np.linspace(45, 58, n) + np.linspace(0, 1, n)
latitude = np.linspace(45, 54, n) - np.linspace(0, 1, n)
altitude = units.pl_to_m(225) * np.ones(n)
start = np.datetime64(time_bounds[0])
end = start + np.timedelta64(90, "m") # 90 minute flight
time = pd.date_range(start, end, periods=n)
fl = Flight(
longitude=longitude,
latitude=latitude,
altitude=altitude,
time=time,
aircraft_type="B737",
flight_id=17,
)
fl["fuel_flow"] = np.linspace(2.1, 2.4, n) # kg/s
[5]:
fl
[5]:
Attributes | |
---|---|
time | [2022-01-01 12:00:00, 2022-01-01 13:30:00] |
longitude | [45.0, 59.0] |
latitude | [45.0, 53.0] |
altitude | [11037.0, 11037.0] |
aircraft_type | B737 |
flight_id | 17 |
longitude | latitude | time | altitude | fuel_flow | |
---|---|---|---|---|---|
0 | 45.000000 | 45.0000 | 2022-01-01 12:00:00.000000000 | 11037.01126 | 2.10000 |
1 | 45.001400 | 45.0008 | 2022-01-01 12:00:00.540054005 | 11037.01126 | 2.10003 |
2 | 45.002800 | 45.0016 | 2022-01-01 12:00:01.080108010 | 11037.01126 | 2.10006 |
3 | 45.004200 | 45.0024 | 2022-01-01 12:00:01.620162016 | 11037.01126 | 2.10009 |
4 | 45.005601 | 45.0032 | 2022-01-01 12:00:02.160216021 | 11037.01126 | 2.10012 |
... | ... | ... | ... | ... | ... |
9995 | 58.994399 | 52.9968 | 2022-01-01 13:29:57.839783978 | 11037.01126 | 2.39988 |
9996 | 58.995800 | 52.9976 | 2022-01-01 13:29:58.379837983 | 11037.01126 | 2.39991 |
9997 | 58.997200 | 52.9984 | 2022-01-01 13:29:58.919891989 | 11037.01126 | 2.39994 |
9998 | 58.998600 | 52.9992 | 2022-01-01 13:29:59.459945994 | 11037.01126 | 2.39997 |
9999 | 59.000000 | 53.0000 | 2022-01-01 13:30:00.000000000 | 11037.01126 | 2.40000 |
10000 rows × 5 columns
Initialize ACCF model and evaluate on flight¶
[6]:
ac = ACCF(met=pl, surface=sl, unit_K_per_kg_fuel=True)
[7]:
# Evaluate ACCFs over this flight
fl = ac.eval(fl)
Forecast step has not been selected manually and determined automatically. Forecast step: 1 hour
UserWarning: For this configuration formation of persistent contrails is possible, if temperatures are low enough (below 235K) and relative humidity (with respect to ice) is above or at 90.0%. However keep in mind that the threshold value for the relative humidity varies with the used forecast model and its resolution. In order to choose the appropriate threshold value, you should read the details given in Section 5.1 of the connected publication of Dietmueller et al. 2022
Explore the output¶
Raw output:
[8]:
fl
[8]:
Attributes | |
---|---|
time | [2022-01-01 12:00:00, 2022-01-01 13:30:00] |
longitude | [45.0, 59.0] |
latitude | [45.0, 53.0] |
altitude | [11037.0, 11037.0] |
aircraft_type | B737 |
flight_id | 17 |
met_source_provider | ECMWF |
met_source_dataset | ERA5 |
met_source_product | reanalysis |
pycontrails_version | 0.54.3.dev22 |
longitude | latitude | time | altitude | fuel_flow | flight_id | air_temperature | specific_humidity | potential_vorticity | geopotential | ... | aCCF_CH4 | aCCF_O3 | aCCF_H2O | aCCF_nCont | aCCF_dCont | aCCF_Cont | aCCF_CO2 | aCCF_merged | aCCF_NOx | Fin | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 45.000000 | 45.0000 | 2022-01-01 12:00:00.000000000 | 11037.01126 | 2.10000 | 17.0 | 215.779122 | 0.000007 | 0.000007 | 105447.963578 | ... | -5.791611e-15 | 2.128180e-14 | 7.799343e-16 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 | 7.480000e-16 | 1.701813e-14 | 1.549019e-14 | 509.002230 |
1 | 45.001400 | 45.0008 | 2022-01-01 12:00:00.540054005 | 11037.01126 | 2.10003 | 17.0 | 215.779775 | 0.000007 | 0.000007 | 105447.773186 | ... | -5.791619e-15 | 2.128180e-14 | 7.799481e-16 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 | 7.480000e-16 | 1.701813e-14 | 1.549018e-14 | 508.984589 |
2 | 45.002800 | 45.0016 | 2022-01-01 12:00:01.080108010 | 11037.01126 | 2.10006 | 17.0 | 215.780429 | 0.000007 | 0.000007 | 105447.582752 | ... | -5.791627e-15 | 2.128179e-14 | 7.799622e-16 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 | 7.480000e-16 | 1.701812e-14 | 1.549016e-14 | 508.966947 |
3 | 45.004200 | 45.0024 | 2022-01-01 12:00:01.620162016 | 11037.01126 | 2.10009 | 17.0 | 215.781085 | 0.000007 | 0.000007 | 105447.392279 | ... | -5.791635e-15 | 2.128178e-14 | 7.799766e-16 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 | 7.480000e-16 | 1.701812e-14 | 1.549015e-14 | 508.949306 |
4 | 45.005601 | 45.0032 | 2022-01-01 12:00:02.160216021 | 11037.01126 | 2.10012 | 17.0 | 215.781742 | 0.000007 | 0.000007 | 105447.201764 | ... | -5.791643e-15 | 2.128177e-14 | 7.799912e-16 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 | 7.480000e-16 | 1.701812e-14 | 1.549013e-14 | 508.931664 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
9995 | 58.994399 | 52.9968 | 2022-01-01 13:29:57.839783978 | 11037.01126 | 2.39988 | 17.0 | 209.364664 | 0.000013 | 0.000007 | 104271.609633 | ... | -5.844423e-15 | 1.980883e-14 | 7.788148e-16 | 2.748458e-29 | -3.015281e-29 | 2.748458e-29 | 7.480000e-16 | 1.549122e-14 | 1.396441e-14 | 328.603173 |
9996 | 58.995800 | 52.9976 | 2022-01-01 13:29:58.379837983 | 11037.01126 | 2.39991 | 17.0 | 209.364758 | 0.000013 | 0.000007 | 104271.422620 | ... | -5.844429e-15 | 1.980874e-14 | 7.789030e-16 | 2.748245e-29 | -3.015449e-29 | 2.748245e-29 | 7.480000e-16 | 1.549122e-14 | 1.396432e-14 | 328.584764 |
9997 | 58.997200 | 52.9984 | 2022-01-01 13:29:58.919891989 | 11037.01126 | 2.39994 | 17.0 | 209.364852 | 0.000013 | 0.000007 | 104271.235559 | ... | -5.844435e-15 | 1.980866e-14 | 7.789914e-16 | 2.748031e-29 | -3.015618e-29 | 2.748031e-29 | 7.480000e-16 | 1.549121e-14 | 1.396422e-14 | 328.566356 |
9998 | 58.998600 | 52.9992 | 2022-01-01 13:29:59.459945994 | 11037.01126 | 2.39997 | 17.0 | 209.364947 | 0.000013 | 0.000007 | 104271.048450 | ... | -5.844441e-15 | 1.980857e-14 | 7.790802e-16 | 2.747817e-29 | -3.015790e-29 | 2.747817e-29 | 7.480000e-16 | 1.549121e-14 | 1.396413e-14 | 328.547947 |
9999 | 59.000000 | 53.0000 | 2022-01-01 13:30:00.000000000 | 11037.01126 | 2.40000 | 17.0 | 209.365042 | 0.000013 | 0.000007 | 104270.861293 | ... | -5.844446e-15 | 1.980848e-14 | 7.791693e-16 | 2.747603e-29 | -3.015963e-29 | 2.747603e-29 | 7.480000e-16 | 1.549121e-14 | 1.396404e-14 | 328.529539 |
10000 rows × 27 columns
Now convert fuel flow to total fuel burned by waypoint, and get the impact of each flight waypoint and plot
[9]:
# Waypoint duration in seconds
dt_sec = fl.segment_duration()
# kg fuel per contrail
fuel_burn = fl["fuel_flow"] * dt_sec
# Get impacts in degrees K per waypoint
warming_contrails = fuel_burn * fl["aCCF_Cont"]
warming_merged = fuel_burn * fl["aCCF_merged"]
[10]:
f, (ax0, ax1) = plt.subplots(2, 1, sharex=True, figsize=(12, 8))
ax0.plot(fl["time"], warming_contrails, label="Contrails")
ax0.plot(fl["time"], warming_merged, label="Combined ACCFs")
ax0.set_ylabel("Degrees K")
ax0.set_title("Warming impact by waypoint")
ax0.legend()
ax1.plot(fl["time"], np.cumsum(warming_contrails), label="Contrails")
ax1.plot(fl["time"], np.cumsum(warming_merged), label="Combined ACCFs")
ax1.legend()
ax1.set_xlabel("Waypoint Time")
ax1.set_ylabel("Degrees K")
ax1.set_title("Cumulative warming impact");
Grid ACCF with Parameters¶
[11]:
ac = ACCF(
pl,
sl,
params={"emission_scenario": "future_scenario", "accf_v": "V1.0", "unit_K_per_kg_fuel": True},
)
ds = ac.eval() # This will evaluate over the met grid
Forecast step has not been selected manually and determined automatically. Forecast step: 1 hour
UserWarning: For this configuration formation of persistent contrails is possible, if temperatures are low enough (below 235K) and relative humidity (with respect to ice) is above or at 90.0%. However keep in mind that the threshold value for the relative humidity varies with the used forecast model and its resolution. In order to choose the appropriate threshold value, you should read the details given in Section 5.1 of the connected publication of Dietmueller et al. 2022
[12]:
fig, ax = plt.subplots()
p = ax.pcolor(
ds["longitude"].data,
ds["latitude"].data,
ds["aCCF_merged"].data[:, :, 0, 0].T,
cmap="coolwarm",
vmin=-6e-13,
vmax=6e-13,
)
ax.set_xlabel("Longitude")
ax.set_ylabel("Latitude")
ax.set_title("Merged ACCF")
cbar = plt.colorbar(p)
cbar.set_label("Degrees K/km");