Open stephenworsley opened 2 years ago
An example of _create_cube
being written in a generic way that supports multiple different dimensionalities can be found in iris-esmf-regrid. Especially in this PR, also concerned with unifying regridders https://github.com/SciTools-incubator/iris-esmf-regrid/pull/175.
Thanks @stephenworsley for raising this issue. There would be great benefit in having a uniform API for regridding and interpolation. My take on this:
From this perspective we can classify each of the existing projection/interpolation and regridding methods. Eg, UnstructuredNearest for the interpolation of a nodal field on an unstructured grid, RectilinearRegridder for regridding of a nodal field, .... Ideally we want all the methods implemented for 2d/3d, different staggerings and mesh types with dispatching the operation to the "right" method based on the grid/field metadata.
📰 Custom Issue
There are a collection of regridders in iris which each work slightly differently, but are similar enough that they could potentially benefit from unifying some of their behaviour and perhaps have them inherit from the same abstract class. This would also benefit regridders built outside of iris such as in iris-esmf-regrid. The current set of iris regridding schemes is:
Linear
Nearest
AreaWeighted
UnstructuredNearest
PointInCell
There is also the deprecated regridder in iris.experimental.regrid_conservative which is functionally replaced by iris-esmf-regrid.
The current set of regridders have the following quirks:
Linear and Nearest
Linear
andNearest
regridding schemes create aRectilinearRegridder
(from analysis._regrid). This uses_RegularGridInterpolator
(from analysis._scipy_interpolate) to calculate weights and then use those weights, this derives from scipy and is under a scipy copyright, though the code has developed significantly since it was copied from scipy.RectilinearRegridder
, though_RegularGridInterpolator
does offer weight caching.interpolator
method._create_cube
method which handles derived coordinates. Even handles derived coordinates covering the grid dimension via the use of a regridder function callback.map_complete_blocks
.extrapolation_mode
AreaWeighted
AreaWeightedRegridder
(from analysis._area_weighted).__init__
.RectilinearRegridder._create_cube
with the callback being equivalent to Linear. This means that a different regridding method is acting on the AuxCoords and the data.regrid_area_weighted_rectilinear_src_and_grid
handles scalar grid coords, though the regridder class itself does not.map_complete_blocks
.mdtol
UnstructuredNearest
UnstructuredNearestNeighbourRegridder
(from analysis.trajectory) which usesanalysis.trajectory.interpolate
for calculations.Nearest
.trajectory.interpolate
rather thanRectilinearRegridder._create_cube
. This handles derived coords but not those which cover the grid dimensions, so a callback is not used.PointInCell
CurvilinearRegridder
(from analysis._regrid)__init__
but are cached on__call__
.__call__
function.weights
Suggestions
Currently, the most sophisticated regridder for metadata handling is
RectilinearRegridder
. The problem seems to be that other regridders have slightly different use cases so they can't fully take advantage of the infrastructure inRectilinearRegridder
. These regridders could be improved by having them derive from a regridder class which is more generic thanRectilinearRegridder
. This could also help the creation of future regridders (like in iris-esmf-regrid). Some ideas for how this regridder might be structured:_AbstractRegridder
DimCoords
andAuxCoords
with a view that this could be extended forMesh
in a subclass.__init__
.DimCoords
andAuxCoords
with a view that this could be extended forMesh
in a subclass.RectilinearRegridder._create_cube
._create_cube
method should call on methods for adding the grid Coords with a view that this could be extended forMesh
in a subclass.Rough proposed common structure of regridders:
The following is copied from a comment in #4807 where it demonstrates a structure to aim for which would allow the possibility to derive from a common class. The aim here is to bring all regridder closer to this structure, improving their functionality along the way, and then refactor this structure in terms of class inheritance when that becomes possible.
Sub-tasks/Side-tasks
Aside from the larger task of refactoring all the regridders to derive from an abstract class, there are several smaller tasks which could help to unify the behaviour of regridders. Bear in mind some of these tasks may have redundancy with the larger refactoring task.
AreaWeightedRegridder
to use sparse matrices (similar to iris-esmf-regrid, assuming this improves performance). #5365csc_matrix
andcsr_matrix
for consistency, comparing performance.CurvilinearRegridder
andRectilinearRegridder
to work on whole cubes rather than slices. #4807UnstructuredNearest
mask handling. #5062_create_cube
so that they can be consistent with the regridder they are being used in. #4807map_complete_blocks
.