Skip to content

Commit ebb27c0

Browse files
Merge branch 'main' into python3.14
2 parents db3f495 + 36a9a2c commit ebb27c0

9 files changed

Lines changed: 595 additions & 98 deletions

File tree

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,11 +455,11 @@ authors:
455455

456456

457457
cff-version: 1.2.0
458-
date-released: 2025-10-20
458+
date-released: 2026-03-13
459459
doi: "10.5281/zenodo.3401363"
460460
license: "Apache-2.0"
461461
message: "If you use this software, please cite it using these metadata."
462462
repository-code: "https://github.com/ESMValGroup/ESMValTool/"
463463
title: ESMValTool
464-
version: "v2.13.0"
464+
version: "v2.14.0"
465465
...

doc/sphinx/source/changelog.rst

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,138 @@
33
Changelog
44
=========
55

6+
.. _changelog-v2-14-0:
7+
8+
v2.14.0
9+
-------
10+
11+
Highlights
12+
~~~~~~~~~~
13+
14+
- New diagnostics/recipes:
15+
- Calculation of Lamb weathertypes (:pull:`4231`)
16+
- Histogram plots (:pull:`4329`)
17+
- Hour of maximum precipitation (:pull:`4334`)
18+
- Support for new observational datasets:
19+
- ESACCI SNOW (:pull:`3542`)
20+
- Improved support for ESACCI AEROSOL (:pull:`3629`)
21+
- EN4 (:pull:`4193`)
22+
- We modernized our development set-up and are now using `Ruff <https://docs.astral.sh/ruff/>`__ for :ref:`code_quality` checks and formatting.
23+
24+
This release includes
25+
26+
Backwards incompatible changes
27+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28+
29+
- Update the CMORizer command (:pull:`4317`, :pull:`4326`) by :user:`bouweandela`
30+
31+
.. admonition:: Upgrade instructions
32+
33+
The ``--config-file`` argument to the ``esmvaltool data`` commands has
34+
been removed. Please use these commands with the ``--config-dir``
35+
argument to specify the output directory, custom CMOR tables, or Dask
36+
configuration, and with the ``--original-data-dir`` argument to point the
37+
tool to the directory where downloaded original data should be saved.
38+
39+
Bug fixes
40+
~~~~~~~~~
41+
42+
- Fix recipe_enso_climatology1 - remove collect diagnostic (:pull:`4221`) by :user:`flicj191`
43+
- Rename ``modeling_realm`` to ``type`` in CMORizers (:pull:`4319`) by :user:`bouweandela`
44+
- Fix ``multi_datasets.py`` so it can handle different projections (:pull:`4358`) by :user:`schlunma`
45+
46+
Broken or retired recipes
47+
~~~~~~~~~~~~~~~~~~~~~~~~~
48+
49+
- Remove ``recipe_russel18jgr.yml`` from list of broken recipes (:pull:`4351`) by :user:`schlunma`
50+
- Retire ``recipe_climwip_brunner2019_med.yml`` (:pull:`4350`) by :user:`schlunma`
51+
- Add ``recipe_kcs.yml`` to list of broken recipes (:pull:`4354`) by :user:`schlunma`
52+
- Retire Wenzel recipes (:pull:`4357`) by :user:`schlunma`
53+
- Remove ``recipe_check_obs.yml`` from list of broken recipes (:pull:`4376`) by :user:`schlunma`
54+
- Retire ``recipe_eyring*jgr.yml`` (:pull:`4379`) by :user:`schlunma`
55+
56+
Documentation
57+
~~~~~~~~~~~~~
58+
59+
- Separate ESMValTool and ESMValCore documentation (:pull:`3914`) by :user:`flicj191`
60+
- Fix PDF documentation build (:pull:`4236`) by :user:`bouweandela`
61+
- Update links to ESMValCore configuration (:pull:`4249`) by :user:`bouweandela`
62+
- Document that we follow SPEC 0 (:pull:`4246`) by :user:`bouweandela`
63+
- Fix stable documentation build (:pull:`4253`) by :user:`bouweandela`
64+
- Update some easy to fix links in documentation (:pull:`4256`) by :user:`katjaweigel`
65+
- Add link checker github action for documentation (:pull:`4251`) by :user:`flicj191`
66+
- Add ENES-RI Zenodo community (:pull:`4254`) by :user:`bouweandela`
67+
- Schedule for link checker and update for recent report (:pull:`4305`) by :user:`flicj191`
68+
- Pin sphinx<9 (:pull:`4315`) by :user:`valeriupredoi`
69+
- Add Matomo page view tracking for the documentation (:pull:`4320`) by :user:`bouweandela`
70+
- Fix matomo integration (:pull:`4322`) by :user:`bouweandela`
71+
- Remove mentions of the deprecated config-developer.yml file from the documentation (:pull:`4335`) by :user:`bouweandela`
72+
- Documentation update -remove gensidebar (:pull:`4345`) by :user:`flicj191`
73+
- Update documentation on defining custom variables (:pull:`4349`) by :user:`bouweandela`
74+
- Update contact info (:pull:`4348`) by :user:`axel-lauer`
75+
- Remove mention of deprecated ``esmvaltool config get_config_user`` command (:pull:`4366`) by :user:`schlunma`
76+
- Update contact email in documentation (:pull:`4383`) by :user:`axel-lauer`
77+
78+
Diagnostics
79+
~~~~~~~~~~~
80+
81+
- Calculating Lamb weathertypes for CMIP5, CMIP6, SMILES and EURO-CORDEX (:pull:`4231`) by :user:`thomaskroi1996`
82+
- Add diagnostic to plot a histogram (:pull:`4329`) by :user:`LisaBock`
83+
- Add diagnostic to calculate hour of maximum precipitation (:pull:`4334`) by :user:`schlunma`
84+
- Make emergent constraints diagnostics compatible with Pandas>=3 (:pull:`4356`) by :user:`schlunma`
85+
- Allow specifying ``axes_kwargs`` in ``monitor/multi_datasets.py`` (:pull:`4365`) by :user:`schlunma`
86+
87+
Observational and re-analysis dataset support
88+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
89+
90+
- ESACCI SNOW CMORizer (:pull:`3542`) by :user:`axel-lauer`
91+
- Update CMORizer CERES-EBAF to v4.2 (:pull:`3360`) by :user:`axel-lauer`
92+
- Fix JRA-55 downloader (:pull:`4191`) by :user:`LisaBock`
93+
- EN4 cmorizer (:pull:`4193`) by :user:`hanellis`
94+
- New ESACCI AEROSOL CMORizer (Python version) (:pull:`3629`) by :user:`axel-lauer`
95+
- Extension of ESA CCI OZONE CMORizer (:pull:`4125`) by :user:`axel-lauer`
96+
97+
Release
98+
~~~~~~~
99+
100+
- Modernize release notes script (:pull:`4336`) by :user:`schlunma`
101+
102+
Automatic testing
103+
~~~~~~~~~~~~~~~~~
104+
105+
- Run Github Action install from conda with Python 3.13 also (:pull:`4229`) by :user:`valeriupredoi`
106+
- Fix WOA CMORizer tests (:pull:`4243`) by :user:`valeriupredoi`
107+
- Update recipe tests to align with ESMValCore development (:pull:`4268`) by :user:`bouweandela`
108+
- Fix tests for new esmvalcore config (:pull:`4252`) by :user:`valeriupredoi`
109+
- Clean up OSX Github Action tests (:pull:`4272`) by :user:`valeriupredoi`
110+
- Update recipe load test so it works with the latest ESMValCore (:pull:`4294`) by :user:`bouweandela`
111+
- Increase CirleCI container resource to medium+ (:pull:`4364`) by :user:`valeriupredoi`
112+
- Update batch job generation script with experiences from latest tests (:pull:`4378`) by :user:`schlunma`
113+
114+
Installation
115+
~~~~~~~~~~~~
116+
117+
- Use ``pip install --no-deps`` to avoid overwiting packages from the conda environment (:pull:`4182`) by :user:`bouweandela`
118+
- Drop support for Python 3.11 (:pull:`4273`) by :user:`bouweandela`
119+
- Pin iris <3.14.1 to comply with iris-esmf-regrid 0.13 (:pull:`4284`) by :user:`valeriupredoi`
120+
- Update package build and deploy (:pull:`4289`) by :user:`bouweandela`
121+
- Drop ``ruamel.yaml`` as a dependency (:pull:`4295`) by :user:`bouweandela`
122+
- Unpin iris (:pull:`4304`) by :user:`valeriupredoi`
123+
- Remove R development dependencies (:pull:`4306`) by :user:`valeriupredoi`
124+
- Update environment.yml with R dependency r-r.utils for recipe_martin18grl and recipe_spei (:pull:`4355`) by :user:`katjaweigel`
125+
- Pin numpy >=2 (:pull:`4375`) by :user:`valeriupredoi`
126+
127+
Improvements
128+
~~~~~~~~~~~~
129+
130+
- Switch from Prospector to ruff (:pull:`4209`) by :user:`bouweandela`
131+
- Fix Codacy configuration (:pull:`4262`) by :user:`bouweandela`
132+
- Apply automatic fixes for style issues (:pull:`4263`) by :user:`bouweandela`
133+
- Update obs4MIPs dataset names (:pull:`4321`, :pull:`4377`) by :user:`bouweandela` and :user:`valeriupredoi`
134+
- Add ``keep_group_coordinates: true`` to recipes that fail without it (:pull:`4352`) by :user:`schlunma`
135+
- Load configuration before accessing CMOR tables (:pull:`4363`) by :user:`bouweandela`
136+
- Avoid failing tests on coverage upload from forks (:pull:`4371`) by :user:`bouweandela`
137+
6138
.. _changelog-v2-13-0:
7139

8140
v2.13.0

esmvaltool/cmorizers/data/cmor_config/ESACCI-OZONE.yml

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,40 @@ attributes:
55
tier: 2
66
type: sat
77
project_id: OBS6
8-
source: "https://cds.climate.copernicus.eu/datasets/satellite-ozone-v1"
8+
source: "https://cds.climate.copernicus.eu/datasets/satellite-ozone-v1 and https://webdav.aeronomie.be/guest/o3_cci/webdata/Nadir_Profiles/L3/IASI_MG_FORLI/"
99
reference: "esacci-ozone"
1010
comment: ""
1111

1212
variables:
13-
toz:
13+
# Note: Do not change variable names, these are used to handle the different
14+
# datasets in the formatting script esacci_ozone.py.
15+
toz_gto_ecv:
16+
version: L3-GTO-ECV
1417
mip: AERmon
18+
output: toz
1519
raw: total_ozone_column
16-
filename: C3S-L3_OZONE-O3_PRODUCTS-MERGED_UV-MERGED-ALG-MONTHLY-v2000.nc #The filename needs also "YYYYMM-" as prefix added during the cmorization
17-
o3:
20+
filename: "{year}{month}-C3S-L3_OZONE-O3_PRODUCTS-MERGED_UV-MERGED-ALG-MONTHLY-v2000.nc"
21+
o3_sage_omps:
22+
version: L3-SAGE-OMPS
1823
mip: AERmon
24+
output: o3
1925
raw: merged_ozone_concentration
20-
filename: C3S-L3_OZONE-O3_PRODUCTS-CONC_MZM-MERGED-ALG-MONTHLY-v0008.nc #The filename needs also "YYYYMM-" as prefix added during the cmorization
26+
filename: "{year}{month}-C3S-L3_OZONE-O3_PRODUCTS-CONC_MZM-MERGED-ALG-MONTHLY-v0008.nc"
27+
o3_megridop:
28+
version: L3-MEGRIDOP
29+
mip: AERmon
30+
output: o3
31+
raw: merged_ozone_concentration
32+
filename: "{year}{month}-C3S-L3_OZONE-O3_PRODUCTS-CONC_LLG-MERGED-ALG-MONTHLY-v0004.nc"
33+
o3_iasi:
34+
version: L3-IASI
35+
mip: AERmon
36+
output: o3
37+
raw: O3_partial_column_profile
38+
filename: "IASI_FORLI_O3_MERGED_{year}{month}*_V1.0.nc"
39+
toz_iasi:
40+
version: L3-IASI
41+
mip: AERmon
42+
output: toz
43+
raw: O3_total_column
44+
filename: "IASI_FORLI_O3_MERGED_{year}{month}*_V1.0.nc"

esmvaltool/cmorizers/data/datasets.yml

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -573,34 +573,54 @@ datasets:
573573
ESACCI-OZONE:
574574
tier: 2
575575
source: https://cds.climate.copernicus.eu/datasets/satellite-ozone-v1
576-
last_access: 2025-02-11
576+
last_access: 2026-02-12
577577
info: |
578578
Download the data from:
579579
GTO-ECV total column (variable toz)
580580
Select the following from the CDS:
581581
https://cds.climate.copernicus.eu/datasets/satellite-ozone-v1?tab=download
582+
Put all files under a single directory (no subdirectories with years).
582583
583584
Processing Level = "Level 3"
584585
Variable = "Atm. mole content of ozone"
585-
Vertical aggregation = "Total column"
586-
Sensor = "MERGED-UV"
586+
Vertical aggregation = "Total columns UV"
587+
Sensor = "GTO-ECV"
587588
Year = select all (1995-2023)
588589
Month = select all (1-12)
589590
Version = "v2000"
590591
591592
SAGE-CCI-OMPS (variable o3)
592593
Select the following options from the same link:
593594
https://cds.climate.copernicus.eu/datasets/satellite-ozone-v1?tab=download
595+
Put all files under a single directory (no subdirectories with years).
594596
595597
Processing Level = "Level 3"
596598
Variable = "Mole concentration of ozone in air"
597-
Vertical aggregation = " Vertical profiles from limb sensors"
598-
Sensor = " CMZM (Monthly zonal mean merged concentration product from limb
599-
sensors ACE, GOMOS, MIPAS, OMPS, OSIRIS, SAGE-2 and SCIAMACHY)"
599+
Vertical aggregation = "Vertical profiles from limb sensors"
600+
Sensor = "SAGE-CCI-OMPS_CONC"
600601
Year = select all (1984-2022)
601602
Month = select all (1-12)
602603
Version = "v0008"
603-
Put all files under a single directory (no subdirectories with years).
604+
605+
MEGRIDOP (variable o3)
606+
Select the following options from the same link:
607+
https://cds.climate.copernicus.eu/datasets/satellite-ozone-v1?tab=download
608+
Put all files under a single directory (no subdirectories with years).
609+
610+
Processing Level = "Level 3"
611+
Variable = "Mole concentration of ozone in air"
612+
Vertical aggregation = "Vertical profiles from limb sensors"
613+
Sensor = "MEGRIDOP_CONC"
614+
Year = select all (2001-2022)
615+
Month = select all (1-12)
616+
Version = "v0004"
617+
618+
IASI (variables o3, toz)
619+
Download from BIRA WebDAV server: https://webdav.aeronomie.be
620+
Path: /guest/o3_cci/webdata/Nadir_Profiles/L3/IASI_MG_FORLI/<yyyy>
621+
Username: o3_cci_public
622+
No password (leave empty)
623+
Download each year <yyyy> into the same folder
604624
605625
ESACCI-SEAICE:
606626
tier: 2

esmvaltool/cmorizers/data/downloaders/datasets/esacci_ozone.py

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
"""Script to download ESACCI-OZONE from the CDS."""
1+
"""Script to download ESACCI-OZONE from the CDS and BIRA WebDAV."""
22

33
import gzip
44
import logging
55
import shutil
66
import zipfile
7+
from datetime import datetime
78

89
import cdsapi
10+
from dateutil import relativedelta
11+
12+
from esmvaltool.cmorizers.data.downloaders.wget import WGetDownloader
913

1014
logger = logging.getLogger(__name__)
1115

@@ -26,28 +30,61 @@ def download_dataset(
2630
the ECMWF account needs to be saved in user's ${HOME} directory.
2731
- All the files will be saved in Tier2/ESACCI-OZONE.
2832
"""
29-
cds_url = "https://cds.climate.copernicus.eu/api"
30-
3133
if dataset == "ESACCI-OZONE":
34+
output_folder = (
35+
original_data_dir / f"Tier{dataset_info['tier']}" / dataset
36+
)
37+
output_folder.mkdir(parents=True, exist_ok=True)
38+
39+
cds_url = "https://cds.climate.copernicus.eu/api"
40+
41+
if start_date is None:
42+
gto_year1 = 1995
43+
omps_year1 = 1984
44+
megridop_year1 = 2001
45+
else:
46+
gto_year1 = start_date.year
47+
omps_year1 = start_date.year
48+
megridop_year1 = start_date.year
49+
if end_date is None:
50+
gto_year2 = 2024
51+
omps_year2 = 2023
52+
megridop_year2 = 2023
53+
else:
54+
gto_year2 = end_date.year
55+
omps_year2 = end_date.year
56+
megridop_year2 = end_date.year
57+
3258
requests = {
33-
"toz": {
59+
"toz_gto_ecv": {
3460
"processing_level": "level_3",
3561
"variable": "atmosphere_mole_content_of_ozone",
36-
"vertical_aggregation": "total_column",
37-
"sensor": ["merged_uv"],
38-
"year": [str(y) for y in range(1995, 2024)],
62+
"vertical_aggregation": "total_columns_uv",
63+
"sensor": ["gto_ecv"],
64+
"year": [str(y) for y in range(gto_year1, gto_year2)],
3965
"month": [f"{m:02d}" for m in range(1, 13)],
4066
"version": ["v2000"],
4167
},
42-
"o3": {
68+
"o3_sage_omps": {
4369
"processing_level": "level_3",
4470
"variable": "mole_concentration_of_ozone_in_air",
4571
"vertical_aggregation": "vertical_profiles_from_limb_sensors",
46-
"sensor": ["cmzm"],
47-
"year": [str(y) for y in range(1984, 2023)],
72+
"sensor": ["sage_cci_omps_conc"],
73+
"year": [str(y) for y in range(omps_year1, omps_year2)],
4874
"month": [f"{m:02d}" for m in range(1, 13)],
4975
"version": ["v0008"],
5076
},
77+
"o3_sage_megridop": {
78+
"processing_level": "level_3",
79+
"variable": "mole_concentration_of_ozone_in_air",
80+
"vertical_aggregation": "vertical_profiles_from_limb_sensors",
81+
"sensor": ["megridop_conc"],
82+
"year": [
83+
str(y) for y in range(megridop_year1, megridop_year2)
84+
],
85+
"month": [f"{m:02d}" for m in range(1, 13)],
86+
"version": ["v0004"],
87+
},
5188
}
5289

5390
client = cdsapi.Client(cds_url)
@@ -88,5 +125,41 @@ def download_dataset(
88125
with open(output_folder / file_path.stem, "wb") as f_out:
89126
shutil.copyfileobj(f_in, f_out)
90127

128+
# download IASI data from BIRA WebDAV (IASI data not available on CDS)
129+
# all the files will be saved by in ${RAWOBS}/Tier2/ESACCI-OZONE
130+
131+
if start_date is None:
132+
start_date = datetime(2008, 1, 1)
133+
if end_date is None:
134+
end_date = datetime(2023, 12, 31)
135+
136+
downloader = WGetDownloader(
137+
original_data_dir=original_data_dir,
138+
dataset=dataset,
139+
dataset_info=dataset_info,
140+
overwrite=overwrite,
141+
)
142+
143+
basepath = "https://webdav.aeronomie.be/guest/o3_cci/webdata/Nadir_Profiles/L3/IASI_MG_FORLI"
144+
145+
wget_options = [
146+
"-e robots=off", # ignore robots.txt
147+
"--no-parent", # don't ascend to the parent directory
148+
"--accept=nc", # download only *.nc files
149+
"--user=o3_cci_public", # user name
150+
"--password=", # empty password (no password needed for public access)
151+
]
152+
153+
loop_date = start_date
154+
while loop_date <= end_date:
155+
year = loop_date.year
156+
157+
# directory on server to download
158+
remotepath = f"{basepath}/{year}"
159+
downloader.download_folder(remotepath, wget_options)
160+
161+
loop_date += relativedelta.relativedelta(years=1)
162+
91163
else:
92-
raise ValueError(f"Unknown dataset: {dataset}")
164+
errmsg = f"Unknown dataset: {dataset}"
165+
raise ValueError(errmsg)

0 commit comments

Comments
 (0)