Skip to content

Conversation

@scottstanie
Copy link
Member

@scottstanie scottstanie commented Dec 1, 2025

The implementation of RegularGridInterpolators changed after scipy 1.14. If you ran this, you'd get the error from #2 :

uvx --with scipy==1.15 ipython
In [1]: spline = pickle.load(Path("src/whirlwind/carballo-pdf-0-spline.pkl").open('rb'))

In [2]: spline((.1, .1, 10))
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[8], line 1
----> 1 spline((.1, .1, 10))

File ~/.cache/uv/archive-v0/Zn_jXn_9BGPpxhZbmyQ53/lib/python3.13/site-packages/scipy/interpolate/_rgi.py:391, in RegularGridInterpolator.__call__(self, xi, method, nu)
    334 def __call__(self, xi, method=None, *, nu=None):
    335     """
    336     Interpolation at coordinates.
    337
   (...)    389     array([ 4.7, 24.3])
    390     """
--> 391     _spline = self._spline
    392     method = self.method if method is None else method
    393     is_method_changed = self.method != method

AttributeError: 'RegularGridInterpolator' object has no attribute '_spline'

This PR saves the underlying numpy arrays so that we can load it in newer scipy versions.

Closes #2

Copy link
Member

@gmgunter gmgunter left a comment

Choose a reason for hiding this comment

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

Thanks! Looks like a good fix to me. Glad to see that this tool is still getting some love.

@scottstanie
Copy link
Member Author

Changed those two items, thought I had done something else wrong since a SNAPHU-like unit test (with unw = whirlwind.unwrap(igram, corr, nlooks=1.0) instead) lead to this:
image
but it's happening on the main branch, as well as a couple git commits back before i touched anything

@gmgunter
Copy link
Member

Weird! Seems like it's an issue with the residue calculation -- nothing to do with the unwrapping algorithm itself. I don't think there should be any residues in that interferogram, but

import numpy as np
from whirlwind._lib import residue as get_residues

y, x = np.ogrid[-3:3:512j, -3:3:512j]
phase = np.pi * (x + y)
igram = np.exp(1j * phase)

wrapped_phase = np.angle(igram)
residue = get_residues(wrapped_phase)

num_negative_residues = np.sum(residue == -1)
num_positive_residues = np.sum(residue == 1)

print(f"{num_negative_residues:d}")  # prints '6'
print(f"{num_positive_residues:d}")  # prints '6'

Thanks for the report! It's clearly unrelated to this PR. I'll see if I can fix it in a separate PR.


def _load_rgi(path: Path | str) -> RegularGridInterpolator:
"""Reconstruct RegularGridInterpolator from saved data."""
data = np.load(path, allow_pickle=False)
Copy link
Member

Choose a reason for hiding this comment

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

Using numpy=2.3.5 and the latest commit

$ git rev-parse HEAD
46560ee9b55e331be1b82b2bf8e831f50ced7d32

I'm getting the following error:

Traceback (most recent call last):
  File "/home/ggunter/Projects/whirlwind/./test.py", line 12, in <module>
    unw = ww.unwrap(igram, corr, nlooks=1.0)
  File "/home/ggunter/miniforge3/envs/whirlwind/lib/python3.14/site-packages/whirlwind/_unwrap.py", line 28, in unwrap
    cost = compute_carballo_costs(igram, corr, nlooks, mask)
  File "/home/ggunter/miniforge3/envs/whirlwind/lib/python3.14/site-packages/whirlwind/_cost.py", line 65, in compute_carballo_costs
    spline_pdf0, spline_pdf1 = load_carballo_pdf_splines()
                               ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/ggunter/miniforge3/envs/whirlwind/lib/python3.14/site-packages/whirlwind/_cost.py", line 50, in load_carballo_pdf_splines
    spline_pdf0 = _load_rgi(p)
  File "/home/ggunter/miniforge3/envs/whirlwind/lib/python3.14/site-packages/whirlwind/_cost.py", line 37, in _load_rgi
    points=tuple(data["grid"]),
                 ~~~~^^^^^^^^
  File "/home/ggunter/miniforge3/envs/whirlwind/lib/python3.14/site-packages/numpy/lib/_npyio_impl.py", line 257, in __getitem__
    return format.read_array(
           ~~~~~~~~~~~~~~~~~^
        bytes,
        ^^^^^^
    ...<2 lines>...
        max_header_size=self.max_header_size
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/home/ggunter/miniforge3/envs/whirlwind/lib/python3.14/site-packages/numpy/lib/_format_impl.py", line 833, in read_array
    raise ValueError("Object arrays cannot be loaded when "
                     "allow_pickle=False")
ValueError: Object arrays cannot be loaded when allow_pickle=False

Comment on lines +41 to +43
fill_value=float(data["fill_value"])
if data["fill_value"] is not None
else None,
Copy link
Member

Choose a reason for hiding this comment

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

Looks like your formatter barfed here. Can we fit this on a single line for readability?

Maybe something like

    fill_value = float(data["fill_value"]) if data["fill_value"] is not None else None
    return RegularGridInterpolator(
        ...,
        fill_value=fill_value,
    )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace pickled splines with other data serialization method

2 participants