xarray_interp_inverse

PlasmaCalcs.tools.xarray_tools.xarray_sci.xarray_interp_inverse(array, interpto=None, output=None, *, promote_dims_if_needed=True, assume_sorted=None, assume_sorted_values=None, method=None, kw_interp=None, **interpto_as_kw)

interpolate a DataArray but using the array values as one of the interpolation variables;

the result is the array of the unused interpolation coordinate.
Example: if array has dims {‘x’, ‘y’} and name ‘T’, and interpto specifies ‘x’ and ‘T’,
then result will be a DataArray with dims {‘x’, ‘T’} and values for ‘y’.
Special case: if interpto specifications are single values,
the result will be scalar along that key instead of a dimension,
e.g. if interpto[‘x’] = 7 (as a opposed to a 1D array like [1,2,3]),
then result would have coordinate ‘x’=7 but not have an ‘x’ dimension.
See below for even more examples.
[EFF] note: inefficient if choosing many values along vars other than array.name.
each result value along those vars corresponds to its own interp call.
The internal steps are roughly:
(1) array.interp(all interpto vars except array.name)
(2) array.assign_coords({array.name: array})
(3) for each index along all interpto vars except array.name:
tmp = array.isel(index).interp({array.name: interpto[array.name]})
result[index] = tmp[output var]
[TODO] still need to implement step 3 for 3D+ arrays instead of only 2D or less.
array: xarray.DataArray
must have non-None array.name.
interpto: None or dict
dictionary of {var: value or array of values} to interpolate to.
Keys must correspond to array.name, and coords for all except 1 dim of array.
None –> provide interpto dict as kwargs to this function.
Note: the array of values for [TODO]
output: None or str
name for the result variable.
None –> use the key from array.dims which is missing from interpto (after xarray_ensure_dims).
promote_dims_if_needed: bool
whether to promote non-dimension coords to dimensions.
if False, raise DimensionKeyError if any relevant coord is not already a dimension.
assume_sorted: None or bool
whether to assume_sorted during step (1),
i.e. during the initial interp for all interpto vars except array.name
None –> assume_sorted if xarray_is_sorted.
True –> assume_sorted without checking. CAUTION: only do this if you’re 100% sure!
False –> don’t assume sorted. May be noticeably slower for large arrays.
assume_sorted_values: None or bool
whether to assume_sorted during step (3),
i.e. during the interp using array.name as a coordinate.
None –> assume_sorted if xarray_is_sorted. check at each index in step 3;
if False multiple times in a row, stop checking and just assume False.
True –> assume_sorted without checking. CAUTION: only do this if you’re 100% sure!
False –> don’t assume sorted. May be noticeably slower for large arrays.
method: None or str
method to pass to xarray.interp for all interpolations.
if None, use xarray.interp method default.
kw_interp: None or dict
if provided, pass these kwargs to all calls of xarray.interp.
These will eventually go to the internal interpolator method e.g. from scipy.
interpto_as_kw: optionally, provide interpto dict as kwargs to this function.
— More Examples —
# This array should make it easier to understand, follow, and predict results:
tt = pc.xrrange(5, ‘tens’)
oo = pc.xrrange(10, ‘ones’)
arr = (10 * tt + oo).rename(‘n’)
# arr looks like: [[0, 10, …, 40], [1, 11, …, 41], …, [9, 19, …, 49]].
pc.xarray_interp_inverse(arr, tens=1, n=17) == 7
arr.pc.interp_inverse(tens=1, n=17) == 7 # more convenient syntax thanks to pcAccessor.
# more exact matches:
arr.pc.interp_inverse(tens=2, n=23) == 3 # n=23, tens=2 –> ones=3
arr.pc.interp_inverse(n=20, tens=2) == 0 # n=20, tens=2 –> ones=0
arr.pc.interp_inverse(n=18, ones=8) == 1 # n=18, ones=8 –> tens=1
arr.pc.interp_inverse(n=29, ones=9) == 2 # n=29, ones=9 –> tens=2
# inexact matches:
arr.pc.interp_inverse(n=15, ones=0) == 1.5 # ones=0 –> tens needs 0.5
arr.pc.interp_inverse(n=27, ones=3) == 2.4
arr.pc.interp_inverse(n=23.5, tens=2) == 3.5
arr.pc.interp_inverse(n=27, tens=2.5) == 2
# unreachable array values (n) gives nan
arr.pc.interp_inverse(n=27, tens=3) –> NaN # ones can’t compensate
# out of bounds input coords (ones or tens) raises DimensionValueError (regardless of n)
arr.pc.interp_inverse(n=27, ones=10) –> crash with DimensionValueError
arr.pc.interp_inverse(n=11, ones=-1) –> crash with DimensionValueError
# coords can be arrays (output will be an xarray; shown here as a list.)
arr.pc.interp_inverse(ones=[7, 2], n=27)
–> xr.DataArray([2.0, 2.5], name=’tens’, dims=[‘ones’], coords=dict(ones=[7, 2], n=27))
arr.pc.interp_inverse(tens=[2,3], n=27)
–> xr.DataArray([7.0, nan], name=’ones’, dims=[‘tens’], coords=dict(tens=[2, 3], n=27))
# arr.name var can be an array:
arr.pc.interp_inverse(ones=5, n=[20, 25, 30, 36])
–> xr.DataArray([1.5, 2, 2.5, 3.1], name=’tens’, dims=[‘n’],
coords=dict(ones=5, n=[20, 25, 30, 36]))
# both can be arrays:
arr.pc.interp_inverse(ones=[0, 7, 9], n=[27, 29])
–> xr.DataArray([[2.7, 2.9], [2.0, 2.2], [1.8, 2.0]], name=’tens’, dims=[‘ones’, ‘n’],
coords=dict(ones=[0, 7, 9], n=[27, 29]))
# inputs can also be well-labeled; relevant info will be maintained:
ones = xr.DataArray([7, 2], name=’customname’, dims=[‘x’], coords=dict(x=[100, 200]))
arr.pc.interp_inverse(ones=ones, n=27)
–> xr.DataArray([2.0, 2.5], name=’tens’, dims=[‘x’],
coords=dict(ones=(‘x’, [7, 2]), n=27, x=[100, 200]))