diff --git a/esmvalcore/cmor/_fixes/obs4mips/airs_2_0.py b/esmvalcore/cmor/_fixes/obs4mips/airs_2_0.py new file mode 100644 index 0000000000..b8eab7b711 --- /dev/null +++ b/esmvalcore/cmor/_fixes/obs4mips/airs_2_0.py @@ -0,0 +1,35 @@ +"""Fixes for obs4MIPs dataset AIRS-2-0.""" +import dask.array as da + +from ..fix import Fix + + +class Hur(Fix): + """Fixes for hur.""" + + def fix_metadata(self, cubes): + """Fix metadata. + + Convert units from `1` to `%` and remove `valid_range` attribute. + + Parameters + ---------- + cubes: iris.cube.CubeList + Input cubes. + + Returns + ------- + iris.cube.CubeList + Fixed cubes. + + """ + for cube in cubes: + # Put information from valid_range into mask and remove the + # attribute (otherwise this will cause problems after reloading the + # data with different units) + valid_range = cube.attributes['valid_range'] + cube.data = da.ma.masked_outside(cube.core_data(), *valid_range) + cube.attributes.pop('valid_range', None) + + cube.convert_units('%') + return cubes diff --git a/tests/integration/cmor/_fixes/obs4mips/test_airs_2_0.py b/tests/integration/cmor/_fixes/obs4mips/test_airs_2_0.py new file mode 100644 index 0000000000..9ba4603f8c --- /dev/null +++ b/tests/integration/cmor/_fixes/obs4mips/test_airs_2_0.py @@ -0,0 +1,31 @@ +"""Test AIRS-2-0 fixes.""" +import dask.array as da +import numpy as np +from iris.cube import Cube, CubeList + +from esmvalcore.cmor.fix import fix_metadata + + +def test_fix_metadata_hur(): + """Test ``fix_metadata`` for hur.""" + cubes = CubeList([ + Cube( + da.from_array([-0.1, 0.2, 1.2, 1.7]), + var_name='hur', + units='1', + attributes={'valid_range': [0.0, 1.5]}, + ), + ]) + + fixed_cubes = fix_metadata( + cubes, 'hur', 'obs4MIPs', 'AIRS-2-0', 'Amon', check_level=5, + ) + + assert len(fixed_cubes) == 1 + fixed_cube = fixed_cubes[0] + assert fixed_cube.units == '%' + assert fixed_cube.attributes == {} + assert fixed_cube.has_lazy_data() + expected_data = np.ma.masked_invalid([np.nan, 20.0, 120.0, np.nan]) + np.testing.assert_allclose(fixed_cube.data.mask, expected_data.mask) + np.testing.assert_allclose(fixed_cube.data, expected_data)