Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 33 additions & 53 deletions lib/iris/analysis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
'PEAK', 'PERCENTILE', 'PROPORTION', 'RMS', 'STD_DEV', 'SUM',
'VARIANCE', 'WPERCENTILE', 'coord_comparison', 'Aggregator',
'WeightedAggregator', 'clear_phenomenon_identity', 'Linear',
'AreaWeighted', 'Nearest')
'AreaWeighted', 'Nearest', 'UnstructuredNearest')


class _CoordGroup(object):
Expand Down Expand Up @@ -2348,13 +2348,31 @@ def regridder(self, src_grid, target_grid):

class UnstructuredNearest(object):
"""
This is a nearest-neighbour interpolation and regridding scheme for
regridding cubes whose latitude and longitude coordinates are mapped to the
same dimensions, rather than being orthogonal on independent dimensions.
This is a nearest-neighbour regridding scheme for regridding data whose
horizontal (X- and Y-axis) coordinates are mapped to the *same* dimensions,
rather than being orthogonal on independent dimensions.

Currently only supports regridding, not interpolation.
For latitude-longitude coordinates, the nearest-neighbour distances are
computed on the sphere, otherwise flat Euclidean distances are used.

The source X and Y coordinates can have any shape.

The target grid must be of the "normal" kind, i.e. it has separate,
1-dimensional X and Y coordinates.

Source and target XY coordinates must have the same coordinate system,
which may also be None.
If any of the XY coordinates are latitudes or longitudes, then they *all*
must be. Otherwise, the corresponding X and Y coordinates must have the
same units in the source and grid cubes.

.. Note::
Currently only supports regridding, not interpolation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This distinction isn't immediately obvious to me: interpolation is a numerical method which can support a regrid operation.
As this is the docstring for a class called UnstructuredNearest I suggest that this note is simply not required

Copy link
Member Author

@pp-mo pp-mo Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This distinction isn't immediately obvious to me: interpolation is a numerical method which can support a regrid operation.

What the words 'regrid' and 'interpolate' mean in Iris terms is that cubes support both a 'regrid' and an 'interpolate' method, which can both specify a "scheme".

the docstring for a class called UnstructuredNearest

UnstructuredNearest is a scheme, and these can generally be used with either interpolate or regrid
-- except that this one can't. ( Similarly, neither can PointInCell ).

So, I'd like to keep this statement.

This arrangement is now well established in Iris.
The practical difference is that a "regrid" uses a grid cube as its reference, while "interpolate" takes coordinate values.
But I do agree that the need for both is questionable, and the choice between is nowhere very clearly explained !!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I'm content with this


"""
# Note: the argument requirements are simply those of the underlying
# regridder class,
# :class:`iris.analysis.trajectory.UnstructuredNearestNeigbourRegridder`.
def __init__(self):
"""
Nearest-neighbour interpolation and regridding scheme suitable for
Expand All @@ -2367,53 +2385,14 @@ def __init__(self):
def __repr__(self):
return 'UnstructuredNearest()'

# def interpolator(self, cube, coords):
# """
# Creates a nearest-neighbour interpolator to perform
# interpolation over the given :class:`~iris.cube.Cube` specified
# by the dimensions of the specified coordinates.
#
# Typically you should use :meth:`iris.cube.Cube.interpolate` for
# interpolating a cube. There are, however, some situations when
# constructing your own interpolator is preferable. These are detailed
# in the :ref:`user guide <caching_an_interpolator>`.
#
# Args:
#
# * cube:
# The source :class:`iris.cube.Cube` to be interpolated.
# * coords:
# The names or coordinate instances that are to be
# interpolated over.
#
# Returns:
# A callable with the interface:
#
# `callable(sample_points, collapse_scalar=True)`
#
# where `sample_points` is a sequence containing an array of values
# for each of the coordinates passed to this method, and
# `collapse_scalar` determines whether to remove length one
# dimensions in the result cube caused by scalar values in
# `sample_points`.
#
# The values for coordinates that correspond to date/times
# may optionally be supplied as datetime.datetime or
# netcdftime.datetime instances.
#
# For example, for the callable returned by:
# `Nearest().interpolator(cube, ['latitude', 'longitude'])`,
# sample_points must have the form
# `[new_lat_values, new_lon_values]`.
#
# """
# return RectilinearInterpolator(cube, coords, 'nearest',
# self.extrapolation_mode)
# TODO: add interpolator usage
# def interpolator(self, cube):

def regridder(self, src_cube, target_grid):
"""
Creates a nearest-neighbour regridder to perform regridding from the
source grid to the target grid.
Creates a nearest-neighbour regridder, of the
:class:`~iris.analysis.trajectory.UnstructuredNearestNeigbourRegridder`
type, to perform regridding from the source grid to the target grid.

This can then be applied to any source data with the same structure as
the original 'src_cube'.
Expand All @@ -2427,13 +2406,14 @@ def regridder(self, src_cube, target_grid):

* src_cube:
The :class:`~iris.cube.Cube` defining the source grid.
The X and Y coordinates must be mapped over the same dimensions.
The X and Y coordinates can have any shape, but must be mapped over
the same cube dimensions.

* target_grid:
The :class:`~iris.cube.Cube` defining the target grid.
It must have only 2 dimensions.
The X and Y coordinates must be one-dimensional and mapped to
different dimensions.
The X and Y coordinates must be one-dimensional dimension
coordinates, mapped to different dimensions.
All other cube components are ignored.

Returns:
A callable with the interface:
Expand Down
5 changes: 5 additions & 0 deletions lib/iris/analysis/_interpolate_private.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ def _nearest_neighbour_indices_ndcoords(cube, sample_points, cache=None):
Because this function can be slow for multidimensional coordinates,
a 'cache' dictionary can be provided by the calling code.

.. Note::

If the points are longitudes/latitudes, these are handled correctly as
points on the sphere, but the values must be in 'degrees'.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this protected somewhere? if i supply radians, will a meaningful exception be raised?

Copy link
Member Author

@pp-mo pp-mo Dec 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this protected somewhere? if i supply radians, will a meaningful exception be raised?

No, it is not checked and will just give wrong answers !

I decided to document this problem rather than fix it, as it is an existing low-level routine.
As this is a private routine I thought that was ok.

Arguably, we should maybe fix the existing analysis.trajectory.interpolate, as it calls this and so exposes the same problem.
? what do you think @marqh ?

I have fixed it in the UnstructuredNearest classes, which now convert everything to degrees (and complain if it fails).


"""

# Developer notes:
Expand Down
Loading