diff --git a/mip_convert/mip_convert/tests/test_functional/test_functional_cmip7/test_cmip7_day_mmraerh2o_tavg-h2m-hxy-u.py b/mip_convert/mip_convert/tests/test_functional/test_functional_cmip7/test_cmip7_day_mmraerh2o_tavg-h2m-hxy-u.py new file mode 100644 index 000000000..924ac36b4 --- /dev/null +++ b/mip_convert/mip_convert/tests/test_functional/test_functional_cmip7/test_cmip7_day_mmraerh2o_tavg-h2m-hxy-u.py @@ -0,0 +1,58 @@ +# (C) British Crown Copyright 2022-2026, Met Office. +# Please see LICENSE.md for license details. +import os + +import pytest + +from mip_convert.tests.test_functional.test_command_line import AbstractFunctionalTests +from mip_convert.tests.test_functional.utils.configurations import Cmip7TestData, SpecificInfo +from mip_convert.tests.test_functional.utils.directories import (get_cmor_log, get_output_dir, + MODEL_OUTPUT_DIR, + ROOT_OUTPUT_CASES_DIR) + + +class TestCmip7_mmraerh2o_tavg_h2m_hxy_u(AbstractFunctionalTests): + + def get_test_data(self): + test_location = os.path.join(ROOT_OUTPUT_CASES_DIR, 'test_CMIP7_aerosol_mmraerh2o_tavg-h2m-hxy-u') + return Cmip7TestData( + mip_table='aerosol', + variables=['mmraerh2o_tavg-h2m-hxy-u'], + specific_info=SpecificInfo( + common={ + 'test_location': test_location}, + cmor_setup={ + 'cmor_log_file': get_cmor_log(test_location) + }, + cmor_dataset={ + 'output_dir': get_output_dir(test_location), + 'calendar': 'standard', + 'branch_date_in_child': "1850-01-01T00:00:00", + 'branch_date_in_parent': "1850-01-01T00:00:00", + 'model_id': 'UKCM2-0-LL', + 'variant_label': 'r2i1p1f1', + 'parent_model_id': 'UKCM2-0-LL' + }, + request={ + 'model_output_dir': MODEL_OUTPUT_DIR, + 'run_bounds': '1900-01-01T00:00:00 1900-02-01T00:00:00', + 'suite_id': 'u-dv623', + 'mip_convert_plugin': 'UKCM2' + }, + streams={ + 'ap6': {'CMIP7_aerosol@day': 'mmraerh2o_tavg-h2m-hxy-u'} + }, + other={ + 'reference_version': 'v1', + 'filenames': [ + 'mmraerh2o_tavg-h2m-hxy-u_day_glb_g100_UKCM2-0-LL_1pctCO2_r2i1p1f1_19000101-19000131.nc' + ], + 'ignore_history': True, + } + ) + ) + + @pytest.mark.slow + def test_cmip7_day_mmraerh2o(self): + self.maxDiff = True + self.check_convert(plugin_id="CMIP7") diff --git a/mip_convert/mip_convert/tests/test_process/test_processors.py b/mip_convert/mip_convert/tests/test_process/test_processors.py index 9d4d48403..1ff9715f1 100644 --- a/mip_convert/mip_convert/tests/test_process/test_processors.py +++ b/mip_convert/mip_convert/tests/test_process/test_processors.py @@ -18,8 +18,9 @@ from mip_convert.plugins.base.data.processors import ( area_mean, areacella, calc_rho_mean, calc_zostoga, combine_cubes_to_basin_coord, eos_insitu, fix_clmisr_height, land_class_area, land_class_mean, level_sum, mask_copy, mask_zeros, mask_polar_column_zonal_means, - mon_mean_from_day, ocean_quasi_barotropic_streamfunc, tile_ids_for_class, volcello, vortmean, - annual_from_monthly_2d, annual_from_monthly_3d, calculate_thkcello_weights, check_data_is_monthly) + mon_mean_from_day, ocean_quasi_barotropic_streamfunc, replace_altitude_with_height2m, tile_ids_for_class, + remove_altitude_coords, volcello, vortmean, annual_from_monthly_2d, annual_from_monthly_3d, calculate_thkcello_weights, + check_data_is_monthly) from mip_convert.tests.common import dummy_cube from functools import reduce @@ -45,6 +46,16 @@ def _cube_with_tbounds(bounds, unit=_DEFAULT_UNIT): dim_coords_and_dims=[(times, 0)]) +def _cube_with_surface_altitude(): + """Return a minimal cube with a 2D surface_altitude aux coord.""" + lat = DimCoord([0.], long_name='lat') + lon = DimCoord([0.], long_name='lon') + surface_altitude = AuxCoord(np.zeros((1, 1)), standard_name='surface_altitude') + cube = Cube(np.ones((1, 1)), dim_coords_and_dims=[(lat, 0), (lon, 1)]) + cube.add_aux_coord(surface_altitude, (0, 1)) + return cube + + class TestMonMeanFromDay(unittest.TestCase): def _assert_value_error(self, cube, err_msg): @@ -985,5 +996,33 @@ def test_test_annual_cube(self): np.testing.assert_array_almost_equal(result.data, expected, decimal=12) +class TestReplaceAltitudeWithHeight2m(unittest.TestCase): + + def setUp(self): + self.cube = _cube_with_surface_altitude() + + def test_surface_altitude_coord_is_removed(self): + result = replace_altitude_with_height2m(self.cube) + coord_names = [c.name() for c in result.coords()] + self.assertNotIn('surface_altitude', coord_names) + + def test_height2m_scalar_coord_is_added(self): + result = replace_altitude_with_height2m(self.cube) + height_coord = result.coord('height') + self.assertEqual(height_coord.points[0], np.float32(2.0)) + self.assertEqual(str(height_coord.units), 'm') + + +class TestRemoveAltitudeCoords(unittest.TestCase): + + def setUp(self): + self.cube = _cube_with_surface_altitude() + + def test_surface_altitude_coord_is_removed(self): + result = remove_altitude_coords(self.cube) + coord_names = [c.name() for c in result.coords()] + self.assertNotIn('surface_altitude', coord_names) + + if __name__ == '__main__': unittest.main()