CMIP6 dimension coordinate problems

Most CMIP6 ocean models use a curvilinear grid, which means an ocean variable (e.g. wfo) will be defined as follows:

netcdf wfo_Omon_HadGEM3-GC31-LL_piControl_r1i1p1f1_gn_225001-234912 {
dimensions:
    time = UNLIMITED ; // (1200 currently)
    bnds = 2 ;
    j = 330 ;
    i = 360 ;
    vertices = 4 ;
variables:
    double time(time) ;
        time:bounds = "time_bnds" ;
        time:units = "days since 1850-01-01" ;
        time:calendar = "360_day" ;
        time:axis = "T" ;
        time:long_name = "time" ;
        time:standard_name = "time" ;
    double time_bnds(time, bnds) ;
    int j(j) ;
        j:units = "1" ;
        j:long_name = "cell index along second dimension" ;
    int i(i) ;
        i:units = "1" ;
        i:long_name = "cell index along first dimension" ;
    float latitude(j, i) ;
        latitude:standard_name = "latitude" ;
        latitude:long_name = "latitude" ;
        latitude:units = "degrees_north" ;
        latitude:missing_value = 1.e+20f ;
        latitude:_FillValue = 1.e+20f ;
        latitude:bounds = "vertices_latitude" ;
    float longitude(j, i) ;
        longitude:standard_name = "longitude" ;
        longitude:long_name = "longitude" ;
        longitude:units = "degrees_east" ;
        longitude:missing_value = 1.e+20f ;
        longitude:_FillValue = 1.e+20f ;
        longitude:bounds = "vertices_longitude" ;
    float wfo(time, j, i) ;
    ...

You'll notice that wfo(time, j, i) where j is defined as the cell index along second dimension and i the cell index along first dimension.

You can go ahead and use these dimension names to collapse coordinates (or to do whatever other calculations you are doing along an axis):


In [ ]:
import warnings
warnings.filterwarnings('ignore')

import iris

In [21]:
good_file = '/g/data1b/oi10/replicas/CMIP6/CMIP/MOHC/HadGEM3-GC31-LL/piControl/r1i1p1f1/Omon/wfo/gn/v20190628/wfo_Omon_HadGEM3-GC31-LL_piControl_r1i1p1f1_gn_225001-234912.nc'
good_cube = iris.load_cube(good_file, 'water_flux_into_sea_water')

In [22]:
print(good_cube.summary(shorten=True))


water_flux_into_sea_water / (kg m-2 s-1) (time: 1200; cell index along second dimension: 330; cell index along first dimension: 360)

In [24]:
spatial_mean = good_cube.collapsed(['cell index along second dimension', 'cell index along first dimension'], iris.analysis.MEAN)

In [26]:
print(spatial_mean.summary(shorten=True))


water_flux_into_sea_water / (kg m-2 s-1) (time: 1200)

In CMIP6, however, some groups have not defined the j and i dimensions (I didn't notice this in CMIP5). e.g:

netcdf wfo_Omon_CNRM-CM6-1_piControl_r1i1p1f2_gn_185001-234912 {
dimensions:
    axis_nbounds = 2 ;
    x = 362 ;
    y = 294 ;
    nvertex = 4 ;
    time = UNLIMITED ; // (6000 currently)
variables:
    double lat(y, x) ;
        lat:standard_name = "latitude" ;
        lat:long_name = "Latitude" ;
        lat:units = "degrees_north" ;
        lat:bounds = "bounds_lat" ;
    double lon(y, x) ;
        lon:standard_name = "longitude" ;
        lon:long_name = "Longitude" ;
        lon:units = "degrees_east" ;
        lon:bounds = "bounds_lon" ;
    double bounds_lon(y, x, nvertex) ;
    double bounds_lat(y, x, nvertex) ;
    double time(time) ;
        time:axis = "T" ;
        time:standard_name = "time" ;
        time:long_name = "Time axis" ;
        time:calendar = "gregorian" ;
        time:units = "days since 1850-01-01 00:00:00" ;
        time:time_origin = "1850-01-01 00:00:00" ;
        time:bounds = "time_bounds" ;
    double time_bounds(time, axis_nbounds) ;
    float wfo(time, y, x) ;
...

This means you can't refer to the spatial dimensions by name, which is very annoying.


In [29]:
bad_file = '/g/data1b/oi10/replicas/CMIP6/CMIP/CNRM-CERFACS/CNRM-CM6-1/piControl/r1i1p1f2/Omon/wfo/gn/v20180814/wfo_Omon_CNRM-CM6-1_piControl_r1i1p1f2_gn_185001-234912.nc'
bad_cube = iris.load_cube(bad_file, 'water_flux_into_sea_water')

In [30]:
print(bad_cube.summary(shorten=True))


water_flux_into_sea_water / (kg m-2 s-1) (time: 6000; -- : 294; -- : 362)