diff --git a/esmvalcore/preprocessor/_io.py b/esmvalcore/preprocessor/_io.py index 86460328a6..2c3bd761f0 100644 --- a/esmvalcore/preprocessor/_io.py +++ b/esmvalcore/preprocessor/_io.py @@ -36,55 +36,6 @@ } -def _fix_aux_factories(cube): - """Fix :class:`iris.aux_factory.AuxCoordFactory` after concatenation. - - Necessary because of bug in :mod:`iris` (see issue #2478). - """ - coord_names = [coord.name() for coord in cube.coords()] - - # Hybrid sigma pressure coordinate - # TODO possibly add support for other hybrid coordinates - if 'atmosphere_hybrid_sigma_pressure_coordinate' in coord_names: - new_aux_factory = iris.aux_factory.HybridPressureFactory( - delta=cube.coord(var_name='ap'), - sigma=cube.coord(var_name='b'), - surface_air_pressure=cube.coord(var_name='ps'), - ) - for aux_factory in cube.aux_factories: - if isinstance(aux_factory, iris.aux_factory.HybridPressureFactory): - break - else: - cube.add_aux_factory(new_aux_factory) - - # Hybrid sigma height coordinate - if 'atmosphere_hybrid_height_coordinate' in coord_names: - new_aux_factory = iris.aux_factory.HybridHeightFactory( - delta=cube.coord(var_name='lev'), - sigma=cube.coord(var_name='b'), - orography=cube.coord(var_name='orog'), - ) - for aux_factory in cube.aux_factories: - if isinstance(aux_factory, iris.aux_factory.HybridHeightFactory): - break - else: - cube.add_aux_factory(new_aux_factory) - - # Atmosphere sigma coordinate - if 'atmosphere_sigma_coordinate' in coord_names: - new_aux_factory = iris.aux_factory.AtmosphereSigmaFactory( - pressure_at_top=cube.coord(var_name='ptop'), - sigma=cube.coord(var_name='lev'), - surface_air_pressure=cube.coord(var_name='ps'), - ) - for aux_factory in cube.aux_factories: - if isinstance(aux_factory, - iris.aux_factory.AtmosphereSigmaFactory): - break - else: - cube.add_aux_factory(new_aux_factory) - - def _get_attr_from_field_coord(ncfield, coord_name, attr): if coord_name is not None: attrs = ncfield.cf_group[coord_name].cf_attrs() @@ -389,8 +340,6 @@ def concatenate(cubes, check_level=CheckLevels.DEFAULT): else: _get_concatenation_error(result) - _fix_aux_factories(result) - return result diff --git a/tests/integration/preprocessor/_io/test_concatenate.py b/tests/integration/preprocessor/_io/test_concatenate.py index 3171c27a25..d8d5d680c1 100644 --- a/tests/integration/preprocessor/_io/test_concatenate.py +++ b/tests/integration/preprocessor/_io/test_concatenate.py @@ -1,17 +1,11 @@ """Integration tests for :func:`esmvalcore.preprocessor._io.concatenate`.""" import unittest -import warnings -from unittest.mock import call import numpy as np import pytest from cf_units import Unit -from iris.aux_factory import ( - AtmosphereSigmaFactory, - HybridHeightFactory, - HybridPressureFactory, -) +from iris.aux_factory import HybridPressureFactory from iris.coords import AuxCoord, DimCoord from iris.cube import Cube, CubeList @@ -64,98 +58,6 @@ def get_time_coord(time_point): units='days since 6453-2-1') -@pytest.fixture -def mock_empty_cube(): - """Return mocked cube with irrelevant coordinates.""" - cube = unittest.mock.create_autospec(Cube, spec_set=True, instance=True) - a_coord = AuxCoord(0.0, var_name='a') - b_coord = AuxCoord(0.0, var_name='b') - cube.coords.return_value = [a_coord, b_coord] - return cube - - -@pytest.fixture -def mock_atmosphere_sigma_cube(): - """Return mocked cube with atmosphere sigma coordinate.""" - cube = unittest.mock.create_autospec(Cube, spec_set=True, instance=True) - ptop_coord = AuxCoord([1.0], var_name='ptop', units='Pa') - lev_coord = AuxCoord([0.0], - bounds=[[-0.5, 1.5]], - var_name='lev', - units='1') - ps_coord = AuxCoord([[[100000]]], var_name='ps', units='Pa') - cube.coord.side_effect = [ - ptop_coord, lev_coord, ps_coord, ptop_coord, lev_coord, ps_coord - ] - cube.coords.return_value = [ - ptop_coord, - lev_coord, - ps_coord, - AuxCoord(0.0, standard_name='atmosphere_sigma_coordinate'), - ] - aux_factory = AtmosphereSigmaFactory( - pressure_at_top=ptop_coord, - sigma=lev_coord, - surface_air_pressure=ps_coord, - ) - cube.aux_factories = ['dummy', aux_factory] - return cube - - -@pytest.fixture -def mock_hybrid_height_cube(): - """Return mocked cube with hybrid height coordinate.""" - cube = unittest.mock.create_autospec(Cube, spec_set=True, instance=True) - lev_coord = AuxCoord([1.0], bounds=[[0.0, 2.0]], var_name='lev', units='m') - b_coord = AuxCoord([0.0], bounds=[[-0.5, 1.5]], var_name='b') - orog_coord = AuxCoord([[[100000]]], var_name='orog', units='m') - cube.coord.side_effect = [ - lev_coord, b_coord, orog_coord, lev_coord, b_coord, orog_coord - ] - cube.coords.return_value = [ - lev_coord, - b_coord, - orog_coord, - AuxCoord(0.0, standard_name='atmosphere_hybrid_height_coordinate'), - ] - aux_factory = HybridHeightFactory( - delta=lev_coord, - sigma=b_coord, - orography=orog_coord, - ) - cube.aux_factories = ['dummy', aux_factory] - return cube - - -@pytest.fixture -def mock_hybrid_pressure_cube(): - """Return mocked cube with hybrid pressure coordinate.""" - cube = unittest.mock.create_autospec(Cube, spec_set=True, instance=True) - ap_coord = AuxCoord([1.0], bounds=[[0.0, 2.0]], var_name='ap', units='Pa') - b_coord = AuxCoord([0.0], - bounds=[[-0.5, 1.5]], - var_name='b', - units=Unit('1')) - ps_coord = AuxCoord([[[100000]]], var_name='ps', units='Pa') - cube.coord.side_effect = [ - ap_coord, b_coord, ps_coord, ap_coord, b_coord, ps_coord - ] - cube.coords.return_value = [ - ap_coord, - b_coord, - ps_coord, - AuxCoord(0.0, - standard_name='atmosphere_hybrid_sigma_pressure_coordinate'), - ] - aux_factory = HybridPressureFactory( - delta=ap_coord, - sigma=b_coord, - surface_air_pressure=ps_coord, - ) - cube.aux_factories = ['dummy', aux_factory] - return cube - - @pytest.fixture def real_hybrid_pressure_cube(): """Return real cube with hybrid pressure coordinate.""" @@ -168,114 +70,6 @@ def real_hybrid_pressure_cube_list(): return get_hybrid_pressure_cube_list() -def check_if_fix_aux_factories_is_necessary(): - """Check if _fix_aux_factories() is necessary (i.e. iris bug is fixed).""" - cubes = get_hybrid_pressure_cube_list() - cube = cubes.concatenate_cube() - coords = [coord.name() for coord in cube.coords()] - msg = ("Apparently concatenation of cubes that have a derived variable " - "is now possible in iris (i.e. issue #2478 has been fixed). Thus, " - "this test and ALL appearances of the function " - "'_fix_aux_factories' can safely be removed!") - if 'air_pressure' in coords: - warnings.warn(msg) - - -def test_fix_aux_factories_empty_cube(mock_empty_cube): - """Test fixing with empty cube.""" - check_if_fix_aux_factories_is_necessary() - _io._fix_aux_factories(mock_empty_cube) - assert mock_empty_cube.mock_calls == [call.coords()] - - -def test_fix_aux_factories_atmosphere_sigma(mock_atmosphere_sigma_cube): - """Test fixing of atmosphere sigma coordinate.""" - check_if_fix_aux_factories_is_necessary() - - # Test with aux_factory object - _io._fix_aux_factories(mock_atmosphere_sigma_cube) - mock_atmosphere_sigma_cube.coords.assert_called_once_with() - mock_atmosphere_sigma_cube.coord.assert_has_calls( - [call(var_name='ptop'), - call(var_name='lev'), - call(var_name='ps')]) - mock_atmosphere_sigma_cube.add_aux_factory.assert_not_called() - - # Test without aux_factory object - mock_atmosphere_sigma_cube.reset_mock() - mock_atmosphere_sigma_cube.aux_factories = ['dummy'] - _io._fix_aux_factories(mock_atmosphere_sigma_cube) - mock_atmosphere_sigma_cube.coords.assert_called_once_with() - mock_atmosphere_sigma_cube.coord.assert_has_calls( - [call(var_name='ptop'), - call(var_name='lev'), - call(var_name='ps')]) - mock_atmosphere_sigma_cube.add_aux_factory.assert_called_once() - - -def test_fix_aux_factories_hybrid_height(mock_hybrid_height_cube): - """Test fixing of hybrid height coordinate.""" - check_if_fix_aux_factories_is_necessary() - - # Test with aux_factory object - _io._fix_aux_factories(mock_hybrid_height_cube) - mock_hybrid_height_cube.coords.assert_called_once_with() - mock_hybrid_height_cube.coord.assert_has_calls( - [call(var_name='lev'), - call(var_name='b'), - call(var_name='orog')]) - mock_hybrid_height_cube.add_aux_factory.assert_not_called() - - # Test without aux_factory object - mock_hybrid_height_cube.reset_mock() - mock_hybrid_height_cube.aux_factories = ['dummy'] - _io._fix_aux_factories(mock_hybrid_height_cube) - mock_hybrid_height_cube.coords.assert_called_once_with() - mock_hybrid_height_cube.coord.assert_has_calls( - [call(var_name='lev'), - call(var_name='b'), - call(var_name='orog')]) - mock_hybrid_height_cube.add_aux_factory.assert_called_once() - - -def test_fix_aux_factories_hybrid_pressure(mock_hybrid_pressure_cube): - """Test fixing of hybrid pressure coordinate.""" - check_if_fix_aux_factories_is_necessary() - - # Test with aux_factory object - _io._fix_aux_factories(mock_hybrid_pressure_cube) - mock_hybrid_pressure_cube.coords.assert_called_once_with() - mock_hybrid_pressure_cube.coord.assert_has_calls( - [call(var_name='ap'), - call(var_name='b'), - call(var_name='ps')]) - mock_hybrid_pressure_cube.add_aux_factory.assert_not_called() - - # Test without aux_factory object - mock_hybrid_pressure_cube.reset_mock() - mock_hybrid_pressure_cube.aux_factories = ['dummy'] - _io._fix_aux_factories(mock_hybrid_pressure_cube) - mock_hybrid_pressure_cube.coords.assert_called_once_with() - mock_hybrid_pressure_cube.coord.assert_has_calls( - [call(var_name='ap'), - call(var_name='b'), - call(var_name='ps')]) - mock_hybrid_pressure_cube.add_aux_factory.assert_called_once() - - -def test_fix_aux_factories_real_cube(real_hybrid_pressure_cube): - """Test fixing of hybrid pressure coordinate on real cube.""" - check_if_fix_aux_factories_is_necessary() - assert not real_hybrid_pressure_cube.coords('air_pressure') - _io._fix_aux_factories(real_hybrid_pressure_cube) - air_pressure_coord = real_hybrid_pressure_cube.coord('air_pressure') - expected_coord = AuxCoord([[[[1.0]]]], - bounds=[[[[[-50000., 150002.]]]]], - standard_name='air_pressure', - units='Pa') - assert air_pressure_coord == expected_coord - - def test_concatenation_with_aux_factory(real_hybrid_pressure_cube_list): """Test actual concatenation of a cube with a derived coordinate.""" concatenated = _io.concatenate(real_hybrid_pressure_cube_list)