Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,10 @@
"affiliation": "ACCESS-NRI, Australia",
"name": "Chun, Felicity",
"orcid": "0009-0007-0845-0953"
},
{
"affiliation": "Met Office, UK",
"name": "Ellis, Hannah"
}
],
"description": "ESMValTool: A community diagnostic and performance metrics tool for routine evaluation of Earth system models in CMIP.",
Expand Down
5 changes: 5 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,11 @@ authors:
family-names: Chun
given-names: Felicity
orcid: "https://orcid.org/0009-0007-0845-0953"
-
affiliation: "Met Office, UK"
family-names: Ellis
given-names: Hannah


cff-version: 1.2.0
date-released: 2025-09-04
Expand Down
2 changes: 2 additions & 0 deletions doc/sphinx/source/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ A list of the datasets for which a CMORizers is available is provided in the fol
+----------------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+
| Duveiller2018 | albDiffiTr13 | 2 | Python |
+----------------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+
| EN4 | tos, thetao, sos, so (Omon) | 2 | Python |
+----------------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+
| E-OBS | tas, tasmin, tasmax, pr, psl (day, Amon) | 2 | Python |
+----------------------------------------+------------------------------------------------------------------------------------------------------+------+-----------------+
| Eppley-VGPM-MODIS | intpp (Omon) | 2 | Python |
Expand Down
26 changes: 26 additions & 0 deletions esmvaltool/cmorizers/data/cmor_config/EN4.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---

# Filename
filename: 'EN.4.2.2.f.analysis.g10.*.nc'

# Common global attributes for Cmorizer output
attributes:
dataset_id: EN4
version: '4.2.2'
tier: 2
modeling_realm: reanaly
project_id: OBS6
source: 'https://www.metoffice.gov.uk/hadobs/en4/download-en4-2-2.html'
reference: 'good2013jgr'
comment: 'Uses analyses with Gouretski and Reseghetti (2010) XBT corrections and Gouretski and Cheng (2020) MBT corrections applied.'

# Variables to cmorize
variables:
thetao:
mip: Omon
raw_var: sea_water_potential_temperature
srf_var: tos
so:
mip: Omon
raw_var: sea_water_salinity
srf_var: sos
14 changes: 14 additions & 0 deletions esmvaltool/cmorizers/data/datasets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,20 @@ datasets:
- Complete the CMOR-config specifications (see instructions in the file
itself)

EN4:
tier: 2
source: "https://www.metoffice.gov.uk/hadobs/en4/download-en4-2-2.html"
last_access: 2025-06-13
info: |
EN4: quality controlled subsurface ocean temperature and salinity objective analyses.
Script tested using analyses with Gouretski and Reseghetti (2010) XBT corrections
and Gouretski and Cheng (2020) MBT corrections applied.
To download data:
- Edit the text file for your chosen years, https://www.metoffice.gov.uk/hadobs/en4/EN.4.2.2.analyses.g10.download-list.txt
- Save .txt file in directory for data to be downloaded to.
- Run 'wget -i EN.4.2.2.profiles.g10.download-list.txt' in same directory.
- Unzip files prior to running the cmorizer script.

Comment on lines +335 to +348
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can transfer this below the E-OBS entry for consistency please :)

E-OBS:
tier: 2
source: http://surfobs.climate.copernicus.eu/dataaccess/access_eobs.php#datafiles
Expand Down
128 changes: 128 additions & 0 deletions esmvaltool/cmorizers/data/formatters/datasets/en4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"""
CMORizer for EN4 dataset.
This script processes EN4 ocean temperature and salinity data to CMOR-compliant format for use in ESMValTool.
Tier
Tier 2: other freely-available dataset.
Source
https://www.metoffice.gov.uk/hadobs/en4/download-en4-2-2.html
Last access
2025-06-13
Info
EN4: quality controlled subsurface ocean temperature and salinity objective analyses.
Script tested using analyses with Gouretski and Reseghetti (2010) XBT corrections
and Gouretski and Cheng (2020) MBT corrections applied.
Download instructions
- Edit the text file for your chosen years, https://www.metoffice.gov.uk/hadobs/en4/EN.4.2.2.analyses.g10.download-list.txt
- Save .txt file in directory for data to be downloaded to.
- Run 'wget -i EN.4.2.2.profiles.g10.download-list.txt' in same directory.
- Unzip files prior to running the cmorizer script.
"""

import logging
from pathlib import Path

import iris

from esmvaltool.cmorizers.data import utilities as utils

logger = logging.getLogger(__name__)


def load_and_prepare_cube(fullpath, var, var_info, glob_attrs, cmor_table):
"""
Load and prepare a data cube for CMORization. Fix attributes, coordinates, and units.
Parameters
----------
fullpath : str
Path to the input file.
var : str
Name of the variable to save in output cube.
var_info : dict
Variable information dictionary.
glob_attrs : dict
Global attributes to set on the cube.
cmor_table : object
CMOR table.
Returns
-------
iris.cube.Cube
The prepared data cube.
"""

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

glob_attrs["mip"] = var_info["mip"]
raw_var = var_info["raw_var"]
cmor_info = cmor_table.get_variable(var_info["mip"], var)

cubes = iris.load(fullpath, raw_var)
iris.util.equalise_attributes(cubes)
cube = cubes.concatenate_cube()

if cube.units == "K":
cube.convert_units("degC")

cube.coord("depth").units = "m"
cube = utils.fix_coords(cube)
utils.fix_var_metadata(cube, cmor_info)
utils.set_global_atts(cube, glob_attrs)

return cube


def extract_surface_var(cube, cmor_info):
"""
Extract the surface level variable from a data cube.
Parameters
----------
cube : iris.cube.Cube
Input data cube.
cmor_info : object
CMOR table object for the surface variable.
Returns
-------
iris.cube.Cube
The extracted surface level cube.
"""
logger.info("Extracting surface level")

depth0 = iris.Constraint(depth=cube.coord("depth").points[0])
surface_cube = cube.extract(depth0)

utils.fix_var_metadata(surface_cube, cmor_info)

return surface_cube


def cmorization(in_dir, out_dir, cfg, cfg_user, start_date, end_date):
"""
CMORization main function call.
"""
Comment on lines +107 to +109
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
CMORization main function call.
"""
"""Cmorization main function call."""

cmor_table = cfg["cmor_table"]
glob_attrs = cfg["attributes"]
fullpath = str(Path(in_dir) / cfg["filename"])

for var, var_info in cfg["variables"].items():
logger.info("Loading %s", fullpath)

srf_var = var_info["srf_var"]
cmor_info_srf = cmor_table.get_variable(var_info["mip"], srf_var)

cube = load_and_prepare_cube(
fullpath, var, var_info, glob_attrs, cmor_table
)
surface_cube = extract_surface_var(cube, cmor_info_srf)
logger.info("Saving for %s", var)
utils.save_variable(cube, var, out_dir, glob_attrs)

logger.info("Saving for %s", srf_var)
utils.save_variable(surface_cube, srf_var, out_dir, glob_attrs)
13 changes: 12 additions & 1 deletion esmvaltool/recipes/examples/recipe_check_obs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
---
documentation:
description: |
Test recipe for OBS, no proprocessor or diagnostics are applied,
Test recipe for OBS, no preprocessor or diagnostics are applied,
just to check correct reading of the CMORized data.

title: Recipe to test run all obs cmorizers.
Expand Down Expand Up @@ -154,6 +154,17 @@ diagnostics:
type: clim, version: v2018, start_year: 2010, end_year: 2010}
scripts: null

EN4:
description: EN4 check
variables:
thetao:
tos:
so:
sos:
Comment on lines +160 to +163
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you consistently add these variables too to input.rst, EN4.yml, or delete tos and sos here as per V's comment? https://github.com/ESMValGroup/ESMValTool/pull/4193/files#r2359790298

additional_datasets:
- {dataset: EN4, project: OBS6, mip: Omon, type: reanaly,
version: 4.2.2, tier: 2, start_year: 1900, end_year: 2024}
scripts: null
Comment on lines +157 to +167
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And similarly to the datasets.yml entry, if you can have this after the E-OBS entry :)


E-OBS:
description: E-OBS check
Expand Down
12 changes: 12 additions & 0 deletions esmvaltool/references/good2013jgr.bibtex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@article{Good2013EN4:Estimates,
title = {{EN4: Quality controlled ocean temperature and salinity profiles and monthly objective analyses with uncertainty estimates}},
year = {2013},
journal = {Journal of Geophysical Research: Oceans},
author = {Good, Simon A. and Martin, Matthew J. and Rayner, Nick A.},
number = {12},
pages = {6704--6716},
volume = {118},
publisher = {Blackwell Publishing Ltd},
doi = {10.1002/2013JC009067},
issn = {21699291},
keywords = {objective analysis, ocean observations, quality control, uncertainty estimation}