Repository: Starfish-develop/Starfish

Issue:
Creating interpolator fails.
After making a HDF5 grid, and loading successfully the flux for combinations of parameters in the grid. 
I tried to interpolate a spectrum:

`myHDF5 = HDF5Interface(filename=inputfile)
flux = myHDF5.load_flux(np.array([6200, 4.5, 0.0]))
myInterpolator = Interpolator(myHDF5)`


Which gives the error:

keeping grid as is
/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Starfish/grid_tools/interpolators.py:22: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
  parameter_list = np.asarray(parameter_list)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~/GDrive/RESEARCH/GCK/code/galex111.py in <module>
----> 1 myInterpolator = Interpolator(myHDF5)

/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Starfish/grid_tools/interpolators.py in __init__(self, interface, wl_range, cache_max, cache_dump)
     88         self._determine_chunk_log()
     89 
---> 90         self._setup_index_interpolators()
     91         self.cache = OrderedDict([])
     92         self.cache_max = cache_max

/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Starfish/grid_tools/interpolators.py in _setup_index_interpolators(self)
    138         # Given a parameter value, produce fractional index between two points
    139         # Store the interpolators as a list
--> 140         self.index_interpolator = IndexInterpolator(self.interface.points)
    141 
    142         lenF = self.interface.ind[1] - self.interface.ind[0]

/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/Starfish/grid_tools/interpolators.py in __init__(self, parameter_list)
     22         parameter_list = np.asarray(parameter_list)
     23         self.npars = parameter_list.shape[-1]
---> 24         self.parameter_list = np.unique(parameter_list)
     25         self.index_interpolator = interp1d(
     26             self.parameter_list, np.arange(len(self.parameter_list)), kind="linear"

<__array_function__ internals> in unique(*args, **kwargs)

~/Library/Python/3.7/lib/python/site-packages/numpy/lib/arraysetops.py in unique(ar, return_index, return_inverse, return_counts, axis)
    270     ar = np.asanyarray(ar)
    271     if axis is None:
--> 272         ret = _unique1d(ar, return_index, return_inverse, return_counts)
    273         return _unpack_tuple(ret)
    274 

~/Library/Python/3.7/lib/python/site-packages/numpy/lib/arraysetops.py in _unique1d(ar, return_index, return_inverse, return_counts)
    331         aux = ar[perm]
    332     else:
--> 333         ar.sort()
    334         aux = ar
    335     mask = np.empty(aux.shape, dtype=np.bool_)

ValueError: operands could not be broadcast together with shapes (12,) (73,) 



Discussion:

Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4b4e685..e21f838 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,5 +1,5 @@
 repos:
 -   repo: https://github.com/python/black
-    rev: stable
+    rev: 22.3.0
     hooks:
     - id: black
diff --git a/Starfish/__init__.py b/Starfish/__init__.py
index 53d8ffc..2e6f331 100644
--- a/Starfish/__init__.py
+++ b/Starfish/__init__.py
@@ -1,4 +1,4 @@
-__version__ = "0.4.1"
+__version__ = "0.4.2"
 
 from .spectrum import Spectrum
 
diff --git a/Starfish/grid_tools/interpolators.py b/Starfish/grid_tools/interpolators.py
index bf6496a..ee954ce 100644
--- a/Starfish/grid_tools/interpolators.py
+++ b/Starfish/grid_tools/interpolators.py
@@ -19,12 +19,14 @@ class IndexInterpolator:
     """
 
     def __init__(self, parameter_list):
-        parameter_list = np.asarray(parameter_list)
-        self.npars = parameter_list.shape[-1]
-        self.parameter_list = np.unique(parameter_list)
-        self.index_interpolator = interp1d(
-            self.parameter_list, np.arange(len(self.parameter_list)), kind="linear"
-        )
+        parameter_list = list(parameter_list)
+        self.npars = len(parameter_list)
+        self.parameter_list = [np.unique(pars) for pars in parameter_list]
+        idxs = [np.arange(len(pars)) for pars in self.parameter_list]
+        self.index_interpolators = [
+            interp1d(pars, idx, kind="linear")
+            for pars, idx in zip(self.parameter_list, idxs)
+        ]
 
     def __call__(self, param):
         """
@@ -34,8 +36,8 @@ class IndexInterpolator:
         :type param: list
         :raises ValueError: if *value* is out of bounds.
 
-        :returns: ((low_val, high_val), (frac_low, frac_high)), the lower and higher bounding points in the grid
-        and the fractional distance (0 - 1) between them and the value.
+        :returns: ((low_val, high_val), (low_dist, high_dist)), the lower and higher bounding points in the grid
+        and the fractional distance (0 - 1) from the two points.
         """
         if len(param) != self.npars:
             raise ValueError(
@@ -43,17 +45,24 @@ class IndexInterpolator:
                     self.npars, len(param)
                 )
             )
-        try:
-            index = self.index_interpolator(param)
-        except ValueError:
-            raise ValueError("Requested param {} is out of bounds.".format(param))
-        high = np.ceil(index).astype(int)
-        low = np.floor(index).astype(int)
-        frac_index = index - low
-        return (
-            (self.parameter_list[low], self.parameter_list[high]),
-            ((1 - frac_index), frac_index),
-        )
+        lows = np.empty(self.npars)
+        highs = np.empty(self.npars)
+        fracs = np.empty(self.npars)
+        for i in range(self.npars):
+            # get interpolated index
+            try:
+                index = self.index_interpolators[i](param[i])
+            except ValueError:
+                raise ValueError("Requested param {} is out of bounds.".format(param))
+            low = np.floor(index).astype(int)
+            high = np.ceil(index).astype(int)
+            frac = index - low
+            # get bounding params
+            lows[i] = self.parameter_list[i][low]
+            highs[i] = self.parameter_list[i][high]
+            fracs[i] = frac
+
+        return (lows, highs), (1 - fracs, fracs)
 
 
 class Interpolator:
diff --git a/Starfish/grid_tools/utils.py b/Starfish/grid_tools/utils.py
index b7c2d4d..2a7a682 100644
--- a/Starfish/grid_tools/utils.py
+++ b/Starfish/grid_tools/utils.py
@@ -217,7 +217,7 @@ def determine_chunk_log(wl, wl_min, wl_max):
         else:
             break
 
-    assert type(chunk) == np.int, "Chunk is not an integer!. Chunk is {}".format(chunk)
+    assert type(chunk) == int, "Chunk is not an integer!. Chunk is {}".format(chunk)
 
     if chunk < len_wl:
         # Now that we have determined the length of the chunk of the synthetic
@@ -345,4 +345,4 @@ def idl_float(idl_num: str) -> float:
     ```
     """
     idl_str = idl_num.lower()
-    return np.float(idl_str.replace("d", "e"))
+    return float(idl_str.replace("d", "e"))


Test patch:
diff --git a/tests/test_grid_tools/test_interpolators.py b/tests/test_grid_tools/test_interpolators.py
index 7527237..db6a151 100644
--- a/tests/test_grid_tools/test_interpolators.py
+++ b/tests/test_grid_tools/test_interpolators.py
@@ -7,7 +7,8 @@ from Starfish.grid_tools import IndexInterpolator, Interpolator
 class TestIndexInterpolator:
     @pytest.fixture
     def mock_index_interpolator(self, grid_points):
-        yield IndexInterpolator(grid_points)
+        pars = [np.unique(pars) for pars in grid_points.T]
+        yield IndexInterpolator(pars)
 
     @pytest.mark.parametrize(
         "input, expected",