%load_ext autoreload
%autoreload 2

Examples of CORDEX-CMIP6 cmorization#

Introduction#

This notebook demonstrates how climate model output can be reformatted and standardized using CMOR (Climate Model Output Rewriter) for the CORDEX-CMIP6 framework.

What is CMORization?

  • CMORization is the process of converting raw model output into standardized netCDF files

  • It ensures compliance with CF (Climate and Forecast) conventions

  • It automatically handles unit conversions, time resampling, and metadata standardization

In this notebook, we’ll show examples of how to cmorize different types of climate data (fixed fields, monthly, and sub-daily data).

!ls ../Tables
CORDEX-CMIP6_1hr.json	      CORDEX-CMIP6_formula_terms.json
CORDEX-CMIP6_3hr.json	      CORDEX-CMIP6_fx.json
CORDEX-CMIP6_6hr.json	      CORDEX-CMIP6_grids.json
CORDEX-CMIP6_CV.json	      CORDEX-CMIP6_mon.json
CORDEX-CMIP6_coordinate.json  CORDEX-CMIP6_remo_example.json
CORDEX-CMIP6_day.json

Controlled Vocabulary (CV)#

The CORDEX-CMIP6_CV.json file defines the controlled vocabulary and required global attributes that the CMOR3 library uses for rewriting and validating the model output. This ensures all CORDEX-CMIP6 datasets follow the same conventions and contain consistent metadata.

Below we show the required global attributes that must be present in every CORDEX-CMIP6 dataset:

import json
import pprint

from IPython.display import JSON

# Opening JSON file
with open("../Tables/CORDEX-CMIP6_CV.json") as json_file:
    CV = json.load(json_file)["CV"]

# JSON(CV['required_global_attributes'])
pprint.pprint(CV["required_global_attributes"])
['activity_id',
 'contact',
 'Conventions',
 'creation_date',
 'domain_id',
 'domain',
 'driving_experiment_id',
 'driving_experiment',
 'driving_institution_id',
 'driving_source_id',
 'driving_variant_label',
 'frequency',
 'grid',
 'institution',
 'institution_id',
 'license',
 'mip_era',
 'product',
 'project_id',
 'source',
 'source_id',
 'source_type',
 'tracking_id',
 'variable_id',
 'version_realization']

CMORization Examples#

We use the cordex.cmor module to create examples of CORDEX-CMIP6 compliant datasets. The following section defines three functions that demonstrate how to cmorize different types of climate data:

  1. Fixed fields (fx): Time-independent data like topography (orog)

  2. Monthly data (mon): Variables averaged over monthly timescales (e.g., temperature)

  3. Sub-daily data: Hourly, 3-hourly, and 6-hourly data that can be automatically resampled

Each function shows how to:

  • Specify the input variable mapping

  • Define the CMOR table for the output format

  • Handle coordinate systems and domain information

  • Convert units as needed

Hide code cell source

import os

import cordex as cx
import xarray as xr
from cordex import cmor as cmor

table_dir = "../Tables"

# Set the CMOR table prefix for CORDEX-CMIP6 standard
cmor.set_options(table_prefix="CORDEX-CMIP6")


def test_cmorizer_fx():
    """
    CMORize a fixed field (time-independent) variable.

    This example demonstrates how to cmorize topography (orog) data,
    which is a fixed field that doesn't change over time. We use a dummy
    topography field generated from the EUR-11 CORDEX domain.

    Returns
    -------
    str
        Path to the cmorized netCDF file
    """
    ds = cx.cordex_domain("EUR-11", dummy="topo")
    filename = cmor.cmorize_variable(
        ds,
        "orog",
        mapping_table={"orog": {"varname": "topo"}},
        cmor_table=os.path.join(table_dir, "CORDEX-CMIP6_fx.json"),
        dataset_table=os.path.join(table_dir, "CORDEX-CMIP6_remo_example.json"),
        grids_table=os.path.join(table_dir, "CORDEX-CMIP6_grids.json"),
        CORDEX_domain="EUR-11",
        time_units=None,
        allow_units_convert=True,
    )
    return filename


def test_cmorizer_mon():
    """
    CMORize a monthly aggregated variable.

    This example demonstrates how to cmorize monthly averaged temperature (tas).
    The input data is loaded from a tutorial dataset containing hourly 2m temperature.

    Returns
    -------
    str
        Path to the cmorized netCDF file
    """
    ds = cx.tutorial.open_dataset("remo_EUR-11_TEMP2_mon")
    filename = cmor.cmorize_variable(
        ds,
        "tas",
        mapping_table={"tas": {"varname": "TEMP2"}},
        cmor_table=os.path.join(table_dir, "CORDEX-CMIP6_mon.json"),
        dataset_table=os.path.join(table_dir, "CORDEX-CMIP6_remo_example.json"),
        grids_table=os.path.join(table_dir, "CORDEX-CMIP6_grids.json"),
        CORDEX_domain="EUR-11",
        time_units=None,
        allow_units_convert=True,
    )
    return filename


def test_cmorizer_subdaily(table):
    """
    CMORize sub-daily (1hr, 3hr, 6hr) variables.

    This example demonstrates how to cmorize sub-daily data. The input data
    is hourly temperature, which can be automatically resampled to other
    frequencies (3-hourly, 6-hourly, daily) based on the target CMOR table.

    Parameters
    ----------
    table : str
        Name of the time frequency table (e.g., '1hr', '3hr', '6hr', 'day')

    Returns
    -------
    str
        Path to the cmorized netCDF file
    """
    ds = cx.tutorial.open_dataset("remo_EUR-11_TEMP2_1hr")
    filename = cmor.cmorize_variable(
        ds,
        "tas",
        mapping_table={"tas": {"varname": "TEMP2"}},
        cmor_table=os.path.join(table_dir, f"CORDEX-CMIP6_{table}.json"),
        dataset_table=os.path.join(table_dir, "CORDEX-CMIP6_remo_example.json"),
        grids_table=os.path.join(table_dir, "CORDEX-CMIP6_grids.json"),
        CORDEX_domain="EUR-11",
        time_units=None,
        allow_units_convert=True,
        allow_resample=True,  # Enable automatic resampling to target frequency
    )
    return filename

Example 1: Fixed Fields (fx) - Topography#

This example demonstrates CMORization of fixed fields, using topography (orog) as an example. Fixed fields are time-independent variables that describe static properties of the domain, such as terrain height or land-sea masks.

We’ll create the file, then inspect it using xarray and various validation tools:

f = test_cmorizer_fx()

Generated Filename#

The filename follows the CORDEX-CMIP6 naming convention, encoding information about the domain, driving model, and version:

f
'CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/fx/orog/v20261020/orog_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_fx.nc'
# Display the netCDF header showing all metadata and attributes
!ncdump -h $f
netcdf orog_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_fx {
dimensions:
	rlat = 412 ;
	rlon = 424 ;
	bnds = 2 ;
	vertices = 4 ;
variables:
	double rlat(rlat) ;
		rlat:units = "degrees" ;
		rlat:axis = "Y" ;
		rlat:long_name = "latitude in rotated pole grid" ;
		rlat:standard_name = "grid_latitude" ;
	double rlon(rlon) ;
		rlon:units = "degrees" ;
		rlon:axis = "X" ;
		rlon:long_name = "longitude in rotated pole grid" ;
		rlon:standard_name = "grid_longitude" ;
	int rotated_latitude_longitude ;
		rotated_latitude_longitude:grid_mapping_name = "rotated_latitude_longitude" ;
		rotated_latitude_longitude:grid_north_pole_latitude = 39.25 ;
		rotated_latitude_longitude:grid_north_pole_longitude = -162. ;
		rotated_latitude_longitude:north_pole_grid_longitude = 0. ;
		rotated_latitude_longitude:earth_radius = 6371229. ;
	double lat(rlat, rlon) ;
		lat:standard_name = "latitude" ;
		lat:long_name = "latitude" ;
		lat:units = "degrees_north" ;
		lat:missing_value = 1.e+20 ;
		lat:_FillValue = 1.e+20 ;
		lat:bounds = "vertices_lat" ;
	double lon(rlat, rlon) ;
		lon:standard_name = "longitude" ;
		lon:long_name = "longitude" ;
		lon:units = "degrees_east" ;
		lon:missing_value = 1.e+20 ;
		lon:_FillValue = 1.e+20 ;
		lon:bounds = "vertices_lon" ;
	double vertices_lat(rlat, rlon, vertices) ;
		vertices_lat:units = "degrees_north" ;
		vertices_lat:missing_value = 1.e+20 ;
		vertices_lat:_FillValue = 1.e+20 ;
	double vertices_lon(rlat, rlon, vertices) ;
		vertices_lon:units = "degrees_east" ;
		vertices_lon:missing_value = 1.e+20 ;
		vertices_lon:_FillValue = 1.e+20 ;
	float orog(rlat, rlon) ;
		orog:standard_name = "surface_altitude" ;
		orog:long_name = "Surface Altitude" ;
		orog:comment = "The surface called \'surface\' means the lower boundary of the atmosphere. Altitude is the (geometric) height above the geoid, which is the reference geopotential surface. The geoid is similar to mean sea level." ;
		orog:units = "m" ;
		orog:cell_methods = "area: mean" ;
		orog:cell_measures = "area: areacella" ;
		orog:missing_value = 1.e+20f ;
		orog:_FillValue = 1.e+20f ;
		orog:grid_mapping = "rotated_latitude_longitude" ;
		orog:coordinates = "lat lon" ;

// global attributes:
		:Conventions = "CF-1.11" ;
		:activity_id = "DD" ;
		:contact = "gerics-cordex@hereon.de" ;
		:creation_date = "2026-10-20T12:56:02Z" ;
		:domain = "Europe" ;
		:domain_id = "EUR-12" ;
		:driving_experiment = "reanalysis simulation of the recent past" ;
		:driving_experiment_id = "evaluation" ;
		:driving_institution_id = "ECMWF" ;
		:driving_source = "ECMWF Reanalysis v5" ;
		:driving_source_id = "ERA5" ;
		:driving_variant_label = "r1i1p1f1" ;
		:experiment_id = "evaluation" ;
		:external_variables = "areacella" ;
		:frequency = "fx" ;
		:grid = "Rotated-pole latitude-longitude with 0.11 degree grid spacing" ;
		:history = "2026-10-20T12:56:02Z ;rewrote data to be consistent with CORDEX-CMIP6 for variable orog found in table fx." ;
		:institution = "Climate Service Center Germany, Helmholtz Centre hereon GmbH, Hamburg, Germany" ;
		:institution_id = "GERICS" ;
		:label = "REMO2020 v2.2" ;
		:mip_era = "CMIP6" ;
		:product = "model-output" ;
		:project_id = "CORDEX-CMIP6" ;
		:references = "https://www.remo-rcm.de" ;
		:run_variant = "1st realization" ;
		:source = "Regional Climate Model REMO, version 2.2, hydrostatic configuration with MACv2 aerosol forcing and Fresh-water Lake model (FLake) (2023)" ;
		:source_id = "REMO2020-2-2" ;
		:source_type = "ARCM" ;
		:table_id = "fx" ;
		:table_info = "Name: CORDEX-CMIP6_fx.json; Creation Date:(07 September 2026) MD5:7d8c68a16e22b8a61989906b159c0196" ;
		:title = "GERICS REMO2020-2-2 downscaling of ERA5 evaluation for CORDEX-CMIP6 EUR-12" ;
		:tracking_id = "hdl:21.14103/844d0a4d-606d-47f1-8b8c-7d30e542739b" ;
		:variable_id = "orog" ;
		:version_realization = "v1-r1" ;
		:license = "https://cordex.org/data-access/cordex-cmip6-data/cordex-cmip6-terms-of-use" ;
		:cmor_version = "3.16.0" ;
}

Interactive Dataset Exploration with xarray#

The xarray dataset representation provides an interactive way to explore the dataset structure, dimensions, variables, and attributes:

ds = xr.open_dataset(f)
ds
<xarray.Dataset> Size: 15MB
Dimensions:                     (rlat: 412, rlon: 424, vertices: 4)
Coordinates:
  * rlat                        (rlat) float64 3kB -23.38 -23.27 ... 21.73 21.84
  * rlon                        (rlon) float64 3kB -28.38 -28.27 ... 18.05 18.16
    lat                         (rlat, rlon) float64 1MB ...
    lon                         (rlat, rlon) float64 1MB ...
Dimensions without coordinates: vertices
Data variables:
    rotated_latitude_longitude  int32 4B ...
    vertices_lat                (rlat, rlon, vertices) float64 6MB ...
    vertices_lon                (rlat, rlon, vertices) float64 6MB ...
    orog                        (rlat, rlon) float32 699kB ...
Attributes: (12/36)
    Conventions:             CF-1.11
    activity_id:             DD
    contact:                 gerics-cordex@hereon.de
    creation_date:           2026-10-20T12:56:02Z
    domain:                  Europe
    domain_id:               EUR-12
    ...                      ...
    title:                   GERICS REMO2020-2-2 downscaling of ERA5 evaluati...
    tracking_id:             hdl:21.14103/844d0a4d-606d-47f1-8b8c-7d30e542739b
    variable_id:             orog
    version_realization:     v1-r1
    license:                 https://cordex.org/data-access/cordex-cmip6-data...
    cmor_version:            3.16.0
ds.orog.plot()
<matplotlib.collections.QuadMesh at 0x7f34037eb020>
_images/548978f5b484f64f29aa761225351c96dce36daa86a25a3743e519af8040b8e9.png

In the following cell, we will demonstrate how to check the cmorized datasets using three different tools: cdo verifygrid, cf-checker, and the IOOS compliance-checker including the WCRP plugin:

!cdo verifygrid $f
cdo    verifygrid: Grid consists of 174688 (424x412) cells (type: curvilinear), of which
cdo    verifygrid:    174688 cells have 4 vertices
cdo    verifygrid:        lon : -44.59386 to 64.96438 degrees
cdo    verifygrid:        lat : 21.98783 to 72.585 degrees
cdo    verifygrid: Processed 1 variable [0.11s 602M]
!cfchecks $f
CHECKING NetCDF FILE: CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/fx/orog/v20261020/orog_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_fx.nc
=====================
Using CF Checker Version 4.1.0
Checking against CF Version CF-1.8
Using Standard Name Table Version 95 (2026-09-16T04:56:46Z)
Using Area Type Table Version 13 (20 March 2025)
Using Standardized Region Name Table Version 5 (12 November 2024)

ERROR: (2.6.1): This netCDF file does not appear to contain CF Convention data.
WARN: (7.1): Boundary var vertices_lat should not have attribute units
WARN: (7.1): Boundary var vertices_lon should not have attribute units

------------------
Checking variable: rlat
------------------

------------------
Checking variable: rlon
------------------

------------------
Checking variable: rotated_latitude_longitude
------------------

------------------
Checking variable: lat
------------------

------------------
Checking variable: lon
------------------

------------------
Checking variable: vertices_lat
------------------
WARN: (7.1): Boundary Variable vertices_lat should not have _FillValue attribute
WARN: (7.1): Boundary Variable vertices_lat should not have missing_value attribute

------------------
Checking variable: vertices_lon
------------------
WARN: (7.1): Boundary Variable vertices_lon should not have _FillValue attribute
WARN: (7.1): Boundary Variable vertices_lon should not have missing_value attribute

------------------
Checking variable: orog
------------------

ERRORS detected: 1
WARNINGS given: 6
INFORMATION messages: 0

The compliance checker can be used to validate the cmorized file against the CORDEX-CMIP6 standard. Note that these tests should return no high priority issues. The following command runs the compliance checker with the appropriate tests:

!compliance-checker --test=cf:1.11 --test=wcrp_cordex_cmip6 $f
Running Compliance Checker on the datasets from: ['CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/fx/orog/v20261020/orog_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_fx.nc']
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_coordinate.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_coordinate.json'.
SHA256 hash of downloaded file: ebdc7e928412179be6db384f3b3955383248a0d9581712ad91eed1730319bf4a
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_grids.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_grids.json'.
SHA256 hash of downloaded file: 6d9b6f6b4678be242c70b23620748aaa67e509fc624c060231d92108e409dd8f
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_formula_terms.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_formula_terms.json'.
SHA256 hash of downloaded file: 3d6ae4d188ad95dbea93fa4ca19f81e2d7c6cecf3707acd768549a8201e36819
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_CV.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_CV.json'.
SHA256 hash of downloaded file: a73c6a78843632cc1f816b6b778e54a166ac97311b9959b000ca176a5307881c
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_1hr.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_1hr.json'.
SHA256 hash of downloaded file: 6ca30fec98917f29fa1193f3f91f2c6a29bab75bb304003fd72e8e6f689d48f8
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_3hr.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_3hr.json'.
SHA256 hash of downloaded file: 7c9411fb89eb8e8599cba86f72d87515a83e487de7b2b37df6c1f783192b7b67
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_6hr.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_6hr.json'.
SHA256 hash of downloaded file: 13a133c9003d035eac652ef967aa89c0b746bd529e23e5e2a26861a060e31b61
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_day.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_day.json'.
SHA256 hash of downloaded file: 7b283897583cf443ebf44b9492e0e4214330927549f6e977578e7686a76e6370
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_mon.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_mon.json'.
SHA256 hash of downloaded file: ad3b9822376c3637aa63609f3d2851ebf703a17ba443fc7e6f2d2f2919e13b57
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.
Downloading data from 'https://raw.githubusercontent.com/WCRP-CORDEX/cordex-cmip6-cmor-tables/main/Tables/CORDEX-CMIP6_fx.json' to file '/home/runner/.wcrp_metadata/cordex-cmip6-cmor-tables/CORDEX-CMIP6_fx.json'.
SHA256 hash of downloaded file: 82c82a16a8258a901144f484ecd13893ef39480acfdf1967e0737a0c93dba48b
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.


--------------------------------------------------------------------------------
                         IOOS Compliance Checker Report                         
                                 Version 6.1.0                                  
                     Report generated 2026-10-20T12:56:08Z                      
                                    cf:1.11                                     
http://cfconventions.org/Data/cf-conventions/cf-conventions-1.11/cf-conventions.html
--------------------------------------------------------------------------------
                               Corrective Actions                               
orog_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_fx.nc has 1 potential issue


                                    Warnings                                    
--------------------------------------------------------------------------------
§7.1 Cell Boundaries
* Bounds variable vertices_lat and parent variable lat have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lon and parent variable lon have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lat and parent variable lat have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lon and parent variable lon have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* The Boundary variables 'vertices_lat' should not have the attributes: '['units', 'missing_value', '_FillValue']'
* The Boundary variables 'vertices_lon' should not have the attributes: '['units', 'missing_value', '_FillValue']'


--------------------------------------------------------------------------------
                         IOOS Compliance Checker Report                         
                                 Version 6.1.0                                  
                     Report generated 2026-10-20T12:56:08Z                      
                             wcrp_cordex_cmip6:1.0                              
                                                                                
--------------------------------------------------------------------------------
All tests passed!

Example 2: Monthly Aggregated Data (mon) - Temperature#

This example demonstrates CMORization of monthly averaged data. We use 2-meter temperature (tas), a standard meteorological variable that’s typically provided as monthly means in climate archives. The CMORization process ensures proper scaling, dimension ordering, and CF convention compliance:

f = test_cmorizer_mon()
f
/tmp/ipykernel_3516/2886418336.py:54: DeprecationWarning: 'CORDEX_domain' keyword is deprecated, please use the 'domain_id' keyword instead
  filename = cmor.cmorize_variable(
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1035: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  unused_keys = set(attribute.keys()) - set(inverted)
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1036: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  for key, value in attribute.items():
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1044: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  newmap.update({key: attribute[key] for key in unused_keys})
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:635: UserWarning: adding time bounds
  warn("adding time bounds")
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:426: UserWarning: time units are set to default: days since 1950-01-01T00:00:00
  warn(f"time units are set to default: {u}")
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/utils.py:339: UserWarning: writing temporary table to /tmp/tmp5nbmlcr1
  warn(f"writing temporary table to {filename}")
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1035: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  unused_keys = set(attribute.keys()) - set(inverted)
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1036: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  for key, value in attribute.items():
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1044: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  newmap.update({key: attribute[key] for key in unused_keys})

C Traceback:
In function: cmor_values_from_bounds
! called from: cmor_axis
! 

!!!!!!!!!!!!!!!!!!!!!!!!!
!
! Warning: The values you provided for axis time are different from those computed from the bounds, which are used for the axis values instead of the user-provided values.
!
! The first value found is at index 0: 18276.000000 will be replaced with 18277.500000 between bounds 18262.000000 and 18293.000000
!
!!!!!!!!!!!!!!!!!!!!!!!!!
'CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/mon/tas/v20261020/tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_mon_200001-200012.nc'
ds = xr.open_dataset(f)
ds
<xarray.Dataset> Size: 22MB
Dimensions:                     (time: 12, bnds: 2, rlat: 412, rlon: 424,
                                 vertices: 4)
Coordinates:
  * time                        (time) datetime64[ns] 96B 2000-01-16T12:00:00...
  * rlat                        (rlat) float64 3kB -23.38 -23.27 ... 21.73 21.84
  * rlon                        (rlon) float64 3kB -28.38 -28.27 ... 18.05 18.16
    lat                         (rlat, rlon) float64 1MB ...
    lon                         (rlat, rlon) float64 1MB ...
    height                      float64 8B ...
Dimensions without coordinates: bnds, vertices
Data variables:
    time_bnds                   (time, bnds) datetime64[ns] 192B ...
    rotated_latitude_longitude  int32 4B ...
    vertices_lat                (rlat, rlon, vertices) float64 6MB ...
    vertices_lon                (rlat, rlon, vertices) float64 6MB ...
    tas                         (time, rlat, rlon) float32 8MB ...
Attributes: (12/36)
    Conventions:             CF-1.11
    activity_id:             DD
    contact:                 gerics-cordex@hereon.de
    creation_date:           2026-10-20T12:56:09Z
    domain:                  Europe
    domain_id:               EUR-12
    ...                      ...
    title:                   GERICS REMO2020-2-2 downscaling of ERA5 evaluati...
    tracking_id:             hdl:21.14103/12d482c5-0075-461a-be17-588a0beb0a00
    variable_id:             tas
    version_realization:     v1-r1
    license:                 https://cordex.org/data-access/cordex-cmip6-data...
    cmor_version:            3.16.0
ds.cf
Coordinates:
             CF Axes: * X: ['rlon']
                      * Y: ['rlat']
                        Z: ['height']
                      * T: ['time']

      CF Coordinates:   longitude: ['lon']
                        latitude: ['lat']
                        vertical: ['height']
                      * time: ['time']

       Cell Measures:   area, volume: n/a

      Standard Names: * grid_latitude: ['rlat']
                      * grid_longitude: ['rlon']
                        height: ['height']
                        latitude: ['lat']
                        longitude: ['lon']
                      * time: ['time']

              Bounds:   n/a

       Grid Mappings:   n/a

Data Variables:
       Cell Measures:   area, volume: n/a

      Standard Names:   air_temperature: ['tas']

              Bounds:   T: ['time_bnds']
                        lat: ['vertices_lat']
                        latitude: ['vertices_lat']
                        lon: ['vertices_lon']
                        longitude: ['vertices_lon']
                        time: ['time_bnds']

       Grid Mappings:   rotated_latitude_longitude: ['rotated_latitude_longitude']
ds.tas.plot(col="time", col_wrap=4)
<xarray.plot.facetgrid.FacetGrid at 0x7f3403287fe0>
_images/883bdd960ccc707ce1a06cc4b3d69f33db251fab03fe501f60d40b6a9fbda5f5.png
!ncdump -h $f
netcdf tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_mon_200001-200012 {
dimensions:
	time = UNLIMITED ; // (12 currently)
	rlat = 412 ;
	rlon = 424 ;
	bnds = 2 ;
	vertices = 4 ;
variables:
	double time(time) ;
		time:bounds = "time_bnds" ;
		time:units = "days since 1950-01-01T00:00:00" ;
		time:calendar = "proleptic_gregorian" ;
		time:axis = "T" ;
		time:long_name = "time" ;
		time:standard_name = "time" ;
	double time_bnds(time, bnds) ;
	double rlat(rlat) ;
		rlat:units = "degrees" ;
		rlat:axis = "Y" ;
		rlat:long_name = "latitude in rotated pole grid" ;
		rlat:standard_name = "grid_latitude" ;
	double rlon(rlon) ;
		rlon:units = "degrees" ;
		rlon:axis = "X" ;
		rlon:long_name = "longitude in rotated pole grid" ;
		rlon:standard_name = "grid_longitude" ;
	int rotated_latitude_longitude ;
		rotated_latitude_longitude:grid_mapping_name = "rotated_latitude_longitude" ;
		rotated_latitude_longitude:grid_north_pole_latitude = 39.25 ;
		rotated_latitude_longitude:grid_north_pole_longitude = -162. ;
		rotated_latitude_longitude:north_pole_grid_longitude = 0. ;
		rotated_latitude_longitude:earth_radius = 6371229. ;
	double lat(rlat, rlon) ;
		lat:standard_name = "latitude" ;
		lat:long_name = "latitude" ;
		lat:units = "degrees_north" ;
		lat:missing_value = 1.e+20 ;
		lat:_FillValue = 1.e+20 ;
		lat:bounds = "vertices_lat" ;
	double lon(rlat, rlon) ;
		lon:standard_name = "longitude" ;
		lon:long_name = "longitude" ;
		lon:units = "degrees_east" ;
		lon:missing_value = 1.e+20 ;
		lon:_FillValue = 1.e+20 ;
		lon:bounds = "vertices_lon" ;
	double vertices_lat(rlat, rlon, vertices) ;
		vertices_lat:units = "degrees_north" ;
		vertices_lat:missing_value = 1.e+20 ;
		vertices_lat:_FillValue = 1.e+20 ;
	double vertices_lon(rlat, rlon, vertices) ;
		vertices_lon:units = "degrees_east" ;
		vertices_lon:missing_value = 1.e+20 ;
		vertices_lon:_FillValue = 1.e+20 ;
	double height ;
		height:units = "m" ;
		height:axis = "Z" ;
		height:positive = "up" ;
		height:long_name = "height" ;
		height:standard_name = "height" ;
	float tas(time, rlat, rlon) ;
		tas:standard_name = "air_temperature" ;
		tas:long_name = "Near-Surface Air Temperature" ;
		tas:comment = "near-surface (usually, 2 meter) air temperature" ;
		tas:units = "K" ;
		tas:cell_methods = "area: time: mean" ;
		tas:cell_measures = "area: areacella" ;
		tas:history = "2026-10-20T12:56:09Z altered by CMOR: Treated scalar dimension: \'height\'." ;
		tas:coordinates = "height lat lon" ;
		tas:missing_value = 1.e+20f ;
		tas:_FillValue = 1.e+20f ;
		tas:grid_mapping = "rotated_latitude_longitude" ;

// global attributes:
		:Conventions = "CF-1.11" ;
		:activity_id = "DD" ;
		:contact = "gerics-cordex@hereon.de" ;
		:creation_date = "2026-10-20T12:56:09Z" ;
		:domain = "Europe" ;
		:domain_id = "EUR-12" ;
		:driving_experiment = "reanalysis simulation of the recent past" ;
		:driving_experiment_id = "evaluation" ;
		:driving_institution_id = "ECMWF" ;
		:driving_source = "ECMWF Reanalysis v5" ;
		:driving_source_id = "ERA5" ;
		:driving_variant_label = "r1i1p1f1" ;
		:experiment_id = "evaluation" ;
		:external_variables = "areacella" ;
		:frequency = "mon" ;
		:grid = "Rotated-pole latitude-longitude with 0.11 degree grid spacing" ;
		:history = "2026-10-20T12:56:09Z ;rewrote data to be consistent with CORDEX-CMIP6 for variable tas found in table mon." ;
		:institution = "Climate Service Center Germany, Helmholtz Centre hereon GmbH, Hamburg, Germany" ;
		:institution_id = "GERICS" ;
		:label = "REMO2020 v2.2" ;
		:mip_era = "CMIP6" ;
		:product = "model-output" ;
		:project_id = "CORDEX-CMIP6" ;
		:references = "https://www.remo-rcm.de" ;
		:run_variant = "1st realization" ;
		:source = "Regional Climate Model REMO, version 2.2, hydrostatic configuration with MACv2 aerosol forcing and Fresh-water Lake model (FLake) (2023)" ;
		:source_id = "REMO2020-2-2" ;
		:source_type = "ARCM" ;
		:table_id = "mon" ;
		:table_info = "Name: CORDEX-CMIP6_mon.json; Creation Date:(07 September 2026) MD5:b10b18e683ad5e012613a22c64d9001e" ;
		:title = "GERICS REMO2020-2-2 downscaling of ERA5 evaluation for CORDEX-CMIP6 EUR-12" ;
		:tracking_id = "hdl:21.14103/12d482c5-0075-461a-be17-588a0beb0a00" ;
		:variable_id = "tas" ;
		:version_realization = "v1-r1" ;
		:license = "https://cordex.org/data-access/cordex-cmip6-data/cordex-cmip6-terms-of-use" ;
		:cmor_version = "3.16.0" ;
}
!cfchecks $f
CHECKING NetCDF FILE: CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/mon/tas/v20261020/tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_mon_200001-200012.nc
=====================
Using CF Checker Version 4.1.0
Checking against CF Version CF-1.8
Using Standard Name Table Version 95 (2026-09-16T04:56:46Z)
Using Area Type Table Version 13 (20 March 2025)
Using Standardized Region Name Table Version 5 (12 November 2024)

ERROR: (2.6.1): This netCDF file does not appear to contain CF Convention data.
WARN: (7.1): Boundary var vertices_lat should not have attribute units
WARN: (7.1): Boundary var vertices_lon should not have attribute units

------------------
Checking variable: time
------------------

------------------
Checking variable: time_bnds
------------------

------------------
Checking variable: rlat
------------------

------------------
Checking variable: rlon
------------------

------------------
Checking variable: rotated_latitude_longitude
------------------

------------------
Checking variable: lat
------------------

------------------
Checking variable: lon
------------------

------------------
Checking variable: vertices_lat
------------------
WARN: (7.1): Boundary Variable vertices_lat should not have _FillValue attribute
WARN: (7.1): Boundary Variable vertices_lat should not have missing_value attribute

------------------
Checking variable: vertices_lon
------------------
WARN: (7.1): Boundary Variable vertices_lon should not have _FillValue attribute
WARN: (7.1): Boundary Variable vertices_lon should not have missing_value attribute

------------------
Checking variable: height
------------------

------------------
Checking variable: tas
------------------
INFO: attribute history is being used in a non-standard way

ERRORS detected: 1
WARNINGS given: 6
INFORMATION messages: 1
!compliance-checker --test=cf:1.11 --test=wcrp_cordex_cmip6 $f
Running Compliance Checker on the datasets from: ['CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/mon/tas/v20261020/tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_mon_200001-200012.nc']
--------------------------------------------------------------------------------
                         IOOS Compliance Checker Report                         
                                 Version 6.1.0                                  
                     Report generated 2026-10-20T12:56:15Z                      
                                    cf:1.11                                     
http://cfconventions.org/Data/cf-conventions/cf-conventions-1.11/cf-conventions.html
--------------------------------------------------------------------------------
                               Corrective Actions                               
tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_mon_200001-200012.nc has 3 potential issues


                                    Warnings                                    
--------------------------------------------------------------------------------
§3.1.2 Temperature units
* Variable tas has a temperature related standard_name and it is recommended that the units_metadata attribute is present and has one of the values ['temperature: difference', 'temperature: on_scale', 'temperature: unknown']

§4.4 Time Coordinate
* Variable time has a calendar attribute of proleptic_gregorian and it is recommended that the units_metadata attribute is present and has one of the values ['leap_seconds: none', 'leap_seconds: utc', 'leap_seconds: unknown']

§7.1 Cell Boundaries
* Bounds variable vertices_lat and parent variable lat have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lon and parent variable lon have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lat and parent variable lat have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lon and parent variable lon have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* The Boundary variables 'vertices_lat' should not have the attributes: '['units', 'missing_value', '_FillValue']'
* The Boundary variables 'vertices_lon' should not have the attributes: '['units', 'missing_value', '_FillValue']'


--------------------------------------------------------------------------------
                         IOOS Compliance Checker Report                         
                                 Version 6.1.0                                  
                     Report generated 2026-10-20T12:56:15Z                      
                             wcrp_cordex_cmip6:1.0                              
                                                                                
--------------------------------------------------------------------------------
All tests passed!

Example 3: Sub-daily Data (1hr, 3hr, 6hr, day) - Temperature#

This example demonstrates the flexibility of the CMORization process for sub-daily data. Starting with hourly temperature data, we show how it can be automatically resampled to various standard time frequencies:

  • 1 hour (1hr): Raw hourly output

  • 3 hours (3hr): Averaged over 3-hour intervals

  • 6 hours (6hr): Averaged over 6-hour intervals

  • Daily (day): Daily averaged values

The allow_resample=True parameter enables automatic temporal aggregation to match the target CMOR table frequency:

f = test_cmorizer_subdaily("1hr")
f
/tmp/ipykernel_3516/2886418336.py:87: DeprecationWarning: 'CORDEX_domain' keyword is deprecated, please use the 'domain_id' keyword instead
  filename = cmor.cmorize_variable(
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1035: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  unused_keys = set(attribute.keys()) - set(inverted)
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1036: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  for key, value in attribute.items():
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1044: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  newmap.update({key: attribute[key] for key in unused_keys})
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:517: UserWarning: resampling input data from H to h
  warn(f"resampling input data from {input_freq} to {pd_freq}")
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:426: UserWarning: time units are set to default: days since 1950-01-01T00:00:00
  warn(f"time units are set to default: {u}")
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/utils.py:339: UserWarning: writing temporary table to /tmp/tmpcfduaji9
  warn(f"writing temporary table to {filename}")
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1035: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  unused_keys = set(attribute.keys()) - set(inverted)
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1036: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  for key, value in attribute.items():
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1044: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  newmap.update({key: attribute[key] for key in unused_keys})
'CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/1hr/tas/v20261020/tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_1hr_200001010000-200001030000.nc'
ds = xr.open_dataset(f)
ds
<xarray.Dataset> Size: 48MB
Dimensions:                     (rlat: 412, rlon: 424, vertices: 4, time: 49)
Coordinates:
  * rlat                        (rlat) float64 3kB -23.38 -23.27 ... 21.73 21.84
  * rlon                        (rlon) float64 3kB -28.38 -28.27 ... 18.05 18.16
    lat                         (rlat, rlon) float64 1MB ...
    lon                         (rlat, rlon) float64 1MB ...
  * time                        (time) datetime64[ns] 392B 2000-01-01 ... 200...
    height                      float64 8B ...
Dimensions without coordinates: vertices
Data variables:
    rotated_latitude_longitude  int32 4B ...
    vertices_lat                (rlat, rlon, vertices) float64 6MB ...
    vertices_lon                (rlat, rlon, vertices) float64 6MB ...
    tas                         (time, rlat, rlon) float32 34MB ...
Attributes: (12/36)
    Conventions:             CF-1.11
    activity_id:             DD
    contact:                 gerics-cordex@hereon.de
    creation_date:           2026-10-20T12:56:17Z
    domain:                  Europe
    domain_id:               EUR-12
    ...                      ...
    title:                   GERICS REMO2020-2-2 downscaling of ERA5 evaluati...
    tracking_id:             hdl:21.14103/dd8e870f-055b-4aa4-b8a2-6a943ca8ef9b
    variable_id:             tas
    version_realization:     v1-r1
    license:                 https://cordex.org/data-access/cordex-cmip6-data...
    cmor_version:            3.16.0
!ncdump -h $f
netcdf tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_1hr_200001010000-200001030000 {
dimensions:
	time = UNLIMITED ; // (49 currently)
	rlat = 412 ;
	rlon = 424 ;
	bnds = 2 ;
	vertices = 4 ;
variables:
	double time(time) ;
		time:units = "days since 1950-01-01T00:00:00" ;
		time:calendar = "proleptic_gregorian" ;
		time:axis = "T" ;
		time:long_name = "time" ;
		time:standard_name = "time" ;
	double rlat(rlat) ;
		rlat:units = "degrees" ;
		rlat:axis = "Y" ;
		rlat:long_name = "latitude in rotated pole grid" ;
		rlat:standard_name = "grid_latitude" ;
	double rlon(rlon) ;
		rlon:units = "degrees" ;
		rlon:axis = "X" ;
		rlon:long_name = "longitude in rotated pole grid" ;
		rlon:standard_name = "grid_longitude" ;
	int rotated_latitude_longitude ;
		rotated_latitude_longitude:grid_mapping_name = "rotated_latitude_longitude" ;
		rotated_latitude_longitude:grid_north_pole_latitude = 39.25 ;
		rotated_latitude_longitude:grid_north_pole_longitude = -162. ;
		rotated_latitude_longitude:north_pole_grid_longitude = 0. ;
		rotated_latitude_longitude:earth_radius = 6371229. ;
	double lat(rlat, rlon) ;
		lat:standard_name = "latitude" ;
		lat:long_name = "latitude" ;
		lat:units = "degrees_north" ;
		lat:missing_value = 1.e+20 ;
		lat:_FillValue = 1.e+20 ;
		lat:bounds = "vertices_lat" ;
	double lon(rlat, rlon) ;
		lon:standard_name = "longitude" ;
		lon:long_name = "longitude" ;
		lon:units = "degrees_east" ;
		lon:missing_value = 1.e+20 ;
		lon:_FillValue = 1.e+20 ;
		lon:bounds = "vertices_lon" ;
	double vertices_lat(rlat, rlon, vertices) ;
		vertices_lat:units = "degrees_north" ;
		vertices_lat:missing_value = 1.e+20 ;
		vertices_lat:_FillValue = 1.e+20 ;
	double vertices_lon(rlat, rlon, vertices) ;
		vertices_lon:units = "degrees_east" ;
		vertices_lon:missing_value = 1.e+20 ;
		vertices_lon:_FillValue = 1.e+20 ;
	double height ;
		height:units = "m" ;
		height:axis = "Z" ;
		height:positive = "up" ;
		height:long_name = "height" ;
		height:standard_name = "height" ;
	float tas(time, rlat, rlon) ;
		tas:standard_name = "air_temperature" ;
		tas:long_name = "Near-Surface Air Temperature" ;
		tas:comment = "near-surface (usually, 2 meter) air temperature" ;
		tas:units = "K" ;
		tas:cell_methods = "area: mean time: point" ;
		tas:cell_measures = "area: areacella" ;
		tas:history = "2026-10-20T12:56:17Z altered by CMOR: Treated scalar dimension: \'height\'." ;
		tas:coordinates = "height lat lon" ;
		tas:missing_value = 1.e+20f ;
		tas:_FillValue = 1.e+20f ;
		tas:grid_mapping = "rotated_latitude_longitude" ;

// global attributes:
		:Conventions = "CF-1.11" ;
		:activity_id = "DD" ;
		:contact = "gerics-cordex@hereon.de" ;
		:creation_date = "2026-10-20T12:56:17Z" ;
		:domain = "Europe" ;
		:domain_id = "EUR-12" ;
		:driving_experiment = "reanalysis simulation of the recent past" ;
		:driving_experiment_id = "evaluation" ;
		:driving_institution_id = "ECMWF" ;
		:driving_source = "ECMWF Reanalysis v5" ;
		:driving_source_id = "ERA5" ;
		:driving_variant_label = "r1i1p1f1" ;
		:experiment_id = "evaluation" ;
		:external_variables = "areacella" ;
		:frequency = "1hr" ;
		:grid = "Rotated-pole latitude-longitude with 0.11 degree grid spacing" ;
		:history = "2026-10-20T12:56:17Z ;rewrote data to be consistent with CORDEX-CMIP6 for variable tas found in table 1hr." ;
		:institution = "Climate Service Center Germany, Helmholtz Centre hereon GmbH, Hamburg, Germany" ;
		:institution_id = "GERICS" ;
		:label = "REMO2020 v2.2" ;
		:mip_era = "CMIP6" ;
		:product = "model-output" ;
		:project_id = "CORDEX-CMIP6" ;
		:references = "https://www.remo-rcm.de" ;
		:run_variant = "1st realization" ;
		:source = "Regional Climate Model REMO, version 2.2, hydrostatic configuration with MACv2 aerosol forcing and Fresh-water Lake model (FLake) (2023)" ;
		:source_id = "REMO2020-2-2" ;
		:source_type = "ARCM" ;
		:table_id = "1hr" ;
		:table_info = "Name: CORDEX-CMIP6_1hr.json; Creation Date:(07 September 2026) MD5:beebe3fa80cf01dc01cb22103d724c2a" ;
		:title = "GERICS REMO2020-2-2 downscaling of ERA5 evaluation for CORDEX-CMIP6 EUR-12" ;
		:tracking_id = "hdl:21.14103/dd8e870f-055b-4aa4-b8a2-6a943ca8ef9b" ;
		:variable_id = "tas" ;
		:version_realization = "v1-r1" ;
		:license = "https://cordex.org/data-access/cordex-cmip6-data/cordex-cmip6-terms-of-use" ;
		:cmor_version = "3.16.0" ;
}
!cfchecks $f
CHECKING NetCDF FILE: CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/1hr/tas/v20261020/tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_1hr_200001010000-200001030000.nc
=====================
Using CF Checker Version 4.1.0
Checking against CF Version CF-1.8
Using Standard Name Table Version 95 (2026-09-16T04:56:46Z)
Using Area Type Table Version 13 (20 March 2025)
Using Standardized Region Name Table Version 5 (12 November 2024)

ERROR: (2.6.1): This netCDF file does not appear to contain CF Convention data.
WARN: (7.1): Boundary var vertices_lat should not have attribute units
WARN: (7.1): Boundary var vertices_lon should not have attribute units

------------------
Checking variable: time
------------------

------------------
Checking variable: rlat
------------------

------------------
Checking variable: rlon
------------------

------------------
Checking variable: rotated_latitude_longitude
------------------

------------------
Checking variable: lat
------------------

------------------
Checking variable: lon
------------------

------------------
Checking variable: vertices_lat
------------------
WARN: (7.1): Boundary Variable vertices_lat should not have _FillValue attribute
WARN: (7.1): Boundary Variable vertices_lat should not have missing_value attribute

------------------
Checking variable: vertices_lon
------------------
WARN: (7.1): Boundary Variable vertices_lon should not have _FillValue attribute
WARN: (7.1): Boundary Variable vertices_lon should not have missing_value attribute

------------------
Checking variable: height
------------------

------------------
Checking variable: tas
------------------
INFO: attribute history is being used in a non-standard way

ERRORS detected: 1
WARNINGS given: 6
INFORMATION messages: 1
!compliance-checker --test=cf:1.11 --test=wcrp_cordex_cmip6 $f
Running Compliance Checker on the datasets from: ['CORDEX/CORDEX-CMIP6/DD/EUR-12/GERICS/ERA5/evaluation/r1i1p1f1/REMO2020-2-2/v1-r1/1hr/tas/v20261020/tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_1hr_200001010000-200001030000.nc']
--------------------------------------------------------------------------------
                         IOOS Compliance Checker Report                         
                                 Version 6.1.0                                  
                     Report generated 2026-10-20T12:56:20Z                      
                                    cf:1.11                                     
http://cfconventions.org/Data/cf-conventions/cf-conventions-1.11/cf-conventions.html
--------------------------------------------------------------------------------
                               Corrective Actions                               
tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_1hr_200001010000-200001030000.nc has 3 potential issues


                                    Warnings                                    
--------------------------------------------------------------------------------
§3.1.2 Temperature units
* Variable tas has a temperature related standard_name and it is recommended that the units_metadata attribute is present and has one of the values ['temperature: difference', 'temperature: on_scale', 'temperature: unknown']

§4.4 Time Coordinate
* Variable time has a calendar attribute of proleptic_gregorian and it is recommended that the units_metadata attribute is present and has one of the values ['leap_seconds: none', 'leap_seconds: utc', 'leap_seconds: unknown']

§7.1 Cell Boundaries
* Bounds variable vertices_lat and parent variable lat have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lon and parent variable lon have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lat and parent variable lat have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* Bounds variable vertices_lon and parent variable lon have the following matching attributes ['units'].  It is recommended that only the parent variable of the bounds variable contains these attributes
* The Boundary variables 'vertices_lat' should not have the attributes: '['units', 'missing_value', '_FillValue']'
* The Boundary variables 'vertices_lon' should not have the attributes: '['units', 'missing_value', '_FillValue']'


--------------------------------------------------------------------------------
                         IOOS Compliance Checker Report                         
                                 Version 6.1.0                                  
                     Report generated 2026-10-20T12:56:20Z                      
                             wcrp_cordex_cmip6:1.0                              
                                                                                
--------------------------------------------------------------------------------
                               Corrective Actions                               
tas_EUR-12_ERA5_evaluation_r1i1p1f1_GERICS_REMO2020-2-2_v1-r1_1hr_200001010000-200001030000.nc has 1 potential issue


                                  Recommended                                   
--------------------------------------------------------------------------------
[CDXT001] Time Chunking
* File chunking recommendations: '1' full simulation year is expected in the data file for frequency '1hr'. The last timestep conflicts with this recommendation ('2000-12-31 23:00:00'): '2000-01-03 00:00:00'. 
# Demonstration of automatic resampling: Starting from hourly data,
# the CMORization process automatically aggregates to daily frequency
# based on the CMOR table definition
f = test_cmorizer_subdaily("day")
f
/tmp/ipykernel_3516/2886418336.py:87: DeprecationWarning: 'CORDEX_domain' keyword is deprecated, please use the 'domain_id' keyword instead
  filename = cmor.cmorize_variable(
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1035: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  unused_keys = set(attribute.keys()) - set(inverted)
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1036: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  for key, value in attribute.items():
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cf_xarray/accessor.py:1044: FutureWarning: The return type of `Dataset.dims` will be changed to return a set of dimension names in future, in order to be more consistent with `DataArray.dims`. To access a mapping from dimension names to lengths, please use `Dataset.sizes`.
  newmap.update({key: attribute[key] for key in unused_keys})
/home/runner/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:517: UserWarning: resampling input data from H to D
  warn(f"resampling input data from {input_freq} to {pd_freq}")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[25], line 4
      1 # Demonstration of automatic resampling: Starting from hourly data,
      2 # the CMORization process automatically aggregates to daily frequency
      3 # based on the CMOR table definition
----> 4 f = test_cmorizer_subdaily("day")
      5 f

Cell In[4], line 87, in test_cmorizer_subdaily(table)
     83     str
     84         Path to the cmorized netCDF file
     85     """
     86     ds = cx.tutorial.open_dataset("remo_EUR-11_TEMP2_1hr")
---> 87     filename = cmor.cmorize_variable(
     88         ds,
     89         "tas",
     90         mapping_table={"tas": {"varname": "TEMP2"}},

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:813, in cmorize_variable(ds, out_name, cmor_table, dataset_table, mapping_table, grids_table, inpath, replace_coords, allow_units_convert, allow_resample, input_freq, domain_id, crop, time_units, rewrite_time_axis, outpath, **kwargs)
    810 if outpath:
    811     dataset_table["outpath"] = outpath
--> 813 ds_prep = prepare_variable(
    814     ds,
    815     out_name,
    816     cmor_table,
    817     domain_id=domain_id,
    818     mapping_table=mapping_table,
    819     replace_coords=replace_coords,
    820     input_freq=input_freq,
    821     rewrite_time_axis=rewrite_time_axis,
    822     time_units=time_units,
    823     allow_resample=allow_resample,
    824     allow_units_convert=allow_units_convert,
    825     crop=crop,
    826     **kwargs,
    827 )
    829 return cmorize_cmor(
    830     ds_prep, out_name, cmor_table, dataset_table, grids_table, inpath
    831 )

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:631, in prepare_variable(ds, out_name, cmor_table, mapping_table, replace_coords, allow_units_convert, allow_resample, input_freq, domain_id, time_units, rewrite_time_axis, use_cftime, squeeze, crop, guess_coord_axis)
    629 var_ds = var_ds.convert_calendar(ds.time.dt.calendar, use_cftime=True)
    630 if allow_resample is True:
--> 631     var_ds = _adjust_frequency(var_ds, cf_freq, input_freq, time_cell_method)
    632 if rewrite_time_axis is True:
    633     var_ds = _rewrite_time_axis(var_ds, cf_freq)

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:518, in _adjust_frequency(ds, cf_freq, input_freq, time_cell_method)
    516 if pd_freq != input_freq:
    517     warn(f"resampling input data from {input_freq} to {pd_freq}")
--> 518     resample = _resample(
    519         ds, pd_freq, time_cell_method=time_cell_method, **options["resample_kwargs"]
    520     )
    521     return resample
    522 return ds

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/cordex/cmor/cmor.py:97, in _resample(ds, time, time_cell_method, label, time_offset, **kwargs)
     95         mean_kwargs["engine"] = "flox"
     96         mean_kwargs["method"] = default_flox_method
---> 97     return ds.resample(time=time, label=label, offset=loffset, **kwargs).mean(
     98         **mean_kwargs
     99     )
    100 else:
    101     raise Exception(f"unknown time_cell_method: {time_cell_method}")

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/_aggregations.py:5935, in DatasetResampleAggregations.mean(self, dim, skipna, keep_attrs, **kwargs)
   5925     return self._flox_reduce(
   5926         func="mean",
   5927         dim=dim,
   (...)   5932         **kwargs,
   5933     )
   5934 else:
-> 5935     out = self.reduce(
   5936         duck_array_ops.mean,
   5937         dim=dim,
   5938         skipna=skipna,
   5939         numeric_only=True,
   5940         keep_attrs=keep_attrs,
   5941         **kwargs,
   5942     )
   5943     return out

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/resample.py:499, in DatasetResample.reduce(self, func, dim, axis, keep_attrs, shortcut, **kwargs)
    465 def reduce(
    466     self,
    467     func: Callable[..., Any],
   (...)    473     **kwargs: Any,
    474 ) -> Dataset:
    475     """Reduce the items in this group by applying `func` along the
    476     pre-defined resampling dimension.
    477 
   (...)    497         removed.
    498     """
--> 499     return super().reduce(
    500         func=func,
    501         dim=dim,
    502         axis=axis,
    503         keep_attrs=keep_attrs,
    504         shortcut=shortcut,
    505         **kwargs,
    506     )

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/groupby.py:1966, in DatasetGroupByBase.reduce(self, func, dim, axis, keep_attrs, shortcut, **kwargs)
   1955     return ds.reduce(
   1956         func=func,
   1957         dim=dim,
   (...)   1961         **kwargs,
   1962     )
   1964 check_reduce_dims(dim, self.dims)
-> 1966 return self.map(reduce_dataset)

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/resample.py:436, in DatasetResample.map(self, func, args, shortcut, **kwargs)
    434 # ignore shortcut if set (for now)
    435 applied = (func(ds, *args, **kwargs) for ds in self._iter_grouped())
--> 436 combined = self._combine(applied)
    438 # If the aggregation function didn't drop the original resampling
    439 # dimension, then we need to do so before we can rename the proxy
    440 # dimension we used.
    441 if self._dim in combined.coords:

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/groupby.py:1873, in DatasetGroupByBase._combine(self, applied)
   1871 def _combine(self, applied):
   1872     """Recombine the applied objects like the original."""
-> 1873     applied_example, applied = peek_at(applied)
   1874     dim, positions = self._infer_concat_args(applied_example)
   1875     combined = concat(
   1876         applied,
   1877         dim,
   (...)   1881         join="outer",
   1882     )

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/utils.py:287, in peek_at(iterable)
    283 """Returns the first value from iterable, as well as a new iterator with
    284 the same content as the original iterable
    285 """
    286 gen = iter(iterable)
--> 287 peek = next(gen)
    288 return peek, itertools.chain([peek], gen)

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/resample.py:435, in <genexpr>(.0)
    405 """Apply a function over each Dataset in the groups generated for
    406 resampling and concatenate them together into a new Dataset.
    407 
   (...)    432     The result of splitting, applying and combining this dataset.
    433 """
    434 # ignore shortcut if set (for now)
--> 435 applied = (func(ds, *args, **kwargs) for ds in self._iter_grouped())
    436 combined = self._combine(applied)
    438 # If the aggregation function didn't drop the original resampling
    439 # dimension, then we need to do so before we can rename the proxy
    440 # dimension we used.

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/groupby.py:1955, in DatasetGroupByBase.reduce.<locals>.reduce_dataset(ds)
   1954 def reduce_dataset(ds: Dataset) -> Dataset:
-> 1955     return ds.reduce(
   1956         func=func,
   1957         dim=dim,
   1958         axis=axis,
   1959         keep_attrs=keep_attrs,
   1960         keepdims=False,
   1961         **kwargs,
   1962     )

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/dataset.py:6975, in Dataset.reduce(self, func, dim, keep_attrs, keepdims, numeric_only, **kwargs)
   6971                     None
   6972                     if len(reduce_dims) == var.ndim and var.ndim != 1
   6973                     else reduce_dims
   6974                 )
-> 6975                 variables[name] = var.reduce(
   6976                     func,
   6977                     dim=reduce_maybe_single,
   6978                     keep_attrs=keep_attrs,

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/variable.py:1792, in Variable.reduce(self, func, dim, axis, keep_attrs, keepdims, **kwargs)
   1785 keep_attrs_ = (
   1786     _get_keep_attrs(default=True) if keep_attrs is None else keep_attrs
   1787 )
   1789 # Note that the call order for Variable.mean is
   1790 #    Variable.mean -> NamedArray.mean -> Variable.reduce
   1791 #    -> NamedArray.reduce
-> 1792 result = super().reduce(
   1793     func=func, dim=dim, axis=axis, keepdims=keepdims, **kwargs
   1794 )
   1796 # return Variable always to support IndexVariable
   1797 return Variable(
   1798     result.dims, result._data, attrs=result._attrs if keep_attrs_ else None
   1799 )

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/namedarray/core.py:930, in NamedArray.reduce(self, func, dim, axis, keepdims, **kwargs)
    928         data = func(self.data, axis=axis, **kwargs)
    929     else:
--> 930         data = func(self.data, **kwargs)
    932 if getattr(data, "shape", ()) == self.shape:
    933     dims = self.dims

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/duck_array_ops.py:811, in mean(array, axis, skipna, **kwargs)
    809     return _to_pytimedelta(mean_timedeltas, unit="us") + offset
    810 else:
--> 811     return _mean(array, axis=axis, skipna=skipna, **kwargs)

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/xarray/core/duck_array_ops.py:563, in _create_nan_agg_method.<locals>.f(values, axis, skipna, **kwargs)
    561     with warnings.catch_warnings():
    562         warnings.filterwarnings("ignore", "All-NaN slice encountered")
--> 563         return func(values, axis=axis, **kwargs)
    564 except AttributeError:
    565     if not is_duck_dask_array(values):

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/numpy/_core/fromnumeric.py:3862, in mean(a, axis, dtype, out, keepdims, where)
   3859     else:
   3860         return mean(axis=axis, dtype=dtype, out=out, **kwargs)
-> 3862 return _methods._mean(a, axis=axis, dtype=dtype,
   3863                       out=out, **kwargs)

File ~/micromamba/envs/cmor-examples/lib/python3.12/site-packages/numpy/_core/_methods.py:132, in _mean(a, axis, dtype, out, keepdims, where)
    129         dtype = mu.dtype('f4')
    130         is_float16_result = True
--> 132 ret = umr_sum(arr, axis, dtype, out, keepdims, where=where)
    133 if isinstance(ret, mu.ndarray):
    134     ret = um.true_divide(
    135             ret, rcount, out=ret, casting='unsafe', subok=False)

TypeError: the resolved dtypes are not compatible with add.reduce. Resolved (dtype('S1'), dtype('S1'), dtype('S2'))
ds = xr.open_dataset(f)
ds
ds.tas.plot(col="time")
!ncdump -h $f
!cfchecks $f
!compliance-checker --test=cf:1.11 --test=wcrp_cordex_cmip6 $f