Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a96e132
Add CORDEX domain target grids for regridding
ghossh Jun 1, 2026
8e401c2
Add unit tests for CORDEX domain target grids in regridding
ghossh Jun 4, 2026
ef94822
Refactor _cordex_stock_cube function to utilize xarray for grid creat…
ghossh Jun 8, 2026
502047a
Merge branch 'main' into target-grid-cordex-domain
ghossh Jun 8, 2026
0bd0814
Update docstring in global_cube fixture for clarity in target-grid co…
ghossh Jun 8, 2026
1b6e678
Add documentation for regridding on CORDEX domain grids
ghossh Jun 8, 2026
d5db352
Merge branch 'main' into target-grid-cordex-domain
ghossh Jun 12, 2026
2e6e8d9
Merge branch 'main' into target-grid-cordex-domain
bouweandela Jun 24, 2026
cdc90f1
More cordex fixes
bouweandela Jun 26, 2026
26a9784
Merge branch 'main' of github.com:ESMValGroup/ESMValCore into target-…
bouweandela Jun 29, 2026
5bd5bb9
Merge branch 'target-grid-cordex-domain' of github.com:esmvalgroup/es…
bouweandela Jun 29, 2026
083c723
Merge branch 'main' into target-grid-cordex-domain
bouweandela Jun 29, 2026
b57e930
Fix sftlf long name of HadREM3-GA7-05
bouweandela Jun 29, 2026
369c96c
Always apply standard long_name for HadREM3-GA7-05
bouweandela Jul 1, 2026
c3328b3
Merge branch 'target-grid-cordex-domain' into more-cordex-fixes
bouweandela Jul 1, 2026
1711bb8
Add more facets to alias
bouweandela Jul 1, 2026
4773c70
Avoid variable related facets
bouweandela Jul 1, 2026
5b22c7a
Also correct standard name
bouweandela Jul 1, 2026
683767c
Add fewer facets
bouweandela Jul 2, 2026
f469e53
More updates to facets used for alias and grouping
bouweandela Jul 2, 2026
84742a1
Update tests
bouweandela Jul 2, 2026
0704d4e
Add more tests
bouweandela Jul 2, 2026
c04b300
Merge branch 'main' of github.com:ESMValGroup/ESMValCore into more-co…
bouweandela Jul 2, 2026
78ec4d5
Fix merge error
bouweandela Jul 2, 2026
b124633
Simplify
bouweandela Jul 2, 2026
082a121
Enable standard grid for WRF381P
bouweandela Jul 3, 2026
160fc43
Revert "Enable standard grid for WRF381P"
bouweandela Jul 3, 2026
3e2d698
Replace grid of WRF381P with driver MPI-M-MPI-ESM-LR with the standar…
bouweandela Jul 3, 2026
6c43905
Add test and correct units of cordex standard grid
bouweandela Jul 3, 2026
a0c9c36
Correct clivi units
bouweandela Jul 3, 2026
c5c2209
Add fixes for sic and prw
bouweandela Jul 3, 2026
efd9ef6
Merge branch 'main' into more-cordex-fixes
bouweandela Jul 11, 2026
30d2517
Undo fixes which are not a clear improvement
bouweandela Jul 13, 2026
87eb685
Also undo HadREM3-GA7-05 clivi fixes as no clear improvement
bouweandela Jul 13, 2026
2eef79e
Merge branch 'main' into more-cordex-fixes
bouweandela Jul 14, 2026
f2b4988
Add tests
bouweandela Jul 14, 2026
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
9 changes: 5 additions & 4 deletions esmvalcore/_recipe/to_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@

_ALIAS_INFO_KEYS: tuple[str, ...] = (
"project",
"activity",
"driver",
"dataset",
"exp",
"sub_experiment",
"dataset",
"rcm_version",
"driver",
"ensemble",
"sub_experiment",
"grid",
"version",
)
"""List of keys to be used to compose the alias, ordered by priority."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from esmvalcore.cmor.fix import Fix

if TYPE_CHECKING:
from collections.abc import Sequence

from iris.cube import Cube


class Snw(Fix):
"""Fixes for snw."""

def fix_metadata(self, cubes: Sequence[Cube]) -> Sequence[Cube]:
cube = self.get_cube_from_list(cubes)
cube = cube.copy()
cube.remove_coord("height")
return [cube]
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
"""Fixes for rcm HadREM3-GA7-05 driven by CNRM-CERFACS-CNRM-CM5."""

from __future__ import annotations

from typing import TYPE_CHECKING

import iris
import iris.cube

from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
MOHCHadREM3GA705 as BaseFix,
)
from esmvalcore.cmor.fix import Fix

if TYPE_CHECKING:
from collections.abc import Sequence

AllVars = BaseFix


Tas = BaseFix
class Sic(Fix):
"""Fixes for variable sic."""

Pr = BaseFix
def fix_metadata(
self,
cubes: Sequence[iris.cube.Cube],
) -> Sequence[iris.cube.Cube]:
cube = self.get_cube_from_list(iris.cube.CubeList(cubes)).copy()
cube.units = 1
cube.convert_units("%")
return [cube]
3 changes: 3 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/cordex_fixes.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ def fix_metadata(self, cubes):
iris.cube.CubeList
"""
for cube in cubes:
if self.vardef.standard_name:
cube.standard_name = self.vardef.standard_name
cube.long_name = self.vardef.long_name
cube.coord("latitude").var_name = "lat"
cube.coord("longitude").var_name = "lon"
for coord in cube.coords("time"):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5.cosmo_crclim_v1_1 import (
Snw as BaseSnw,
)


class Snw(BaseSnw):
"""Fixes for snw."""
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@
MOHCHadREM3GA705 as BaseFix,
)

Tas = BaseFix

Pr = BaseFix
AllVars = BaseFix
37 changes: 37 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/mohc_hadgem2_es/cclm4_8_17.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
"""Fixes for rcm CCLM4-8-17 driven by MOHC-HadGEM2-ES."""

from __future__ import annotations

from typing import TYPE_CHECKING

import iris
import iris.cube

from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
CLMcomCCLM4817 as BaseFix,
)
from esmvalcore.cmor.fix import Fix

if TYPE_CHECKING:
from collections.abc import Sequence

AllVars = BaseFix


class Clivi(Fix):
"""Fixes for variable clivi."""

def fix_metadata(
self,
cubes: Sequence[iris.cube.Cube],
) -> Sequence[iris.cube.Cube]:
cube = self.get_cube_from_list(iris.cube.CubeList(cubes)).copy()
cube.units = "Mg m-2"
cube.convert_units("kg m-2")
return [cube]


class Prw(Fix):
"""Fixes for variable prw."""

def fix_metadata(
self,
cubes: Sequence[iris.cube.Cube],
) -> Sequence[iris.cube.Cube]:
cube = self.get_cube_from_list(iris.cube.CubeList(cubes)).copy()
cube.units = "Mg m-2"
cube.convert_units("kg m-2")
return [cube]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5.cosmo_crclim_v1_1 import (
Snw as BaseSnw,
)


class Snw(BaseSnw):
"""Fixes for snw."""
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
"""Fixes for rcm HadREM3-GA7-05 driven by MOHC-HadGEM2-ES."""

from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5.hadrem3_ga7_05 import (
Sic as BaseSic,
)
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
MOHCHadREM3GA705 as BaseFix,
)

Tas = BaseFix
AllVars = BaseFix


Pr = BaseFix
class Sic(BaseSic):
"""Fixes for variable sic."""
2 changes: 1 addition & 1 deletion esmvalcore/cmor/_fixes/cordex/mohc_hadgem2_es/hirham5.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Fixes for rcm HIRHAM driven by MOHC-HadGEM2."""
"""Fixes for rcm HIRHAM5 driven by MOHC-HadGEM2."""

from esmvalcore.cmor.fix import Fix

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5.cosmo_crclim_v1_1 import (
Snw as BaseSnw,
)


class Snw(BaseSnw):
"""Fixes for snw."""
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
"""Fixes for rcm HadREM3-GA7-05 driven by MPI-M-MPI-ESM-LR."""

from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5.hadrem3_ga7_05 import (
Sic as BaseSic,
)
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
MOHCHadREM3GA705 as BaseFix,
)

Tas = BaseFix
AllVars = BaseFix


Pr = BaseFix
class Sic(BaseSic):
"""Fixes for variable sic."""
41 changes: 41 additions & 0 deletions esmvalcore/cmor/_fixes/cordex/mpi_m_mpi_esm_lr/wrf381p.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Fixes for rcm WRF381P driven by MPI-M-MPI-ESM-LR."""

from esmvalcore.cmor.fix import Fix
from esmvalcore.preprocessor._regrid import _cordex_stock_cube


class AllVars(Fix):
"""Fixes for all vars."""

def fix_metadata(self, cubes):
cube = self.get_cube_from_list(cubes).copy()
if cube.coords("projection_x_coordinate"):
# WRF381P datasets with the MPI-M-MPI-ESM-LR driver have bad
# projection coordinates containing all zeros, but the latitude
# and longitude points match those of the standard grid. Therefore
# we replace the bad coordinates with the standard rotated pole
# coordinates.
# https://github.com/ESMValGroup/ESMValCore/issues/3145
standard_grid = _cordex_stock_cube(self.extra_facets["domain"])
x_dim = cube.coord_dims("projection_x_coordinate")
y_dim = cube.coord_dims("projection_y_coordinate")

# Remove the bad coordinates.
cube.remove_coord("projection_x_coordinate")
cube.remove_coord("projection_y_coordinate")
cube.remove_coord("longitude")
cube.remove_coord("latitude")

# Add the standard rotated pole coordinates.
cube.add_dim_coord(
standard_grid.coord("grid_longitude"),
x_dim,
)
cube.add_dim_coord(
standard_grid.coord("grid_latitude"),
y_dim,
)
cube.add_aux_coord(standard_grid.coord("longitude"), y_dim + x_dim)
cube.add_aux_coord(standard_grid.coord("latitude"), y_dim + x_dim)

return [cube]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5.cosmo_crclim_v1_1 import (
Snw as BaseSnw,
)


class Snw(BaseSnw):
"""Fixes for snw."""
9 changes: 7 additions & 2 deletions esmvalcore/cmor/_fixes/cordex/ncc_noresm1_m/hadrem3_ga7_05.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
"""Fixes for rcm HadREM3-GA7-05 driven by NCC-NorESM1-M."""

from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5.hadrem3_ga7_05 import (
Sic as BaseSic,
)
from esmvalcore.cmor._fixes.cordex.cordex_fixes import (
MOHCHadREM3GA705 as BaseFix,
)

Tas = BaseFix
AllVars = BaseFix


Pr = BaseFix
class Sic(BaseSic):
"""Fixes for variable sic."""
12 changes: 12 additions & 0 deletions esmvalcore/config/configurations/defaults/extra_facets_cordex.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,19 @@ projects:
'*':
'*':
use_standard_grid: true
COSMO-crCLIM-v1-1:
'*':
'*':
use_standard_grid: true # lat/lon coords missing bounds
HIRHAM5:
'*':
'*':
use_standard_grid: true
RACMO22E:
'*':
'*':
use_standard_grid: true # lat/lon coords missing bounds
RCA4:
'*':
'*':
use_standard_grid: true # lat/lon coords missing bounds
10 changes: 9 additions & 1 deletion esmvalcore/preprocessor/_multimodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,15 @@ def ensemble_statistics(
:func:`esmvalcore.preprocessor.multi_model_statistics` for
the full description of the core statistics function.
"""
ensemble_grouping = ("project", "dataset", "exp", "sub_experiment")
ensemble_grouping = (
"project",
"exp",
"dataset",
"rcm_version",
"driver",
"grid",
"sub_experiment",
)
return multi_model_statistics(
products=products,
span=span,
Expand Down
3 changes: 3 additions & 0 deletions esmvalcore/preprocessor/_regrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ def _cordex_stock_cube(domain_name: str) -> Cube:
(cube,) = ncdata.iris_xarray.cubes_from_xarray(domain)
cube.coord("grid_latitude").guess_bounds()
cube.coord("grid_longitude").guess_bounds()
# Restore the units that iris changed to degrees.
cube.coord("latitude").units = domain.lat.attrs["units"]
cube.coord("longitude").units = domain.lon.attrs["units"]

return cube

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from esmvalcore.cmor._fixes.cordex.cnrm_cerfacs_cnrm_cm5 import (
aladin53,
aladin63,
hadrem3_ga7_05,
wrf381p,
)
from esmvalcore.cmor._fixes.cordex.cordex_fixes import CLMcomCCLM4817
Expand Down Expand Up @@ -54,6 +55,28 @@ def test_get_hadrem3ga705_fix(short_name):
assert isinstance(fix[0], Fix)


def test_hadrem3_ga7_05_sic() -> None:
fixes = Fix.get_fixes(
"CORDEX",
"HadREM3-GA7-05",
"day",
"sic",
extra_facets={"driver": "CNRM-CERFACS-CNRM-CM5"},
)
assert any(isinstance(fix, hadrem3_ga7_05.Sic) for fix in fixes)

cube = iris.cube.Cube(
np.array([0.5], dtype=np.float32),
var_name="sic",
standard_name="sea_ice_area_fraction",
units="%",
)
fix = next(fix for fix in fixes if isinstance(fix, hadrem3_ga7_05.Sic))
result = fix.fix_metadata([cube])
assert result[0].units == "%"
np.testing.assert_allclose(result[0].data, [50.0])


def test_fix_aladin53_sftlf() -> None:
fixes = Fix.get_fixes(
"CORDEX",
Expand Down Expand Up @@ -193,7 +216,7 @@ def test_wrf381p_height_fix():
var_name="tas",
dim_coords_and_dims=[(time_coord, 0)],
)
vardef = get_var_info("CMIP6", "Amon", "tas")
vardef = get_var_info("CORDEX", "day", "tas")
fix = wrf381p.Tas(vardef)
out_cubes = fix.fix_metadata([cube])
assert out_cubes[0].coord("height").points == 2.0
Expand All @@ -208,3 +231,33 @@ def test_get_cclm4_8_17fix() -> None:
extra_facets={"driver": "CNRM-CERFACS-CNRM-CM5"},
)
assert any(isinstance(fix, CLMcomCCLM4817) for fix in fixes)


def test_cosmo_crclim_v1_1_snw_drop_height_coord():
height_coord = iris.coords.AuxCoord(
[2.0],
var_name="height",
standard_name="height",
long_name="height",
)
cube = iris.cube.Cube(
[10.0],
var_name="snw",
aux_coords_and_dims=[(height_coord, 0)],
)
fixes = Fix.get_fixes(
"CORDEX",
"COSMO-crCLIM-v1-1",
"day",
"snw",
extra_facets={
"driver": "CNRM-CERFACS-CNRM-CM5",
"domain": "EUR-11",
},
)
cubes = [cube]
for fix in fixes:
cubes = fix.fix_metadata(cubes)
assert len(cubes) == 1
assert cubes[0].var_name == "snw"
assert not cubes[0].coords("height")
Loading