logo

Emissions#

Run the tutorial via free cloud platforms: binder kaggle colab

Learning objectives#

In this notebook we use the cams-global-emission-inventories dataset. The dataset contains anthropogenic and natural emissions. We’ll focus on nitrogen oxides (NOx). These come from several sources: agriculture, ships, power generation, road traffic, industry.

Initial setup#

Before we begin we must prepare our environment. This includes installing the Application Programming Interface (API) of the Climate Data Store (CDS), intalling any other packages not already installed, setting up our CDS API credentials and importing the various Python libraries that we will need.

# Ensure that the cdsapi package is installed
!pip install -q cdsapi
# If you are running this notebook in Colab, uncomment the line below and run this cell.
#!pip install cartopy

Add your ADS API credentials#

To set up your ADS API credentials, please login/register on the ADS, then you will see your unique API key here.

You can add this API key to your current session by replacing ######### in the code cell below with your API key.

import os
os.environ['CDSAPI_URL'] = 'https://ads.atmosphere.copernicus.eu/api'
os.environ['CDSAPI_KEY'] = '###########################################'

Import libraries#

import numpy as np
import xarray as xr
import pandas as pd
import matplotlib.pyplot as plt
import cartopy
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.colors as mcol
from matplotlib.colors import ListedColormap
import calendar
from zipfile import ZipFile
import warnings
warnings.filterwarnings('ignore')

Here we specify a data directory in which we will download our data and all output files that we will generate:

DATADIR = '.'

Explore and download data#

Visit the download form for the CAMS global emission inventories data. View the parameters in the API script in the following cell and select the corresponding options. For each year there will be a netcdf file inside the zip that will be downloaded. The size of the file for one year is 370 MB. The data is available from year 2000 up to 2020.

At the end of the download form, select “Show API request”. This will reveal a block of code, which should be identical to the code cell below.

Please remember to accept the terms and conditions at the bottom of the download form.

variable = 'nitrogen_oxides'
source = 'anthropogenic'
start_year = '2000'
#years = (np.array('2000', dtype=int) + np.arange(2)).tolist()
years = ['2000', '2020']
import cdsapi
c = cdsapi.Client()
c.retrieve(
    'cams-global-emission-inventories',
    {
        'variable': variable,
        'source': [
            source,
        ],
        'version': 'latest',
        'year': years,
        'format': 'zip',
    },
    f'{DATADIR}/download.zip')
2024-09-17 13:30:02,488 INFO Request ID is 69a335e3-df11-4417-b85e-2815e5ae4c06
2024-09-17 13:30:02,578 INFO status has been updated to accepted
2024-09-17 13:30:04,153 INFO status has been updated to running
2024-09-17 13:30:06,483 INFO status has been updated to successful
'./download.zip'
with ZipFile(f'{DATADIR}/download.zip', 'r') as zipObj:
   # Extract all the contents of zip file in current directory
   zipObj.extractall(path=f'{DATADIR}')
os.remove(f'{DATADIR}/download.zip')

Emissions of NOx from all sectors#

The dataset of each year contains the emissions from 13 sectors for 12 months

def dataset_path(year_index):
    year = years[year_index]
    ds_path = f'{DATADIR}/CAMS-GLOB-ANT_v4.2_nitrogen-oxides_{year}.nc'
    return ds_path
nox2000_ds_path = dataset_path(0)
nox2000_ds_path
'./CAMS-GLOB-ANT_v4.2_nitrogen-oxides_2000.nc'
nox2000_ds = xr.open_dataset(nox2000_ds_path, decode_times=False)
nox2000_ds;
<xarray.Dataset> Size: 4GB
Dimensions:  (time: 12, lat: 1800, lon: 3600)
Coordinates:
  * time     (time) int32 48B 0 1 2 3 4 5 6 7 8 9 10 11
  * lat      (lat) float32 7kB -89.95 -89.85 -89.75 -89.65 ... 89.75 89.85 89.95
  * lon      (lon) float32 14kB -179.9 -179.9 -179.8 ... 179.8 179.9 179.9
Data variables: (12/13)
    agl      (time, lat, lon) float32 311MB ...
    ags      (time, lat, lon) float32 311MB ...
    awb      (time, lat, lon) float32 311MB ...
    ene      (time, lat, lon) float32 311MB ...
    fef      (time, lat, lon) float32 311MB ...
    ind      (time, lat, lon) float32 311MB ...
    ...       ...
    shp      (time, lat, lon) float32 311MB ...
    slv      (time, lat, lon) float32 311MB ...
    sum      (time, lat, lon) float32 311MB ...
    swd      (time, lat, lon) float32 311MB ...
    tnr      (time, lat, lon) float32 311MB ...
    tro      (time, lat, lon) float32 311MB ...
Attributes:
    Conventions:      CF-1.6
    projection:       latlon
    authors:          N.Elguindi and C.Granier
    description:      Monthly emissions from CAMS-GLOB-ANT_v4.2 nox emissions...
    product_version:  v4.2
    title:            CAMS Global anthropogenic emissions
    institution:      Laboratoire d'Aérologie/CNRS 
    source:           EDGARv4.3.2 emissions up to 2010 and CEDS emissions up ...
    references:       Granier, C., S. Darras, H. Denier van der Gon, J. Douba...
    history:          Mon Mar  1 16:08:43 2021: ncap2 -s time=array(0,1,$time...
    publisher_url:    https://eccad.aeris-data.fr
    NCO:              netCDF Operators version 4.9.2 (Homepage = http://nco.s...
nox2020_ds_path = dataset_path(1)
nox2020_ds_path
'./CAMS-GLOB-ANT_v4.2_nitrogen-oxides_2020.nc'
nox2020_ds = xr.open_dataset(nox2020_ds_path, decode_times=False)
nox2020_ds;
<xarray.Dataset> Size: 4GB
Dimensions:  (time: 12, lat: 1800, lon: 3600)
Coordinates:
  * time     (time) int32 48B 0 1 2 3 4 5 6 7 8 9 10 11
  * lat      (lat) float32 7kB -89.95 -89.85 -89.75 -89.65 ... 89.75 89.85 89.95
  * lon      (lon) float32 14kB -179.9 -179.9 -179.8 ... 179.8 179.9 179.9
Data variables: (12/13)
    agl      (time, lat, lon) float32 311MB ...
    ags      (time, lat, lon) float32 311MB ...
    awb      (time, lat, lon) float32 311MB ...
    ene      (time, lat, lon) float32 311MB ...
    fef      (time, lat, lon) float32 311MB ...
    ind      (time, lat, lon) float32 311MB ...
    ...       ...
    shp      (time, lat, lon) float32 311MB ...
    slv      (time, lat, lon) float32 311MB ...
    sum      (time, lat, lon) float32 311MB ...
    swd      (time, lat, lon) float32 311MB ...
    tnr      (time, lat, lon) float32 311MB ...
    tro      (time, lat, lon) float32 311MB ...
Attributes:
    Conventions:      CF-1.6
    projection:       latlon
    authors:          N.Elguindi and C.Granier
    description:      Monthly emissions from CAMS-GLOB-ANT_v4.2 nox emissions...
    product_version:  v4.2
    title:            CAMS Global anthropogenic emissions
    institution:      Laboratoire d'Aérologie/CNRS 
    source:           EDGARv4.3.2 emissions up to 2010 and CEDS emissions up ...
    references:       Granier, C., S. Darras, H. Denier van der Gon, J. Douba...
    history:          Mon Mar  1 15:26:11 2021: ncap2 -s time=array(0,1,$time...
    publisher_url:    https://eccad.aeris-data.fr
    NCO:              netCDF Operators version 4.9.2 (Homepage = http://nco.s...

NOx all sectors#

We sum the emissions from all sectors in one year. We create a new data array to store the sum of the values from each sector in one year.

def create_da(ds):
    '''
    This function returns a data array similar to one of those
    in the input dataset to be used to collect the values for
    all sectors and for each month. A data array has dimensions,
    coordinates, and attributes. The data array values are set 
    to zero.
    '''
    output_da = None
    
    # Set the dimensions
    months = ds.time
    lats = ds.lat
    lons = ds.lon 
    zeros2d = np.float32(np.zeros((len(months), len(lats), len(lons))))
    
    # Set the coordinates
    coords = [months, lats, lons]
    
    # Creates the new data array
    output_da = xr.DataArray(zeros2d, coords=coords, dims=['time', 'lat', 'lon'])
    
    # Set the attributes. Some attributes are common to all the data arrays in the input dataset
    output_da.attrs['long_name'] = 'Sum of the values of all variables'
    output_da.attrs['units'] = ds['agl'].attrs['units']
    output_da.attrs['sector_name'] = 'all sectors'
    output_da.attrs['molecular_weight_units'] = ds['agl'].attrs['molecular_weight_units']
    output_da.attrs['standard_name'] = 'no standard name'
    output_da.attrs['molecular_weight'] = ds['agl'].attrs['molecular_weight']
    
    return output_da

We loop through all the sectors and months to sum up the values from each sector for each month

def sum_all_sectors(ds):
    '''
    This function computes the sum of the emissions
    from all the sectors and month in the input dataset 
    and returns a data array with the computed values
    '''
    target_da = create_da(ds) # creates a data array with values initialized to 0.0
    for variable in ds.data_vars:
        source_da = ds[variable]
        months = source_da.time
        for m in range(len(months)):
            target_da.sel(time = m).values += source_da.sel(time = m).values
    return target_da

NOx from all sectors in 2000#

nox2000_all_sectors_da = sum_all_sectors(nox2000_ds)
nox2000_all_sectors_da
<xarray.DataArray (time: 12, lat: 1800, lon: 3600)> Size: 311MB
array([[[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
...
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]]], dtype=float32)
Coordinates:
  * time     (time) int32 48B 0 1 2 3 4 5 6 7 8 9 10 11
  * lat      (lat) float32 7kB -89.95 -89.85 -89.75 -89.65 ... 89.75 89.85 89.95
  * lon      (lon) float32 14kB -179.9 -179.9 -179.8 ... 179.8 179.9 179.9
Attributes:
    long_name:               Sum of the values of all variables
    units:                   kg m-2 s-1
    sector_name:             all sectors
    molecular_weight_units:  g mole-1
    standard_name:           no standard name
    molecular_weight:        30.0

NOx from all sectors in 2020#

nox2020_all_sectors_da = sum_all_sectors(nox2020_ds)
nox2020_all_sectors_da
<xarray.DataArray (time: 12, lat: 1800, lon: 3600)> Size: 311MB
array([[[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
...
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]]], dtype=float32)
Coordinates:
  * time     (time) int32 48B 0 1 2 3 4 5 6 7 8 9 10 11
  * lat      (lat) float32 7kB -89.95 -89.85 -89.75 -89.65 ... 89.75 89.85 89.95
  * lon      (lon) float32 14kB -179.9 -179.9 -179.8 ... 179.8 179.9 179.9
Attributes:
    long_name:               Sum of the values of all variables
    units:                   kg m-2 s-1
    sector_name:             all sectors
    molecular_weight_units:  g mole-1
    standard_name:           no standard name
    molecular_weight:        30.0

Visualizations#

We plot the data for the sum of emission from all sectors for each month. We define a discrete color map to visualize the values in the map.

dark_red = '#971039'
red = '#D93322'
orange = '#F09235'
dark_yellow = '#F5BE41'
yellow = '#ECD347'
light_yellow = '#FFFF00'
green = '#5AAA5F'
light_green = '#A7D25C'
cyan = '#7EFEE7'
light_blue = '#92D2F9'
blue = '#0B2CA1'
white = '#FFFFFF'
colors = [white, blue, light_blue, cyan, light_green, green, light_yellow, yellow, dark_yellow, orange, red, dark_red]
levels = [4e-18, 4e-17, 4e-16, 4e-15, 4e-14, 4e-13, 4e-12, 4e-11, 4e-10, 4e-9, 4e-8, 4e-7]
#level_ticks = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
emissions_cmap = ListedColormap(colors)
calendar.month_name[1]
'January'
def plot_emissions(da, year, month):
    maplon = [-180,180]
    maplat = [-90,90]
    lonmin = maplon[0]
    lonmax = maplon[1]
    latmin = maplat[0]
    latmax = maplat[1]
    plt.figure(figsize=(20,10))
    ax = plt.axes(projection=ccrs.PlateCarree())
    ax.gridlines(draw_labels=True, linestyle='--')
    ax.add_feature(cartopy.feature.LAND, edgecolor='black')
    ax.coastlines()
    ax.set_extent([lonmin,lonmax,latmin,latmax], crs=ccrs.PlateCarree()) 
    da_plt = da.sel(time = month).plot(ax=ax, add_colorbar=False, cmap=emissions_cmap, levels=levels, vmin=0.0, robust=True) # 'YlOrRd'
    cbar = plt.colorbar(da_plt, fraction=0.025, pad=0.05) 
    cbar.set_label('micrograms')
    cbar.set_ticks(levels)
    cbar.set_ticklabels(levels)
    plt.title('Emissions of NOx from all sectors - {:s} {:s} '.format(calendar.month_name[month + 1], year))
plot_emissions(nox2000_all_sectors_da, '2000', 0)
_images/5ae0ddbe56caebdbbbf1dad89ad823e2b131fecc1abcaf2380beda950683d3f6.png
plot_emissions(nox2020_all_sectors_da, '2020', 0)
_images/3cb65ba34d517b80c63ac425885c1d76465916501f9392328e2e878862a87b04.png

Total flux January-December#

tot_nox_2020 = nox2020_all_sectors_da.sel(time=slice(0,11)).sum(dim='time')
tot_nox_2020.max()
<xarray.DataArray ()> Size: 4B
array(3.1515065e-06, dtype=float32)
def plot_total_emissions(da, year):
    maplon = [-180,180]
    maplat = [-90,90]
    lonmin = maplon[0]
    lonmax = maplon[1]
    latmin = maplat[0]
    latmax = maplat[1]
    plt.figure(figsize=(20,10))
    ax = plt.axes(projection=ccrs.PlateCarree())
    ax.gridlines(draw_labels=True, linestyle='--')
    ax.add_feature(cartopy.feature.OCEAN)
    ax.add_feature(cartopy.feature.LAND, edgecolor='black')
    ax.coastlines()
    ax.set_extent([lonmin,lonmax,latmin,latmax], crs=ccrs.PlateCarree()) 
    da_plt = da.plot(ax=ax, add_colorbar=False, cmap=emissions_cmap, levels=levels, vmin=0.0, robust=True) # 'YlOrRd'
    cbar = plt.colorbar(da_plt, fraction=0.025, pad=0.05) 
    cbar.set_label('micrograms')
    cbar.set_ticks(levels)
    cbar.set_ticklabels(levels)
    plt.title('Emissions of NOx from all sectors - {:s} Jan-Dec.'.format(year))
plot_total_emissions(tot_nox_2020, '2020')
_images/48f17800a5bb5156b694f9441d83f53d5ff27ee7a7fbed0f4806b2dc7efb0a55.png

Total flux for 2000 and 2020#

We calculate the total emissions from all sector for each year

tot_nox_2000 = nox2000_all_sectors_da.sel(time=slice(0,11)).sum()
tot_nox_2000
<xarray.DataArray ()> Size: 4B
array(0.00049035, dtype=float32)
tot_nox_2020 = nox2020_all_sectors_da.sel(time=slice(0,11)).sum()
tot_nox_2020
<xarray.DataArray ()> Size: 4B
array(0.00053885, dtype=float32)
fig, ax = plt.subplots()

tot_emissions = [tot_nox_2000, tot_nox_2020]
bar_labels = ['2000', '2020']
bar_colors = ['tab:red', 'tab:blue']

ax.bar(years, tot_emissions, label=bar_labels, color=bar_colors)

ax.set_ylabel('kg m-2 s-1')
ax.set_title('Total NOx emissions')
#ax.legend(title='Year')

plt.show()
_images/820d8e7b1455932814b032194cb5cff05fa201d4d2f4ab5c3a992d60a8ebcb7b.png