From 8ea1502b5bfe6ad93bd8fc18d1250587267aa782 Mon Sep 17 00:00:00 2001 From: sloosvel Date: Wed, 16 Nov 2022 16:37:42 +0100 Subject: [PATCH 01/19] Add iris-esmf-regrid to env file --- environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment.yml b/environment.yml index 5873831080..7db41f52c1 100644 --- a/environment.yml +++ b/environment.yml @@ -18,6 +18,7 @@ dependencies: - humanfriendly - importlib_resources - iris>=3.2.1 + - iris-esmf-regrid - isodate - jinja2 - nc-time-axis From f97985dc2ee07c1cb49cedb39ba1f2a3181616d4 Mon Sep 17 00:00:00 2001 From: sloosvel Date: Thu, 17 Nov 2022 16:55:46 +0100 Subject: [PATCH 02/19] Allow to use regrid_rectilinear_to_rectilinear scheme --- esmvalcore/preprocessor/_regrid.py | 35 +++++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/esmvalcore/preprocessor/_regrid.py b/esmvalcore/preprocessor/_regrid.py index 3cf0e057de..c323dcbf84 100644 --- a/esmvalcore/preprocessor/_regrid.py +++ b/esmvalcore/preprocessor/_regrid.py @@ -1,6 +1,7 @@ """Horizontal and vertical regridding module.""" import importlib +import inspect import logging import os import re @@ -14,7 +15,7 @@ from dask import array as da from geopy.geocoders import Nominatim from iris.analysis import AreaWeighted, Linear, Nearest, UnstructuredNearest -from iris.util import broadcast_to_shape +from iris.util import broadcast_to_shape, squeeze from ..cmor._fixes.shared import add_altitude_from_plev, add_plev_from_altitude from ..cmor.fix import fix_file, fix_metadata @@ -24,6 +25,8 @@ from ._regrid_esmpy import ESMF_REGRID_METHODS from ._regrid_esmpy import regrid as esmpy_regrid +from esmf_regrid.schemes import regrid_rectilinear_to_rectilinear + logger = logging.getLogger(__name__) # Regular expression to parse a "MxN" cell-specification. @@ -451,7 +454,7 @@ def extract_point(cube, latitude, longitude, scheme): return cube -def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): +def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True, mdtol=0): """Perform horizontal regridding. Note that the target grid can be a cube (:py:class:`~iris.cube.Cube`), @@ -536,8 +539,7 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): extrapolation_mode: nanmask To use the area weighted regridder available in - :class:`esmf_regrid.schemes.ESMFAreaWeighted`, make sure that - :doc:`iris-esmf-regrid:index` is installed and use + :class:`esmf_regrid.schemes.ESMFAreaWeighted` use .. code-block:: yaml @@ -547,10 +549,8 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): scheme: reference: esmf_regrid.schemes:ESMFAreaWeighted - .. note:: - - Note that :doc:`iris-esmf-regrid:index` is still experimental. """ + scheme_args = None if isinstance(scheme, dict): try: object_ref = scheme.pop("reference") @@ -568,12 +568,12 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): if separator: for attr in scheme_name.split('.'): obj = getattr(obj, attr) - loaded_scheme = obj(**scheme) + scheme_args = inspect.getfullargspec(obj).args else: loaded_scheme = HORIZONTAL_SCHEMES.get(scheme.lower()) - if loaded_scheme is None: - emsg = 'Unknown regridding scheme, got {!r}.' - raise ValueError(emsg.format(scheme)) + if loaded_scheme is None: + emsg = 'Unknown regridding scheme, got {!r}.' + raise ValueError(emsg.format(scheme)) if isinstance(target_grid, str): if os.path.isfile(target_grid): @@ -599,6 +599,12 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): if not isinstance(target_grid, iris.cube.Cube): raise ValueError('Expecting a cube, got {}.'.format(target_grid)) + + if isinstance(scheme_args, list): + if 'src_cube' in scheme_args: + scheme['src_cube'] = cube + if 'grid_cube' in scheme_args: + scheme['grid_cube'] = target_grid # Unstructured regridding requires x2 2d spatial coordinates, # so ensure to purge any 1d native spatial dimension coordinates @@ -625,11 +631,15 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): else: fill_value = GLOBAL_FILL_VALUE da.ma.set_fill_value(cube.core_data(), fill_value) - + a = regrid_rectilinear_to_rectilinear(cube, target_grid) # Perform the horizontal regridding if _attempt_irregular_regridding(cube, scheme): cube = esmpy_regrid(cube, target_grid, scheme) else: + loaded_scheme = obj(**scheme) + if isinstance(loaded_scheme, iris.cube.Cube): + return loaded_scheme + cube = cube.regrid(target_grid, loaded_scheme) # Preserve dtype and use masked arrays for 'unstructured_nearest' @@ -652,7 +662,6 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): return cube - def _horizontal_grid_is_close(cube1, cube2): """Check if two cubes have the same horizontal grid definition. From 263f4b4e929ec437bc319352f535dc07d7ce187b Mon Sep 17 00:00:00 2001 From: sloosvel Date: Thu, 17 Nov 2022 16:56:02 +0100 Subject: [PATCH 03/19] Add tests --- .../preprocessor/_regrid/test_regrid.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/integration/preprocessor/_regrid/test_regrid.py b/tests/integration/preprocessor/_regrid/test_regrid.py index a6ba8b95b5..d954891235 100644 --- a/tests/integration/preprocessor/_regrid/test_regrid.py +++ b/tests/integration/preprocessor/_regrid/test_regrid.py @@ -14,6 +14,7 @@ from tests.unit.preprocessor._regrid import _make_cube + class Test(tests.Test): def setUp(self): """Prepare tests.""" @@ -91,6 +92,15 @@ def test_regrid__linear(self): result = regrid(self.cube, self.grid_for_linear, 'linear') expected = np.array([[[1.5]], [[5.5]], [[9.5]]]) self.assert_array_equal(result.data, expected) + + def test_regrid__esmf_rectilinear(self): + result = regrid( + self.cube, + self.grid_for_linear, + {'reference': + 'esmf_regrid.schemes:regrid_rectilinear_to_rectilinear',}) + expected = np.array([[[1.5]], [[5.5]], [[9.5]]]) + np.testing.assert_array_almost_equal(result.data, expected, decimal=1) def test_regrid__regular_coordinates(self): data = np.ones((1, 1)) @@ -214,6 +224,25 @@ def test_regrid__area_weighted(self): expected = np.array([1.499886, 5.499886, 9.499886]) np.testing.assert_array_almost_equal(result.data, expected, decimal=6) + def test_regrid__esmf_area_weighted(self): + data = np.empty((1, 1)) + lons = iris.coords.DimCoord([1.6], + standard_name='longitude', + bounds=[[1, 2]], + units='degrees_east', + coord_system=self.cs) + lats = iris.coords.DimCoord([1.6], + standard_name='latitude', + bounds=[[1, 2]], + units='degrees_north', + coord_system=self.cs) + coords_spec = [(lats, 0), (lons, 1)] + grid = iris.cube.Cube(data, dim_coords_and_dims=coords_spec) + result = regrid(self.cube, grid, {'reference': + 'esmf_regrid.schemes:ESMFAreaWeighted'}) + expected = np.array([1.499886, 5.499886, 9.499886]) + np.testing.assert_array_almost_equal(result.data, expected, decimal=6) + def test_regrid__unstructured_nearest_float(self): """Test unstructured_nearest regridding with cube of floats.""" result = regrid(self.unstructured_grid_cube, From b5dda6fb0b976a2fe4cf3d5453f2f31b64151d59 Mon Sep 17 00:00:00 2001 From: sloosvel Date: Thu, 17 Nov 2022 17:25:11 +0100 Subject: [PATCH 04/19] Clean --- esmvalcore/preprocessor/_regrid.py | 10 ++++------ tests/integration/preprocessor/_regrid/test_regrid.py | 9 ++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/esmvalcore/preprocessor/_regrid.py b/esmvalcore/preprocessor/_regrid.py index c323dcbf84..fb27495878 100644 --- a/esmvalcore/preprocessor/_regrid.py +++ b/esmvalcore/preprocessor/_regrid.py @@ -15,7 +15,7 @@ from dask import array as da from geopy.geocoders import Nominatim from iris.analysis import AreaWeighted, Linear, Nearest, UnstructuredNearest -from iris.util import broadcast_to_shape, squeeze +from iris.util import broadcast_to_shape from ..cmor._fixes.shared import add_altitude_from_plev, add_plev_from_altitude from ..cmor.fix import fix_file, fix_metadata @@ -25,8 +25,6 @@ from ._regrid_esmpy import ESMF_REGRID_METHODS from ._regrid_esmpy import regrid as esmpy_regrid -from esmf_regrid.schemes import regrid_rectilinear_to_rectilinear - logger = logging.getLogger(__name__) # Regular expression to parse a "MxN" cell-specification. @@ -454,7 +452,7 @@ def extract_point(cube, latitude, longitude, scheme): return cube -def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True, mdtol=0): +def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): """Perform horizontal regridding. Note that the target grid can be a cube (:py:class:`~iris.cube.Cube`), @@ -599,7 +597,7 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True, mdtol=0) if not isinstance(target_grid, iris.cube.Cube): raise ValueError('Expecting a cube, got {}.'.format(target_grid)) - + if isinstance(scheme_args, list): if 'src_cube' in scheme_args: scheme['src_cube'] = cube @@ -631,7 +629,6 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True, mdtol=0) else: fill_value = GLOBAL_FILL_VALUE da.ma.set_fill_value(cube.core_data(), fill_value) - a = regrid_rectilinear_to_rectilinear(cube, target_grid) # Perform the horizontal regridding if _attempt_irregular_regridding(cube, scheme): cube = esmpy_regrid(cube, target_grid, scheme) @@ -662,6 +659,7 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True, mdtol=0) return cube + def _horizontal_grid_is_close(cube1, cube2): """Check if two cubes have the same horizontal grid definition. diff --git a/tests/integration/preprocessor/_regrid/test_regrid.py b/tests/integration/preprocessor/_regrid/test_regrid.py index d954891235..a601fcba3a 100644 --- a/tests/integration/preprocessor/_regrid/test_regrid.py +++ b/tests/integration/preprocessor/_regrid/test_regrid.py @@ -14,7 +14,6 @@ from tests.unit.preprocessor._regrid import _make_cube - class Test(tests.Test): def setUp(self): """Prepare tests.""" @@ -92,13 +91,13 @@ def test_regrid__linear(self): result = regrid(self.cube, self.grid_for_linear, 'linear') expected = np.array([[[1.5]], [[5.5]], [[9.5]]]) self.assert_array_equal(result.data, expected) - + def test_regrid__esmf_rectilinear(self): result = regrid( self.cube, self.grid_for_linear, - {'reference': - 'esmf_regrid.schemes:regrid_rectilinear_to_rectilinear',}) + {'reference': + 'esmf_regrid.schemes:regrid_rectilinear_to_rectilinear'}) expected = np.array([[[1.5]], [[5.5]], [[9.5]]]) np.testing.assert_array_almost_equal(result.data, expected, decimal=1) @@ -239,7 +238,7 @@ def test_regrid__esmf_area_weighted(self): coords_spec = [(lats, 0), (lons, 1)] grid = iris.cube.Cube(data, dim_coords_and_dims=coords_spec) result = regrid(self.cube, grid, {'reference': - 'esmf_regrid.schemes:ESMFAreaWeighted'}) + 'esmf_regrid.schemes:ESMFAreaWeighted'}) expected = np.array([1.499886, 5.499886, 9.499886]) np.testing.assert_array_almost_equal(result.data, expected, decimal=6) From 5d4a34890f7920d445605971bb8256cfb959e881 Mon Sep 17 00:00:00 2001 From: sloosvel Date: Thu, 17 Nov 2022 17:35:19 +0100 Subject: [PATCH 05/19] Fix flake --- .../integration/preprocessor/_regrid/test_regrid.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/integration/preprocessor/_regrid/test_regrid.py b/tests/integration/preprocessor/_regrid/test_regrid.py index a601fcba3a..78a167aa91 100644 --- a/tests/integration/preprocessor/_regrid/test_regrid.py +++ b/tests/integration/preprocessor/_regrid/test_regrid.py @@ -93,11 +93,14 @@ def test_regrid__linear(self): self.assert_array_equal(result.data, expected) def test_regrid__esmf_rectilinear(self): + scheme_name = 'esmf_regrid.schemes:regrid_rectilinear_to_rectilinear' + scheme = { + 'reference': scheme_name + } result = regrid( self.cube, self.grid_for_linear, - {'reference': - 'esmf_regrid.schemes:regrid_rectilinear_to_rectilinear'}) + scheme) expected = np.array([[[1.5]], [[5.5]], [[9.5]]]) np.testing.assert_array_almost_equal(result.data, expected, decimal=1) @@ -237,8 +240,10 @@ def test_regrid__esmf_area_weighted(self): coord_system=self.cs) coords_spec = [(lats, 0), (lons, 1)] grid = iris.cube.Cube(data, dim_coords_and_dims=coords_spec) - result = regrid(self.cube, grid, {'reference': - 'esmf_regrid.schemes:ESMFAreaWeighted'}) + scheme = { + 'reference': 'esmf_regrid.schemes:ESMFAreaWeighted' + } + result = regrid(self.cube, grid, scheme) expected = np.array([1.499886, 5.499886, 9.499886]) np.testing.assert_array_almost_equal(result.data, expected, decimal=6) From 473af2309c1b2800dc601647a12fcc19d4885d4c Mon Sep 17 00:00:00 2001 From: sloosvel Date: Fri, 18 Nov 2022 12:22:12 +0100 Subject: [PATCH 06/19] Add package to setup --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 98401f48b7..74893cf186 100755 --- a/setup.py +++ b/setup.py @@ -39,6 +39,7 @@ 'humanfriendly', "importlib_resources;python_version<'3.9'", 'isodate', + 'iris-esmf-regrid', 'jinja2', 'nc-time-axis', # needed by iris.plot 'nested-lookup', From 54b3acf852a384298a139530e80f1cc5d57c20cd Mon Sep 17 00:00:00 2001 From: sloosvel Date: Fri, 18 Nov 2022 12:26:56 +0100 Subject: [PATCH 07/19] Fix some tests --- esmvalcore/preprocessor/_regrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esmvalcore/preprocessor/_regrid.py b/esmvalcore/preprocessor/_regrid.py index fb27495878..3d6c90299e 100644 --- a/esmvalcore/preprocessor/_regrid.py +++ b/esmvalcore/preprocessor/_regrid.py @@ -603,6 +603,7 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): scheme['src_cube'] = cube if 'grid_cube' in scheme_args: scheme['grid_cube'] = target_grid + loaded_scheme = obj(**scheme) # Unstructured regridding requires x2 2d spatial coordinates, # so ensure to purge any 1d native spatial dimension coordinates @@ -633,7 +634,6 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): if _attempt_irregular_regridding(cube, scheme): cube = esmpy_regrid(cube, target_grid, scheme) else: - loaded_scheme = obj(**scheme) if isinstance(loaded_scheme, iris.cube.Cube): return loaded_scheme From 41ff490665c96901199b83aa4a5cfd176289657e Mon Sep 17 00:00:00 2001 From: sloosvel Date: Fri, 18 Nov 2022 13:23:41 +0100 Subject: [PATCH 08/19] Correct package name --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 74893cf186..c5e0caf870 100755 --- a/setup.py +++ b/setup.py @@ -32,6 +32,7 @@ 'cf-units', 'dask[array]', 'esgf-pyclient>=0.3.1', + 'esmf-regrid', 'esmpy!=8.1.0', # see github.com/ESMValGroup/ESMValCore/issues/1208 'fiona', 'fire', @@ -39,7 +40,6 @@ 'humanfriendly', "importlib_resources;python_version<'3.9'", 'isodate', - 'iris-esmf-regrid', 'jinja2', 'nc-time-axis', # needed by iris.plot 'nested-lookup', From 448f1c4896b4b43e236533e9f6849449c1b25c5d Mon Sep 17 00:00:00 2001 From: sloosvel Date: Fri, 18 Nov 2022 13:37:53 +0100 Subject: [PATCH 09/19] Fix shape in tests --- tests/integration/preprocessor/_regrid/test_regrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/preprocessor/_regrid/test_regrid.py b/tests/integration/preprocessor/_regrid/test_regrid.py index 78a167aa91..8a720d461f 100644 --- a/tests/integration/preprocessor/_regrid/test_regrid.py +++ b/tests/integration/preprocessor/_regrid/test_regrid.py @@ -244,7 +244,7 @@ def test_regrid__esmf_area_weighted(self): 'reference': 'esmf_regrid.schemes:ESMFAreaWeighted' } result = regrid(self.cube, grid, scheme) - expected = np.array([1.499886, 5.499886, 9.499886]) + expected = np.array([[[1.499886]], [[5.499886]], [[9.499886]]]) np.testing.assert_array_almost_equal(result.data, expected, decimal=6) def test_regrid__unstructured_nearest_float(self): From fcf77a245b57d36a5e3629fa4185aa3d53ac9193 Mon Sep 17 00:00:00 2001 From: sloosvel Date: Fri, 18 Nov 2022 16:40:36 +0100 Subject: [PATCH 10/19] Remove warning from docs --- doc/recipe/preprocessor.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/recipe/preprocessor.rst b/doc/recipe/preprocessor.rst index 6b372b9143..9f80d556a0 100644 --- a/doc/recipe/preprocessor.rst +++ b/doc/recipe/preprocessor.rst @@ -926,10 +926,6 @@ example of its usage in an ESMValTool preprocessor is: reference: esmf_regrid.schemes:ESMFAreaWeighted mdtol: 0.7 -.. TODO: Remove the following warning once things have settled a bit. -.. warning:: - Just as the mesh support in Iris itself, this new regridding package is - still considered experimental. .. _ensemble statistics: From 1de2ccd44adeb911e4bdd02ade7ade7057e9f207 Mon Sep 17 00:00:00 2001 From: sloosvel Date: Wed, 23 Nov 2022 11:41:47 +0100 Subject: [PATCH 11/19] Reorder code to make it cleaner --- esmvalcore/preprocessor/_regrid.py | 55 +++++++++---------- .../unit/preprocessor/_regrid/test_regrid.py | 3 +- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/esmvalcore/preprocessor/_regrid.py b/esmvalcore/preprocessor/_regrid.py index 3d6c90299e..6444253c25 100644 --- a/esmvalcore/preprocessor/_regrid.py +++ b/esmvalcore/preprocessor/_regrid.py @@ -548,31 +548,6 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): reference: esmf_regrid.schemes:ESMFAreaWeighted """ - scheme_args = None - if isinstance(scheme, dict): - try: - object_ref = scheme.pop("reference") - except KeyError as key_err: - raise ValueError( - "No reference specified for generic regridding.") from key_err - module_name, separator, scheme_name = object_ref.partition(":") - try: - obj = importlib.import_module(module_name) - except ImportError as import_err: - raise ValueError( - "Could not import specified generic regridding module. " - "Please double check spelling and that the required module is " - "installed.") from import_err - if separator: - for attr in scheme_name.split('.'): - obj = getattr(obj, attr) - scheme_args = inspect.getfullargspec(obj).args - else: - loaded_scheme = HORIZONTAL_SCHEMES.get(scheme.lower()) - if loaded_scheme is None: - emsg = 'Unknown regridding scheme, got {!r}.' - raise ValueError(emsg.format(scheme)) - if isinstance(target_grid, str): if os.path.isfile(target_grid): target_grid = iris.load_cube(target_grid) @@ -590,20 +565,43 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): ycoord = target_grid.coord(axis='y', dim_coords=True) xcoord.coord_system = src_cs ycoord.coord_system = src_cs - elif isinstance(target_grid, dict): # Generate a target grid from the provided specification, target_grid = _regional_stock_cube(target_grid) - + if not isinstance(target_grid, iris.cube.Cube): raise ValueError('Expecting a cube, got {}.'.format(target_grid)) - if isinstance(scheme_args, list): + if isinstance(scheme, dict): + try: + object_ref = scheme.pop("reference") + except KeyError as key_err: + raise ValueError( + "No reference specified for generic regridding.") from key_err + module_name, separator, scheme_name = object_ref.partition(":") + try: + obj = importlib.import_module(module_name) + except ImportError as import_err: + raise ValueError( + "Could not import specified generic regridding module. " + "Please double check spelling and that the required module is " + "installed.") from import_err + if separator: + for attr in scheme_name.split('.'): + obj = getattr(obj, attr) + + scheme_args = inspect.getfullargspec(obj).args if 'src_cube' in scheme_args: scheme['src_cube'] = cube if 'grid_cube' in scheme_args: scheme['grid_cube'] = target_grid + loaded_scheme = obj(**scheme) + else: + loaded_scheme = HORIZONTAL_SCHEMES.get(scheme.lower()) + if loaded_scheme is None: + emsg = 'Unknown regridding scheme, got {!r}.' + raise ValueError(emsg.format(scheme)) # Unstructured regridding requires x2 2d spatial coordinates, # so ensure to purge any 1d native spatial dimension coordinates @@ -636,7 +634,6 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): else: if isinstance(loaded_scheme, iris.cube.Cube): return loaded_scheme - cube = cube.regrid(target_grid, loaded_scheme) # Preserve dtype and use masked arrays for 'unstructured_nearest' diff --git a/tests/unit/preprocessor/_regrid/test_regrid.py b/tests/unit/preprocessor/_regrid/test_regrid.py index 3846ccac81..06001589b1 100644 --- a/tests/unit/preprocessor/_regrid/test_regrid.py +++ b/tests/unit/preprocessor/_regrid/test_regrid.py @@ -103,10 +103,9 @@ def test_invalid_tgt_grid__unknown(self): regrid(self.src_cube, dummy, scheme) def test_invalid_scheme__unknown(self): - dummy = mock.sentinel.dummy emsg = 'Unknown regridding scheme' with self.assertRaisesRegex(ValueError, emsg): - regrid(dummy, dummy, 'wibble') + regrid(self.src_cube, self.src_cube, 'wibble') def test_horizontal_schemes(self): self.assertEqual( From aaa0cae36f695ed8739101df63d642b67957ae63 Mon Sep 17 00:00:00 2001 From: sloosvel Date: Wed, 23 Nov 2022 12:12:13 +0100 Subject: [PATCH 12/19] Improve documentation --- doc/recipe/preprocessor.rst | 16 +++++++++++++++- esmvalcore/preprocessor/_regrid.py | 8 ++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/doc/recipe/preprocessor.rst b/doc/recipe/preprocessor.rst index 9f80d556a0..26c984c72d 100644 --- a/doc/recipe/preprocessor.rst +++ b/doc/recipe/preprocessor.rst @@ -892,7 +892,7 @@ necessary information. That includes a ``reference`` to the desired scheme itself, as well as any arguments that should be passed through to the scheme. For example, the following shows the use of the built-in scheme :class:`iris.analysis.AreaWeighted` with a custom threshold for missing data -tolerance. +tolerance. .. code-block:: yaml @@ -926,6 +926,20 @@ example of its usage in an ESMValTool preprocessor is: reference: esmf_regrid.schemes:ESMFAreaWeighted mdtol: 0.7 +Additionally, the use of generic schemes that take source and target grid cubes as +arguments is also supported. The `regrid` module will automatically pass +the cubes as inputs of the scheme. An example of this usage is +the `regrid_rectilinear_to_rectilinear` scheme available in `iris-esmf-regrid`: + +.. code-block:: yaml + + preprocessors: + regrid_preprocessor: + regrid: + target_grid: 2.5x2.5 + scheme: + reference: esmf_regrid.schemes:regrid_rectilinear_to_rectilinear + mdtol: 0.7 .. _ensemble statistics: diff --git a/esmvalcore/preprocessor/_regrid.py b/esmvalcore/preprocessor/_regrid.py index 6444253c25..bc69ed7023 100644 --- a/esmvalcore/preprocessor/_regrid.py +++ b/esmvalcore/preprocessor/_regrid.py @@ -591,6 +591,7 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): obj = getattr(obj, attr) scheme_args = inspect.getfullargspec(obj).args + # Add source and target cubes as arguments if required if 'src_cube' in scheme_args: scheme['src_cube'] = cube if 'grid_cube' in scheme_args: @@ -628,12 +629,15 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): else: fill_value = GLOBAL_FILL_VALUE da.ma.set_fill_value(cube.core_data(), fill_value) + # Perform the horizontal regridding if _attempt_irregular_regridding(cube, scheme): cube = esmpy_regrid(cube, target_grid, scheme) + elif isinstance(loaded_scheme, iris.cube.Cube): + # Return regridded cube in cases in which the + # scheme is a function f(src_cube, grid_cube) -> Cube. + return loaded_scheme else: - if isinstance(loaded_scheme, iris.cube.Cube): - return loaded_scheme cube = cube.regrid(target_grid, loaded_scheme) # Preserve dtype and use masked arrays for 'unstructured_nearest' From 176f4ce1d4750e42674f45a0df342ee678a22f5d Mon Sep 17 00:00:00 2001 From: sloosvel Date: Wed, 23 Nov 2022 12:21:27 +0100 Subject: [PATCH 13/19] Fix flake --- esmvalcore/preprocessor/_regrid.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/esmvalcore/preprocessor/_regrid.py b/esmvalcore/preprocessor/_regrid.py index b665cfc074..a31c417286 100644 --- a/esmvalcore/preprocessor/_regrid.py +++ b/esmvalcore/preprocessor/_regrid.py @@ -568,7 +568,7 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): elif isinstance(target_grid, dict): # Generate a target grid from the provided specification, target_grid = _regional_stock_cube(target_grid) - + if not isinstance(target_grid, iris.cube.Cube): raise ValueError(f'Expecting a cube, got {target_grid}.') @@ -629,13 +629,13 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): else: fill_value = GLOBAL_FILL_VALUE da.ma.set_fill_value(cube.core_data(), fill_value) - + # Perform the horizontal regridding if _attempt_irregular_regridding(cube, scheme): cube = esmpy_regrid(cube, target_grid, scheme) elif isinstance(loaded_scheme, iris.cube.Cube): - # Return regridded cube in cases in which the - # scheme is a function f(src_cube, grid_cube) -> Cube. + # Return regridded cube in cases in which the + # scheme is a function f(src_cube, grid_cube) -> Cube return loaded_scheme else: cube = cube.regrid(target_grid, loaded_scheme) From 56b85aa1c789d5b7e855033abb37dedeca9e8deb Mon Sep 17 00:00:00 2001 From: sloosvel Date: Wed, 23 Nov 2022 12:25:32 +0100 Subject: [PATCH 14/19] Restore condition --- esmvalcore/preprocessor/_regrid.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/esmvalcore/preprocessor/_regrid.py b/esmvalcore/preprocessor/_regrid.py index a31c417286..df47523f77 100644 --- a/esmvalcore/preprocessor/_regrid.py +++ b/esmvalcore/preprocessor/_regrid.py @@ -600,9 +600,10 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): loaded_scheme = obj(**scheme) else: loaded_scheme = HORIZONTAL_SCHEMES.get(scheme.lower()) - if loaded_scheme is None: - emsg = 'Unknown regridding scheme, got {!r}.' - raise ValueError(emsg.format(scheme)) + + if loaded_scheme is None: + emsg = 'Unknown regridding scheme, got {!r}.' + raise ValueError(emsg.format(scheme)) # Unstructured regridding requires x2 2d spatial coordinates, # so ensure to purge any 1d native spatial dimension coordinates From 47005ea54bfc8bb565f19ba5a1a7d62a388d4bba Mon Sep 17 00:00:00 2001 From: sloosvel Date: Wed, 23 Nov 2022 12:29:18 +0100 Subject: [PATCH 15/19] Fix flake --- esmvalcore/preprocessor/_regrid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esmvalcore/preprocessor/_regrid.py b/esmvalcore/preprocessor/_regrid.py index df47523f77..eabbfd853e 100644 --- a/esmvalcore/preprocessor/_regrid.py +++ b/esmvalcore/preprocessor/_regrid.py @@ -600,7 +600,7 @@ def regrid(cube, target_grid, scheme, lat_offset=True, lon_offset=True): loaded_scheme = obj(**scheme) else: loaded_scheme = HORIZONTAL_SCHEMES.get(scheme.lower()) - + if loaded_scheme is None: emsg = 'Unknown regridding scheme, got {!r}.' raise ValueError(emsg.format(scheme)) From 6305e7dfdd5fd4d918929a28d1b2e69445ef7e03 Mon Sep 17 00:00:00 2001 From: sloosvel <45196700+sloosvel@users.noreply.github.com> Date: Wed, 23 Nov 2022 15:13:14 +0100 Subject: [PATCH 16/19] Apply suggestions from code review Co-authored-by: Manuel Schlund <32543114+schlunma@users.noreply.github.com> --- doc/recipe/preprocessor.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/recipe/preprocessor.rst b/doc/recipe/preprocessor.rst index 26c984c72d..bd0f53fb2c 100644 --- a/doc/recipe/preprocessor.rst +++ b/doc/recipe/preprocessor.rst @@ -892,7 +892,7 @@ necessary information. That includes a ``reference`` to the desired scheme itself, as well as any arguments that should be passed through to the scheme. For example, the following shows the use of the built-in scheme :class:`iris.analysis.AreaWeighted` with a custom threshold for missing data -tolerance. +tolerance. .. code-block:: yaml @@ -929,7 +929,7 @@ example of its usage in an ESMValTool preprocessor is: Additionally, the use of generic schemes that take source and target grid cubes as arguments is also supported. The `regrid` module will automatically pass the cubes as inputs of the scheme. An example of this usage is -the `regrid_rectilinear_to_rectilinear` scheme available in `iris-esmf-regrid`: +the :func:`~esmf_regrid.schemes.regrid_rectilinear_to_rectilinear` scheme available in :doc:`iris-esmf-regrid:index`: .. code-block:: yaml From d81ca55fb456dbd072ff95728fe8867bbcfe811c Mon Sep 17 00:00:00 2001 From: sloosvel Date: Wed, 23 Nov 2022 15:45:45 +0100 Subject: [PATCH 17/19] Improve documentation --- doc/recipe/preprocessor.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/recipe/preprocessor.rst b/doc/recipe/preprocessor.rst index bd0f53fb2c..fecf8f7007 100644 --- a/doc/recipe/preprocessor.rst +++ b/doc/recipe/preprocessor.rst @@ -926,10 +926,13 @@ example of its usage in an ESMValTool preprocessor is: reference: esmf_regrid.schemes:ESMFAreaWeighted mdtol: 0.7 -Additionally, the use of generic schemes that take source and target grid cubes as -arguments is also supported. The `regrid` module will automatically pass -the cubes as inputs of the scheme. An example of this usage is -the :func:`~esmf_regrid.schemes.regrid_rectilinear_to_rectilinear` scheme available in :doc:`iris-esmf-regrid:index`: +Additionally, the use of generic schemes that take source and target grid cubes as +arguments is also supported. The call function for such schemes must be defined as +`(src_cube, grid_cube, **kwargs)` and they must return `iris.cube.Cube` objects. +The `regrid` module will automatically pass the source and grid cubes as inputs +of the scheme. An example of this usage is +the :func:`~esmf_regrid.schemes.regrid_rectilinear_to_rectilinear` +scheme available in :doc:`iris-esmf-regrid:index`:git .. code-block:: yaml From aff8b2a8707ba89af87b98676dac3eac0410fc2a Mon Sep 17 00:00:00 2001 From: Valeriu Predoi Date: Wed, 23 Nov 2022 16:30:52 +0000 Subject: [PATCH 18/19] run GA tests --- .github/workflows/run-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index a9322fe9e8..4fbdeb49a3 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -21,6 +21,7 @@ on: push: branches: - main + - dev_install_iris_esfm # run the test only if the PR is to main # turn it on if required #pull_request: From c7ec2ccb0deee95b0815df0836e2e6275b902657 Mon Sep 17 00:00:00 2001 From: Valeriu Predoi Date: Wed, 23 Nov 2022 16:48:36 +0000 Subject: [PATCH 19/19] GA tests run fine turning them off --- .github/workflows/run-tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 4fbdeb49a3..a9322fe9e8 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -21,7 +21,6 @@ on: push: branches: - main - - dev_install_iris_esfm # run the test only if the PR is to main # turn it on if required #pull_request: