From aed1f33db3444d8cfc8b6d8b7ff38c69387ba221 Mon Sep 17 00:00:00 2001 From: Manuel Schlund Date: Mon, 1 Mar 2021 17:27:49 +0100 Subject: [PATCH] Fixed hybrid sigma pressure coordinate of CESM2 models --- esmvalcore/cmor/_fixes/cmip6/cesm2.py | 55 +++++++++++-------- .../cmor/_fixes/cmip6/test_cesm2.py | 49 ++++++++--------- .../cmor/_fixes/cmip6/test_cesm2_waccm.py | 6 ++ 3 files changed, 61 insertions(+), 49 deletions(-) diff --git a/esmvalcore/cmor/_fixes/cmip6/cesm2.py b/esmvalcore/cmor/_fixes/cmip6/cesm2.py index c7cef0d419..9b4bc499f4 100644 --- a/esmvalcore/cmor/_fixes/cmip6/cesm2.py +++ b/esmvalcore/cmor/_fixes/cmip6/cesm2.py @@ -1,12 +1,16 @@ """Fixes for CESM2 model.""" from shutil import copyfile -from netCDF4 import Dataset import numpy as np +from netCDF4 import Dataset from ..fix import Fix -from ..shared import (add_scalar_depth_coord, add_scalar_height_coord, - add_scalar_typeland_coord, add_scalar_typesea_coord) +from ..shared import ( + add_scalar_depth_coord, + add_scalar_height_coord, + add_scalar_typeland_coord, + add_scalar_typesea_coord, +) from .gfdl_esm4 import Siconc as Addtypesi @@ -24,27 +28,6 @@ def _fix_formula_terms(self, filepath, output_dir): dataset.close() return new_path - def fix_data(self, cube): - """Fix data. - - Fixed ordering of vertical coordinate. - - Parameters - ---------- - cube: iris.cube.Cube - Input cube to fix. - - Returns - ------- - iris.cube.Cube - - """ - (z_axis,) = cube.coord_dims(cube.coord(axis='Z', dim_coords=True)) - indices = [slice(None)] * cube.ndim - indices[z_axis] = slice(None, None, -1) - cube = cube[tuple(indices)] - return cube - def fix_file(self, filepath, output_dir): """Fix hybrid pressure coordinate. @@ -77,6 +60,30 @@ def fix_file(self, filepath, output_dir): dataset.close() return new_path + def fix_metadata(self, cubes): + """Fix ``atmosphere_hybrid_sigma_pressure_coordinate``. + + See discussion in #882 for more details on that. + + Parameters + ---------- + cubes : iris.cube.CubeList + Input cubes. + + Returns + ------- + iris.cube.CubeList + + """ + cube = self.get_cube_from_list(cubes) + lev_coord = cube.coord(var_name='lev') + a_coord = cube.coord(var_name='a') + b_coord = cube.coord(var_name='b') + lev_coord.points = a_coord.core_points() + b_coord.core_points() + lev_coord.bounds = a_coord.core_bounds() + b_coord.core_bounds() + lev_coord.units = '1' + return cubes + Cli = Cl diff --git a/tests/integration/cmor/_fixes/cmip6/test_cesm2.py b/tests/integration/cmor/_fixes/cmip6/test_cesm2.py index 058086c2cb..7ec96ffb5e 100644 --- a/tests/integration/cmor/_fixes/cmip6/test_cesm2.py +++ b/tests/integration/cmor/_fixes/cmip6/test_cesm2.py @@ -97,15 +97,21 @@ def test_cl_fix_file(mock_get_filepath, tmp_path, test_data_path): @pytest.fixture -def cl_cube(): +def cl_cubes(): """``cl`` cube.""" time_coord = iris.coords.DimCoord( [0.0, 1.0], var_name='time', standard_name='time', units='days since 1850-01-01 00:00:00') + a_coord = iris.coords.AuxCoord( + [0.1, 0.2, 0.1], bounds=[[0.0, 0.15], [0.15, 0.25], [0.25, 0.0]], + var_name='a', units='1') + b_coord = iris.coords.AuxCoord( + [0.9, 0.3, 0.1], bounds=[[1.0, 0.8], [0.8, 0.25], [0.25, 0.0]], + var_name='b', units='1') lev_coord = iris.coords.DimCoord( - [0.0, 1.0, 2.0], var_name='lev', - standard_name='atmosphere_hybrid_sigma_pressure_coordinate', units='1', - attributes={'positive': 'up'}) + [999.0, 99.0, 9.0], var_name='lev', + standard_name='atmosphere_hybrid_sigma_pressure_coordinate', + units='hPa', attributes={'positive': 'up'}) lat_coord = iris.coords.DimCoord( [0.0, 1.0], var_name='lat', standard_name='latitude', units='degrees') lon_coord = iris.coords.DimCoord( @@ -122,30 +128,23 @@ def cl_cube(): standard_name='cloud_area_fraction_in_atmosphere_layer', units='%', dim_coords_and_dims=coord_specs, + aux_coords_and_dims=[(a_coord, 1), (b_coord, 1)], ) - return cube + return iris.cube.CubeList([cube]) -def test_cl_fix_data(cl_cube): - """Test ``fix_data`` for ``cl``.""" - fix = Cl(None) - out_cube = fix.fix_data(cl_cube) - assert out_cube.shape == cl_cube.shape - np.testing.assert_allclose(out_cube.data, - [[[[8, 9], - [10, 11]], - [[4, 5], - [6, 7]], - [[0, 1], - [2, 3]]], - [[[20, 21], - [22, 23]], - [[16, 17], - [18, 19]], - [[12, 13], - [14, 15]]]]) - np.testing.assert_allclose(out_cube.coord(var_name='lev').points, - [2.0, 1.0, 0.0]) +def test_cl_fix_metadata(cl_cubes): + """Test ``fix_metadata`` for ``cl``.""" + vardef = get_var_info('CMIP6', 'Amon', 'cl') + fix = Cl(vardef) + out_cubes = fix.fix_metadata(cl_cubes) + out_cube = out_cubes.extract_cube( + 'cloud_area_fraction_in_atmosphere_layer') + lev_coord = out_cube.coord(var_name='lev') + assert lev_coord.units == '1' + np.testing.assert_allclose(lev_coord.points, [1.0, 0.5, 0.2]) + np.testing.assert_allclose(lev_coord.bounds, + [[1.0, 0.95], [0.95, 0.5], [0.5, 0.0]]) def test_get_cli_fix(): diff --git a/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm.py b/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm.py index 341b4f8612..6c9743701f 100644 --- a/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm.py +++ b/tests/integration/cmor/_fixes/cmip6/test_cesm2_waccm.py @@ -7,6 +7,7 @@ import numpy as np import pytest +from esmvalcore.cmor._fixes.cmip6.cesm2 import Cl as BaseCl from esmvalcore.cmor._fixes.cmip6.cesm2 import Tas as BaseTas from esmvalcore.cmor._fixes.cmip6.cesm2_waccm import Cl, Cli, Clw, Tas from esmvalcore.cmor.fix import Fix @@ -18,6 +19,11 @@ def test_get_cl_fix(): assert fix == [Cl(None)] +def test_cl_fix(): + """Test fix for ``cl``.""" + assert issubclass(Cl, BaseCl) + + @pytest.mark.skipif(sys.version_info < (3, 7, 6), reason="requires python3.7.6 or newer") @unittest.mock.patch(