diff --git a/esmvalcore/cmor/_fixes/cmip5/mri_esm1.py b/esmvalcore/cmor/_fixes/cmip5/mri_esm1.py index 270dd3c252..45a502b479 100644 --- a/esmvalcore/cmor/_fixes/cmip5/mri_esm1.py +++ b/esmvalcore/cmor/_fixes/cmip5/mri_esm1.py @@ -1,8 +1,50 @@ """Fixes for MRI-ESM1 model.""" +from typing import Sequence + +import iris.coords +import iris.cube +import iris.exceptions +import numpy as np from dask import array as da -from ..fix import Fix +from esmvalcore.cmor._fixes.fix import Fix + + +class AllVars(Fix): + def fix_metadata( + self, cubes: Sequence[iris.cube.Cube] + ) -> Sequence[iris.cube.Cube]: + """Replace rlat and rlon by index coordinates.""" + # In file fgco2_Omon_MRI-ESM1_historical_r1i1p1_185101-200512.nc + # (v20130307) the usual horizontal index coordinates appear to have + # been replaced by rotated pole coordinates. + # + # This leads to iris-esmf-regrid selecting the wrong coordinate when + # regridding. + for cube in cubes: + for coord_name, index_var_name, index_long_name in [ + ("latitude", "i", "cell index along first dimension"), + ("longitude", "j", "cell index along second dimension"), + ]: + try: + rotated_coord = cube.coord(f"grid_{coord_name}") + horizontal_coord = cube.coord(coord_name) + except iris.exceptions.CoordinateNotFoundError: + pass + else: + if len(horizontal_coord.shape) == 2: + (dim,) = cube.coord_dims(rotated_coord) + (size,) = rotated_coord.shape + cube.remove_coord(rotated_coord) + index_coord = iris.coords.DimCoord( + points=np.arange(1, size + 1), + var_name=index_var_name, + long_name=index_long_name, + units="1", + ) + cube.add_dim_coord(index_coord, dim) + return cubes class Msftmyz(Fix): diff --git a/tests/integration/cmor/_fixes/cmip5/test_mri_esm1.py b/tests/integration/cmor/_fixes/cmip5/test_mri_esm1.py index 16969fc6d8..e68e20d93e 100644 --- a/tests/integration/cmor/_fixes/cmip5/test_mri_esm1.py +++ b/tests/integration/cmor/_fixes/cmip5/test_mri_esm1.py @@ -1,18 +1,51 @@ """Test MRI-ESM1 fixes.""" -import unittest +import iris.coords +import iris.cube +import numpy as np +import pytest -from esmvalcore.cmor._fixes.cmip5.mri_esm1 import Msftmyz -from esmvalcore.cmor._fixes.fix import GenericFix +from esmvalcore.cmor._fixes.cmip5.mri_esm1 import AllVars, Msftmyz from esmvalcore.cmor.fix import Fix -class TestMsftmyz(unittest.TestCase): - """Test msftmyz fixes.""" +def test_get_allvars_fix(): + assert AllVars(None) in Fix.get_fixes("CMIP5", "MRI-ESM1", "Amon", "fgco2") - def test_get(self): - """Test fix get.""" - self.assertListEqual( - Fix.get_fixes("CMIP5", "MRI-ESM1", "Amon", "msftmyz"), - [Msftmyz(None), GenericFix(None)], + +@pytest.mark.parametrize("has_rotated_coord", [True, False]) +def test_grid_fix(has_rotated_coord): + """Test fix for using rotated pole grid coords instead of index coords.""" + cube = iris.cube.Cube(np.arange(4).reshape((2, 2))) + if has_rotated_coord: + r_coord = iris.coords.DimCoord( + np.arange(2).astype(np.float64), + var_name="rlat", + standard_name="grid_latitude", + long_name="latitude in rotated pole grid", + units="degrees", + ) + cube.add_dim_coord(r_coord, 0) + h_coord = iris.coords.AuxCoord( + np.arange(4).astype(np.float64).reshape((2, 2)), + var_name="lat", + standard_name="latitude", + units="degrees", ) + cube.add_aux_coord(h_coord, (0, 1)) + + cubes = [cube] + for fix in Fix.get_fixes("CMIP5", "MRI-ESM1", "Omon", "fgco2"): + cubes = fix.fix_metadata(cubes) + + assert len(cubes) == 1 + if has_rotated_coord: + assert not cube.coords("grid_latitude") + assert cube.coords(var_name="i") + assert cube.coords("latitude") + + +def test_get_msftmyz_fix(): + assert Msftmyz(None) in Fix.get_fixes( + "CMIP5", "MRI-ESM1", "Amon", "msftmyz" + )