From 8ac834d402b8ebd16daab0acbeaac40d9ed5581e Mon Sep 17 00:00:00 2001 From: Matt Ueckermann Date: Sat, 27 Mar 2021 02:27:29 +0000 Subject: [PATCH] FIX: fixing floating point errors causing nan's at tile edges when the request *nearly* matches the source coordinates (up to floating point error) --- .../interpolation/nearest_neighbor_interpolator.py | 6 +++++- podpac/core/interpolation/selector.py | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/podpac/core/interpolation/nearest_neighbor_interpolator.py b/podpac/core/interpolation/nearest_neighbor_interpolator.py index 34962eb1..5b0a4208 100644 --- a/podpac/core/interpolation/nearest_neighbor_interpolator.py +++ b/podpac/core/interpolation/nearest_neighbor_interpolator.py @@ -404,7 +404,11 @@ def select_coordinates(self, udims, source_coordinates, eval_coordinates, index_ if src_coords.size == 1: c = src_coords.copy() else: - c = UniformCoordinates1d(src_start, src_stop, ndelta * src_delta, **src_coords.properties) + c = UniformCoordinates1d( + src_start, + src_stop + ndelta * src_delta / 2, # The delta/2 ensures the endpoint is included + ndelta * src_delta, + **src_coords.properties) if isinstance(idx, slice): idx = slice(idx.start, idx.stop, int(ndelta)) diff --git a/podpac/core/interpolation/selector.py b/podpac/core/interpolation/selector.py index 2893d49e..c6ea006e 100644 --- a/podpac/core/interpolation/selector.py +++ b/podpac/core/interpolation/selector.py @@ -139,11 +139,21 @@ def _select_uniform(self, source, request, index_type): return np.arange(source.size) index = (crds.coordinates - source.start) / source.step - stop_ind = int(np.round((source.stop - source.start) / source.step)) + stop_ind = source.size - 1 if len(self.method) > 1: flr_ceil = {-1: np.floor(index), 1: np.ceil(index)} else: - flr_ceil = {0: np.round(index)} + # In this case, floating point error really matters, so we have to do a test + up = np.round(index - 1e-6) + down = np.round(index + 1e-6) + # When up and down do not agree, use the index that will be kept. + index_mid = down # arbitrarily default to down when both satisfy criteria + Iup = up != down + Iup[Iup] = (up[Iup] >= 0) & (up[Iup] <= stop_ind) & ((up[Iup] > down.max()) | (up[Iup] < down.min())) + index_mid[Iup] = up[Iup] + flr_ceil = {0: index_mid} + # flr_ceil = {0: index} + inds = [] for m in self.method: sign = np.sign(m)