verde icon indicating copy to clipboard operation
verde copied to clipboard

Support n-dimensional coordinates

Open prisae opened this issue 6 years ago • 3 comments

Carrying over from the discussion on SWUNG.

Expand the spline kernel to allow n-dimensional data. In particular, data in 3D (so interpolate [x, y, z, data] to arbitrary points [xi, yi, zi]).

Something like scipy.interpolate.interpn with method=spline, which is only supported for 1D and 2D in scipy.

Loosely related to #138

prisae avatar Jun 09 '19 06:06 prisae

This does what I had in mind: https://github.com/prisae/tmp-share/blob/master/interp_cubic_spline_3d.py

import numpy as np
from scipy import interpolate, ndimage

def interp_cubic_spline_3d(points, values, xi):
    """3D cubic spline interpolation.
    Zeroes are returned for interpolated values requested outside of the domain
    of the input data.
    """

    # Replicate the same expansion of xi as used in
    # RegularGridInterpolator, so the input xi can be quite flexible.
    xi = interpolate.interpnd._ndim_coords_from_arrays(xi, ndim=3)
    xi_shape = xi.shape
    xi = xi.reshape(-1, 3)

    # map_coordinates uses the indices of the input data as coordinates. We
    # have therefore to transform our desired output coordinates to this
    # artificial coordinate system too.
    params = {'kind': 'cubic',
              'bounds_error': False,
              'fill_value': 'extrapolate'}
    x = interpolate.interp1d(
            points[0], np.arange(len(points[0])), **params)(xi[:, 0])
    y = interpolate.interp1d(
            points[1], np.arange(len(points[1])), **params)(xi[:, 1])
    z = interpolate.interp1d(
            points[2], np.arange(len(points[2])), **params)(xi[:, 2])
    coords = np.vstack([x, y, z])

    # map_coordinates only works for real data; split it up if complex.
    if 'complex' in values.dtype.name:
        real = ndimage.map_coordinates(values.real, coords, order=3)
        imag = ndimage.map_coordinates(values.imag, coords, order=3)
        result = real + 1j*imag
    else:
        result = ndimage.map_coordinates(values, coords, order=3)

    return result.reshape(xi_shape[:-1])

It might (or might not) be of interest for verde to add such a functionality.

prisae avatar Jun 10 '19 09:06 prisae

@prisae this is of interest for sure :+1: We would need to have #138 before we can proceed with this, though.

After that is done, the way forward would be to use all given coordinates instead of just coordinates[:2] in the kernels of verde/spline.py. There might be some issues with this down the line or when using Chain with BlockReduce (which is inherently 2D).

Would you be interested in taking a stab at #138 (or know someone who might be)?

leouieda avatar Jun 26 '19 02:06 leouieda

I don't think I have the bandwidth at the moment @leouieda , sorry. Particularly as my problem is solved with the above solution. But let's keep it and if more demand is coming from others we can come back to it!

prisae avatar Jun 26 '19 06:06 prisae