Skip to content

One of the Bluestein FFT tests fails when run locally #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ivalaginja opened this issue May 5, 2025 · 2 comments
Closed

One of the Bluestein FFT tests fails when run locally #13

ivalaginja opened this issue May 5, 2025 · 2 comments

Comments

@ivalaginja
Copy link

This is part of openjournals/joss-reviews#7917.

One of your tests fails when run locally, see below.

That being said, since you have these tests, have you thought about setting up a GitHub Actions workflow? Just to be clear, this is not a requirement for the JOSS review, as tests that can be run locally are considered sufficient for publication of your paper. I just wanted to throw the idea out there.

(pystarshade) maintenncesMBP6:tests ilaginja$ pwd
/Users/ilaginja/repos/PyStarshade/tests
(pystarshade) maintenncesMBP6:tests ilaginja$ pytest .
============================= test session starts ==============================
platform darwin -- Python 3.13.3, pytest-8.3.5, pluggy-1.5.0
rootdir: /Users/ilaginja/repos/PyStarshade
plugins: anyio-4.9.0, asdf-4.1.0
collected 48 items                                                             

test_bluestein_fft.py ...............F......................                       [ 79%]
test_chunk_fft.py .........                                                             [ 97%]
test_circle.py .                                                                        [100%]

========================================== FAILURES ===========================================
_____________________ test_quad_out[63-215-159-3.3968253968253967-221-x5] _____________________

N_x = 63, N_X = 215, N_out = 159, Z_pad = 3.3968253968253967, N_chirp = 221
x = array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
    ...., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]], shape=(215, 215))

    @pytest.mark.parametrize("N_x, N_X, N_out, Z_pad, N_chirp, x", test_data[:8])
    def test_quad_out(N_x, N_X, N_out, Z_pad, N_chirp, x):
        real_ft_x = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(x)))
        real_ft_quad0 = real_ft_x[N_X//2 - N_out: N_X//2, N_X//2 - N_out: N_X//2]
        real_ft_quad1 = real_ft_x[N_X//2 - N_out: N_X//2, N_X//2: N_X//2 + N_out]
        real_ft_quad2 = real_ft_x[N_X//2: N_X//2 + N_out, N_X//2 - N_out: N_X//2]
        real_ft_quad3 = real_ft_x[N_X//2: N_X//2 + N_out, N_X//2: N_X//2 + N_out]
        print (np.shape(x), np.shape(real_ft_x), N_x, N_X, N_out)
        zoom_ft_quad0 = zoom_fft_quad_out_mod(x, N_x, N_out, N_X, chunk=0)
        zoom_ft_quad1 = zoom_fft_quad_out_mod(x, N_x, N_out, N_X, chunk=1)
        zoom_ft_quad2 = zoom_fft_quad_out_mod(x, N_x, N_out, N_X, chunk=2)
        zoom_ft_quad3 = zoom_fft_quad_out_mod(x, N_x, N_out, N_X, chunk=3)
>       assert np.allclose(zoom_ft_quad0, real_ft_quad0)

test_bluestein_fft.py:88: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../opt/miniconda3/envs/pystarshade/lib/python3.13/site-packages/numpy/_core/numeric.py:2329: in allclose
    res = all(isclose(a, b, rtol=rtol, atol=atol, equal_nan=equal_nan))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

a = array([[   4.13339425+2.56856654j,    3.90889125+2.49719603j,
           2.57655273+2.42369295j, ...,    8.21946388+1.......,  466.11831   +0.22558362j,
        1801.70022152+0.07521595j, 2972.50126634-0.07521595j]],
      shape=(159, 159))
b = array([], shape=(0, 0), dtype=complex128), rtol = 1e-05, atol = 1e-08, equal_nan = False

    @array_function_dispatch(_isclose_dispatcher)
    def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
        """
        Returns a boolean array where two arrays are element-wise equal within a
        tolerance.
    
        The tolerance values are positive, typically very small numbers.  The
        relative difference (`rtol` * abs(`b`)) and the absolute difference
        `atol` are added together to compare against the absolute difference
        between `a` and `b`.
    
        .. warning:: The default `atol` is not appropriate for comparing numbers
                     with magnitudes much smaller than one (see Notes).
    
        Parameters
        ----------
        a, b : array_like
            Input arrays to compare.
        rtol : array_like
            The relative tolerance parameter (see Notes).
        atol : array_like
            The absolute tolerance parameter (see Notes).
        equal_nan : bool
            Whether to compare NaN's as equal.  If True, NaN's in `a` will be
            considered equal to NaN's in `b` in the output array.
    
        Returns
        -------
        y : array_like
            Returns a boolean array of where `a` and `b` are equal within the
            given tolerance. If both `a` and `b` are scalars, returns a single
            boolean value.
    
        See Also
        --------
        allclose
        math.isclose
    
        Notes
        -----
        For finite values, isclose uses the following equation to test whether
        two floating point values are equivalent.::
    
         absolute(a - b) <= (atol + rtol * absolute(b))
    
        Unlike the built-in `math.isclose`, the above equation is not symmetric
        in `a` and `b` -- it assumes `b` is the reference value -- so that
        `isclose(a, b)` might be different from `isclose(b, a)`.
    
        The default value of `atol` is not appropriate when the reference value
        `b` has magnitude smaller than one. For example, it is unlikely that
        ``a = 1e-9`` and ``b = 2e-9`` should be considered "close", yet
        ``isclose(1e-9, 2e-9)`` is ``True`` with default settings. Be sure
        to select `atol` for the use case at hand, especially for defining the
        threshold below which a non-zero value in `a` will be considered "close"
        to a very small or zero value in `b`.
    
        `isclose` is not defined for non-numeric data types.
        :class:`bool` is considered a numeric data-type for this purpose.
    
        Examples
        --------
        >>> import numpy as np
        >>> np.isclose([1e10,1e-7], [1.00001e10,1e-8])
        array([ True, False])
    
        >>> np.isclose([1e10,1e-8], [1.00001e10,1e-9])
        array([ True, True])
    
        >>> np.isclose([1e10,1e-8], [1.0001e10,1e-9])
        array([False,  True])
    
        >>> np.isclose([1.0, np.nan], [1.0, np.nan])
        array([ True, False])
    
        >>> np.isclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
        array([ True, True])
    
        >>> np.isclose([1e-8, 1e-7], [0.0, 0.0])
        array([ True, False])
    
        >>> np.isclose([1e-100, 1e-7], [0.0, 0.0], atol=0.0)
        array([False, False])
    
        >>> np.isclose([1e-10, 1e-10], [1e-20, 0.0])
        array([ True,  True])
    
        >>> np.isclose([1e-10, 1e-10], [1e-20, 0.999999e-10], atol=0.0)
        array([False,  True])
    
        """
        # Turn all but python scalars into arrays.
        x, y, atol, rtol = (
            a if isinstance(a, (int, float, complex)) else asanyarray(a)
            for a in (a, b, atol, rtol))
    
        # Make sure y is an inexact type to avoid bad behavior on abs(MIN_INT).
        # This will cause casting of x later. Also, make sure to allow subclasses
        # (e.g., for numpy.ma).
        # NOTE: We explicitly allow timedelta, which used to work. This could
        #       possibly be deprecated. See also gh-18286.
        #       timedelta works if `atol` is an integer or also a timedelta.
        #       Although, the default tolerances are unlikely to be useful
        if (dtype := getattr(y, "dtype", None)) is not None and dtype.kind != "m":
            dt = multiarray.result_type(y, 1.)
            y = asanyarray(y, dtype=dt)
        elif isinstance(y, int):
            y = float(y)
    
        with errstate(invalid='ignore'):
>           result = (less_equal(abs(x-y), atol + rtol * abs(y))
                      & isfinite(y)
                      | (x == y))
E           ValueError: operands could not be broadcast together with shapes (159,159) (0,0)

../../../opt/miniconda3/envs/pystarshade/lib/python3.13/site-packages/numpy/_core/numeric.py:2447: ValueError
------------------------------------ Captured stdout call -------------------------------------
(215, 215) (215, 215) 63 215 159
=================================== short test summary info ===================================
FAILED test_bluestein_fft.py::test_quad_out[63-215-159-3.3968253968253967-221-x5] - ValueError: operands could not be broadcast together with shapes (159,159) (0,0)
================================ 1 failed, 47 passed in 23.52s ================================
(pystarshade) maintenncesMBP6:tests ilaginja$ 

@xiaziyna
Copy link
Owner

xiaziyna commented May 6, 2025

Thanks for catching this.

This test is testing computing an output chunk of a DFT broken into 4 quadrants of space - it failed here because when computed with the FFT comparison case the zero-padded size N_X was less than 2*N_out (hence not enough samples to break it into 4 output quadrants and the slicing failed). I have corrected this and the tests should run successfully. I will consider setting up a Github Actions Workflow for the tests at some point in the future!

@ivalaginja
Copy link
Author

It's fixed indeed! 👍

Image

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

No branches or pull requests

2 participants