From c4746974fcb4a47900b1609cf91da7563ef40a54 Mon Sep 17 00:00:00 2001 From: Sam Van Kooten Date: Thu, 17 Aug 2023 13:29:05 -0500 Subject: [PATCH 1/2] Add modes for nan and inf handling to adaptive algo --- docs/celestial.rst | 15 +++- reproject/adaptive/core.py | 8 ++ reproject/adaptive/deforest.pyx | 76 +++++++++++++----- reproject/adaptive/high_level.py | 18 +++++ reproject/adaptive/tests/test_core.py | 108 +++++++++++++++++++++++++- 5 files changed, 200 insertions(+), 25 deletions(-) diff --git a/docs/celestial.rst b/docs/celestial.rst index 3aceaa256..035538515 100644 --- a/docs/celestial.rst +++ b/docs/celestial.rst @@ -173,7 +173,7 @@ integer or a string giving the order of the interpolation. Supported strings include: * ``'nearest-neighbor'``: zeroth order interpolation -* ``'bilinear'``: fisst order interpolation +* ``'bilinear'``: first order interpolation * ``'biquadratic'``: second order interpolation * ``'bicubic'``: third order interpolation @@ -279,7 +279,7 @@ image, a range of boundary modes can be applied, and this is set with the would have been assigned to the ignored samples exceeds a set fraction of the total weight across the entire sampling region, set by the ``boundary_ignore_threshold`` argument. In that case, acts as ``strict``. -* ``nearest`` --- Samples outside the input image are replaced by the nearst +* ``nearest`` --- Samples outside the input image are replaced by the nearest in-bounds input pixel. The input image can also be marked as being cyclic or periodic in the x and/or @@ -287,6 +287,17 @@ y axes with the ``x_cyclic`` and ``y_cyclic`` flags. If these are set, samples will wrap around to the opposite side of the image, ignoring the ``boundary_mode`` for that axis. +This implementation includes several options for handling ``nan`` and ``inf`` +values in the input data, set via the ``bad_val_mode`` argument: + +* ``strict`` --- Values of ``nan`` or ``inf`` in the input data are propagated + to every output value which samples them. +* ``ignore`` --- When a sampled input value is ``nan`` or ``inf``, that input + pixel is ignored (affected neither the accumulated sum of weighted samples + nor the accumulated sum of weights). +* ``constant`` --- Input values of ``nan`` and ``inf`` are replaced with a + constant value, set via the ``bad_fill_value`` argument. + Algorithm Description --------------------- diff --git a/reproject/adaptive/core.py b/reproject/adaptive/core.py index 195905b4d..b74d18ceb 100644 --- a/reproject/adaptive/core.py +++ b/reproject/adaptive/core.py @@ -45,6 +45,8 @@ def _reproject_adaptive_2d( boundary_ignore_threshold=0.5, x_cyclic=False, y_cyclic=False, + bad_val_mode="strict", + bad_fill_value=0, ): """ Reproject celestial slices from an n-d array from one WCS to another @@ -87,6 +89,10 @@ def _reproject_adaptive_2d( Threshold for 'ignore_threshold' boundary mode, ranging from 0 to 1. x_cyclic, y_cyclic : bool Marks in input-image axis as cyclic. + bad_val_mode : str + NaN and inf handling mode + bad_fill_value : float + Fill value for 'constant' bad value mode Returns ------- @@ -167,6 +173,8 @@ def _reproject_adaptive_2d( boundary_ignore_threshold=boundary_ignore_threshold, x_cyclic=x_cyclic, y_cyclic=y_cyclic, + bad_val_mode=bad_val_mode, + bad_fill_value=bad_fill_value, ) array_out.shape = shape_out diff --git a/reproject/adaptive/deforest.pyx b/reproject/adaptive/deforest.pyx index c2dd15a39..60f3b2ef6 100644 --- a/reproject/adaptive/deforest.pyx +++ b/reproject/adaptive/deforest.pyx @@ -43,6 +43,7 @@ cdef double nan = np.nan cdef extern from "math.h": int isnan(double x) nogil + int isinf(double x) nogil @cython.boundscheck(False) @@ -134,6 +135,12 @@ cdef double gaussian_filter(double x, double y, double width) nogil: @cython.cdivision(True) cdef double clip(double x, double vmin, double vmax, int cyclic, int out_of_range_nearest) nogil: + """Applies bounary conditions to an intended array coordinate. + + Specifically, if the point is outside the array bounds, this function wraps + the coordinate if the boundary is periodic, or clamps to the nearest valid + coordinate if desired, or else returns NaN. + """ if x < vmin: if cyclic: while x < vmin: @@ -164,6 +171,8 @@ cdef bint sample_array(double[:,:,:] source, double[:] dest, y = clip(y, 0, source.shape[1] - 1, y_cyclic, out_of_range_nearest) if isnan(x) or isnan(y): + # Indicates the coordinate is outside the array's bounds and the + # boundary-handling mode doesn't provide an alternative coordinate. return False # Cython doesn't like a return type of (double[:], bint), so we put the @@ -343,6 +352,10 @@ BOUNDARY_MODES['ignore'] = 4 BOUNDARY_MODES['ignore_threshold'] = 5 BOUNDARY_MODES['nearest'] = 6 +BAD_VAL_MODES = {} +BAD_VAL_MODES['strict'] = 1 +BAD_VAL_MODES['constant'] = 2 +BAD_VAL_MODES['ignore'] = 3 @cython.boundscheck(False) @cython.wraparound(False) @@ -355,6 +368,7 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp str kernel='gaussian', double kernel_width=1.3, double sample_region_width=4, str boundary_mode="strict", double boundary_fill_value=0, double boundary_ignore_threshold=0.5, + str bad_val_mode="strict", double bad_fill_value=0, ): # n.b. the source and target arrays are expected to contain three # dimensions---the last two are the image dimensions, while the first @@ -375,6 +389,13 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp raise ValueError( f"boundary_mode '{boundary_mode}' not recognized") from None + cdef int bad_val_flag + try: + bad_val_flag = BAD_VAL_MODES[bad_val_mode.lower()] + except KeyError: + raise ValueError( + f"bad_val_mode '{bad_val_mode}' not recognized") from None + cdef np.ndarray[np.float64_t, ndim=3] pixel_target cdef int delta if center_jacobian: @@ -477,7 +498,7 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp cdef double[:] transformed = np.zeros((2,)) cdef double[:] current_pixel_source = np.zeros((2,)) cdef double[:] current_offset = np.zeros((2,)) - cdef double weight_sum + cdef double[:] weight_sum = np.empty(source.shape[0]) cdef double ignored_weight_sum cdef double weight cdef double[:] value = np.empty(source.shape[0]) @@ -488,7 +509,7 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp cdef double top, bottom, left, right cdef double determinant cdef bint has_sampled_this_row - cdef bint is_good_sample + cdef bint sample_in_bounds with nogil: # Iterate through each pixel in the output image. for yi in range(target.shape[1]): @@ -572,12 +593,19 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp if singularities_nan: target[:,yi,xi] = nan else: - is_good_sample = sample_array( + sample_in_bounds = sample_array( source, value, current_pixel_source[0], current_pixel_source[1], x_cyclic, y_cyclic, out_of_range_nearest=boundary_flag == 6) - if is_good_sample: - target[:,yi,xi] = value + if sample_in_bounds: + for i in range(target.shape[0]): + if bad_val_flag != 1 and (isnan(value[i]) or isinf(value[i])): + if bad_val_flag == 2: + target[i,yi,xi] = bad_fill_value + else: + target[i,yi,xi] = nan + else: + target[i,yi,xi] = value[i] elif boundary_flag == 2 or boundary_flag == 3: target[:,yi,xi] = boundary_fill_value else: @@ -657,7 +685,7 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp top = bottom target[:,yi,xi] = 0 - weight_sum = 0 + weight_sum[:] = 0 ignored_weight_sum = 0 # Iterate through that bounding box in the input image. @@ -704,35 +732,41 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp continue has_sampled_this_row = True - is_good_sample = sample_array( + sample_in_bounds = sample_array( source, value, current_pixel_source[0], current_pixel_source[1], x_cyclic, y_cyclic, out_of_range_nearest=(boundary_flag == 6)) if ((boundary_flag == 2 or boundary_flag == 3) - and not is_good_sample): + and not sample_in_bounds): value[:] = boundary_fill_value - is_good_sample = True + sample_in_bounds = True - if is_good_sample: + if sample_in_bounds: for i in range(target.shape[0]): + if bad_val_flag != 1 and (isnan(value[i]) or isinf(value[i])): + if bad_val_flag == 2: + value[i] = bad_fill_value + else: + # bad_val_flag is 3: 'ignore' + continue target[i,yi,xi] += weight * value[i] - weight_sum += weight + weight_sum[i] += weight else: if boundary_flag == 5: ignored_weight_sum += weight - if (boundary_flag == 5 and - ignored_weight_sum / (ignored_weight_sum + weight_sum) - > boundary_ignore_threshold): - target[:,yi,xi] = nan - else: - if conserve_flux: - determinant = fabs(det2x2(Ji)) + if boundary_flag == 5: for i in range(target.shape[0]): - target[i,yi,xi] /= weight_sum - if conserve_flux: - target[i,yi,xi] *= determinant + if (ignored_weight_sum / (ignored_weight_sum + weight_sum[i]) + > boundary_ignore_threshold): + target[i,yi,xi] = nan + if conserve_flux: + determinant = fabs(det2x2(Ji)) + for i in range(target.shape[0]): + target[i,yi,xi] /= weight_sum[i] + if conserve_flux: + target[i,yi,xi] *= determinant if progress: with gil: sys.stdout.write("\r%d/%d done" % (yi+1, target.shape[1])) diff --git a/reproject/adaptive/high_level.py b/reproject/adaptive/high_level.py index 85d18b9a2..347a9413f 100644 --- a/reproject/adaptive/high_level.py +++ b/reproject/adaptive/high_level.py @@ -30,6 +30,8 @@ def reproject_adaptive( boundary_ignore_threshold=0.5, x_cyclic=False, y_cyclic=False, + bad_val_mode="strict", + bad_fill_value=0, ): """ Reproject a 2D array from one WCS to another using the DeForest (2004) @@ -169,6 +171,20 @@ def reproject_adaptive( Indicates that the x or y axis of the input image should be treated as cyclic or periodic. Overrides the boundary mode for that axis, so that out-of-bounds samples wrap to the other side of the image. + bad_val_mode : str + How to handle values of ``nan`` and ``inf`` in the input data. The + default is ``strct``. Allowed values are: + + * ``strict`` --- Values of ``nan`` or ``inf`` in the input data are + propagated to every output value which samples them. + * ``ignore`` --- When a sampled input value is ``nan`` or ``inf``, + that input pixel is ignored (affected neither the accumulated sum + of weighted samples nor the accumulated sum of weights). + * ``constant`` --- Input values of ``nan`` and ``inf`` are replaced + with a constant value, set via the ``bad_fill_value`` argument. + + bad_fill_value : double + The constant value used by the ``constant`` bad-value mode. Returns ------- @@ -211,6 +227,8 @@ def reproject_adaptive( boundary_ignore_threshold=boundary_ignore_threshold, x_cyclic=x_cyclic, y_cyclic=y_cyclic, + bad_val_mode=bad_val_mode, + bad_fill_value=bad_fill_value, ), return_type=return_type, ) diff --git a/reproject/adaptive/tests/test_core.py b/reproject/adaptive/tests/test_core.py index e4f578cea..2ea9bd4ed 100644 --- a/reproject/adaptive/tests/test_core.py +++ b/reproject/adaptive/tests/test_core.py @@ -679,6 +679,90 @@ def test_boundary_modes(x_cyclic, y_cyclic, rotated): assert not np.any(np.isnan(data_out)) +@pytest.mark.parametrize("bad_val", (np.nan, np.inf)) +def test_bad_val_modes(bad_val): + bad_val_checker = np.isnan if np.isnan(bad_val) else np.isinf + data_in = np.ones((30, 30)) + data_in[15, 15] = bad_val + + wcs_in = WCS(naxis=2) + wcs_in.wcs.crpix = [15.5, 15.5] + wcs_in.wcs.crval = [0, 0] + wcs_in.wcs.cdelt = [1, 1] + + # Our reprojection will be a no-op, so it's easy to reason about what + # should happen + wcs_out = wcs_in.deepcopy() + + data_out = reproject_adaptive( + (data_in, wcs_in), + wcs_out, + shape_out=(30, 30), + return_footprint=False, + boundary_mode="ignore", + sample_region_width=3, + bad_val_mode="strict", + ) + + # With a sample_region_width of 3, we expect a 3x3 box of nans centered on + # the input-image nan. + assert np.all(bad_val_checker(data_out[14:17, 14:17])) + # And they should be the only nans + assert np.sum(bad_val_checker(data_out)) == 9 + + data_out = reproject_adaptive( + (data_in, wcs_in), + wcs_out, + shape_out=(30, 30), + return_footprint=False, + boundary_mode="ignore", + sample_region_width=3, + bad_val_mode="constant", + bad_fill_value=10, + ) + + # Now, where there were nans, we should get values > 1, since 10 is our + # fill value. + assert np.all(data_out[14:17, 14:17] > 1) + data_out[14:17, 14:17] = 1 + np.testing.assert_equal(data_out, 1) + + data_out = reproject_adaptive( + (data_in, wcs_in), + wcs_out, + shape_out=(30, 30), + return_footprint=False, + boundary_mode="ignore", + sample_region_width=3, + bad_val_mode="ignore", + ) + + # Now the nan should be ignored and we should only get 1s coming out + np.testing.assert_equal(data_out, 1) + + +def test_invald_bad_val_mode(): + data_in = np.ones((30, 30)) + + wcs_in = WCS(naxis=2) + wcs_in.wcs.crpix = [15.5, 15.5] + wcs_in.wcs.crval = [0, 0] + wcs_in.wcs.cdelt = [1, 1] + + wcs_out = wcs_in.deepcopy() + + with pytest.raises(ValueError, match="bad_val_mode 'invalid_mode' not recognized"): + reproject_adaptive( + (data_in, wcs_in), + wcs_out, + shape_out=(30, 30), + return_footprint=False, + boundary_mode="ignore", + sample_region_width=3, + bad_val_mode="invalid_mode", + ) + + def prepare_test_data(file_format): pytest.importorskip("sunpy", minversion="2.1.0") from sunpy.coordinates.ephemeris import get_body_heliographic_stonyhurst @@ -757,7 +841,11 @@ def test_reproject_adaptive_uncentered_jacobian(): def _setup_for_broadcast_test( - conserve_flux=False, boundary_mode="strict", kernel="gaussian", center_jacobian=False + conserve_flux=False, + boundary_mode="strict", + kernel="gaussian", + center_jacobian=False, + bad_val_mode="strict", ): with fits.open(get_pkg_data_filename("data/galactic_2d.fits", package="reproject.tests")) as pf: hdu_in = pf[0] @@ -772,6 +860,10 @@ def _setup_for_broadcast_test( image_stack = np.stack((data, data.T, data[::-1], data[:, ::-1])) + # Ensure we exercise the bad-value handling modes + image_stack[1, 30, 30] = np.nan + image_stack[2, 20, 40] = np.inf + # Build the reference array through un-broadcast reprojections array_ref = np.empty_like(image_stack) footprint_ref = np.empty_like(image_stack) @@ -783,6 +875,7 @@ def _setup_for_broadcast_test( boundary_mode=boundary_mode, kernel=kernel, center_jacobian=center_jacobian, + bad_val_mode=bad_val_mode, ) array_ref[i] = array_out footprint_ref[i] = footprint_out @@ -833,13 +926,18 @@ def test_broadcast_reprojection(input_extra_dims, output_shape, input_as_wcs, ou def _test_broadcast_reprojection_algo_specific_options( - conserve_flux=False, boundary_mode="strict", kernel="gaussian", center_jacobian=False + conserve_flux=False, + boundary_mode="strict", + kernel="gaussian", + center_jacobian=False, + bad_val_mode="strict", ): image_stack, array_ref, footprint_ref, header_in, header_out = _setup_for_broadcast_test( conserve_flux=conserve_flux, boundary_mode=boundary_mode, kernel=kernel, center_jacobian=center_jacobian, + bad_val_mode=bad_val_mode, ) array_broadcast, footprint_broadcast = reproject_adaptive( @@ -850,6 +948,7 @@ def _test_broadcast_reprojection_algo_specific_options( boundary_mode=boundary_mode, kernel=kernel, center_jacobian=center_jacobian, + bad_val_mode=bad_val_mode, ) np.testing.assert_array_equal(footprint_broadcast, footprint_ref) @@ -879,6 +978,11 @@ def test_broadcast_reprojection_center_jacobian(center_jacobian): _test_broadcast_reprojection_algo_specific_options(center_jacobian=center_jacobian) +@pytest.mark.parametrize("bad_val_mode", ("strict", "ignore", "constant")) +def test_broadcast_reprojection_bad_val_mode(bad_val_mode): + _test_broadcast_reprojection_algo_specific_options(bad_val_mode=bad_val_mode) + + def test_adaptive_input_output_types( valid_celestial_input_data, valid_celestial_output_projections ): From a4312de81b0429a8363486f0913a31373f824cd5 Mon Sep 17 00:00:00 2001 From: Thomas Robitaille Date: Thu, 7 Sep 2023 10:53:42 +0100 Subject: [PATCH 2/2] Rename bad_val_mode to bad_value_mode --- docs/celestial.rst | 2 +- reproject/adaptive/core.py | 6 +++--- reproject/adaptive/deforest.pyx | 14 ++++++------- reproject/adaptive/high_level.py | 6 +++--- reproject/adaptive/tests/test_core.py | 30 +++++++++++++-------------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/celestial.rst b/docs/celestial.rst index 035538515..20c6f6528 100644 --- a/docs/celestial.rst +++ b/docs/celestial.rst @@ -288,7 +288,7 @@ will wrap around to the opposite side of the image, ignoring the ``boundary_mode`` for that axis. This implementation includes several options for handling ``nan`` and ``inf`` -values in the input data, set via the ``bad_val_mode`` argument: +values in the input data, set via the ``bad_value_mode`` argument: * ``strict`` --- Values of ``nan`` or ``inf`` in the input data are propagated to every output value which samples them. diff --git a/reproject/adaptive/core.py b/reproject/adaptive/core.py index b74d18ceb..d09f2257d 100644 --- a/reproject/adaptive/core.py +++ b/reproject/adaptive/core.py @@ -45,7 +45,7 @@ def _reproject_adaptive_2d( boundary_ignore_threshold=0.5, x_cyclic=False, y_cyclic=False, - bad_val_mode="strict", + bad_value_mode="strict", bad_fill_value=0, ): """ @@ -89,7 +89,7 @@ def _reproject_adaptive_2d( Threshold for 'ignore_threshold' boundary mode, ranging from 0 to 1. x_cyclic, y_cyclic : bool Marks in input-image axis as cyclic. - bad_val_mode : str + bad_value_mode : str NaN and inf handling mode bad_fill_value : float Fill value for 'constant' bad value mode @@ -173,7 +173,7 @@ def _reproject_adaptive_2d( boundary_ignore_threshold=boundary_ignore_threshold, x_cyclic=x_cyclic, y_cyclic=y_cyclic, - bad_val_mode=bad_val_mode, + bad_value_mode=bad_value_mode, bad_fill_value=bad_fill_value, ) diff --git a/reproject/adaptive/deforest.pyx b/reproject/adaptive/deforest.pyx index 60f3b2ef6..4af8c56d7 100644 --- a/reproject/adaptive/deforest.pyx +++ b/reproject/adaptive/deforest.pyx @@ -352,10 +352,10 @@ BOUNDARY_MODES['ignore'] = 4 BOUNDARY_MODES['ignore_threshold'] = 5 BOUNDARY_MODES['nearest'] = 6 -BAD_VAL_MODES = {} -BAD_VAL_MODES['strict'] = 1 -BAD_VAL_MODES['constant'] = 2 -BAD_VAL_MODES['ignore'] = 3 +BAD_VALUE_MODES = {} +BAD_VALUE_MODES['strict'] = 1 +BAD_VALUE_MODES['constant'] = 2 +BAD_VALUE_MODES['ignore'] = 3 @cython.boundscheck(False) @cython.wraparound(False) @@ -368,7 +368,7 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp str kernel='gaussian', double kernel_width=1.3, double sample_region_width=4, str boundary_mode="strict", double boundary_fill_value=0, double boundary_ignore_threshold=0.5, - str bad_val_mode="strict", double bad_fill_value=0, + str bad_value_mode="strict", double bad_fill_value=0, ): # n.b. the source and target arrays are expected to contain three # dimensions---the last two are the image dimensions, while the first @@ -391,10 +391,10 @@ def map_coordinates(double[:,:,:] source, double[:,:,:] target, Ci, int max_samp cdef int bad_val_flag try: - bad_val_flag = BAD_VAL_MODES[bad_val_mode.lower()] + bad_val_flag = BAD_VALUE_MODES[bad_value_mode.lower()] except KeyError: raise ValueError( - f"bad_val_mode '{bad_val_mode}' not recognized") from None + f"bad_value_mode '{bad_value_mode}' not recognized") from None cdef np.ndarray[np.float64_t, ndim=3] pixel_target cdef int delta diff --git a/reproject/adaptive/high_level.py b/reproject/adaptive/high_level.py index 347a9413f..fe25c4784 100644 --- a/reproject/adaptive/high_level.py +++ b/reproject/adaptive/high_level.py @@ -30,7 +30,7 @@ def reproject_adaptive( boundary_ignore_threshold=0.5, x_cyclic=False, y_cyclic=False, - bad_val_mode="strict", + bad_value_mode="strict", bad_fill_value=0, ): """ @@ -171,7 +171,7 @@ def reproject_adaptive( Indicates that the x or y axis of the input image should be treated as cyclic or periodic. Overrides the boundary mode for that axis, so that out-of-bounds samples wrap to the other side of the image. - bad_val_mode : str + bad_value_mode : str How to handle values of ``nan`` and ``inf`` in the input data. The default is ``strct``. Allowed values are: @@ -227,7 +227,7 @@ def reproject_adaptive( boundary_ignore_threshold=boundary_ignore_threshold, x_cyclic=x_cyclic, y_cyclic=y_cyclic, - bad_val_mode=bad_val_mode, + bad_value_mode=bad_value_mode, bad_fill_value=bad_fill_value, ), return_type=return_type, diff --git a/reproject/adaptive/tests/test_core.py b/reproject/adaptive/tests/test_core.py index 2ea9bd4ed..9eaa56884 100644 --- a/reproject/adaptive/tests/test_core.py +++ b/reproject/adaptive/tests/test_core.py @@ -680,7 +680,7 @@ def test_boundary_modes(x_cyclic, y_cyclic, rotated): @pytest.mark.parametrize("bad_val", (np.nan, np.inf)) -def test_bad_val_modes(bad_val): +def test_bad_value_modes(bad_val): bad_val_checker = np.isnan if np.isnan(bad_val) else np.isinf data_in = np.ones((30, 30)) data_in[15, 15] = bad_val @@ -701,7 +701,7 @@ def test_bad_val_modes(bad_val): return_footprint=False, boundary_mode="ignore", sample_region_width=3, - bad_val_mode="strict", + bad_value_mode="strict", ) # With a sample_region_width of 3, we expect a 3x3 box of nans centered on @@ -717,7 +717,7 @@ def test_bad_val_modes(bad_val): return_footprint=False, boundary_mode="ignore", sample_region_width=3, - bad_val_mode="constant", + bad_value_mode="constant", bad_fill_value=10, ) @@ -734,14 +734,14 @@ def test_bad_val_modes(bad_val): return_footprint=False, boundary_mode="ignore", sample_region_width=3, - bad_val_mode="ignore", + bad_value_mode="ignore", ) # Now the nan should be ignored and we should only get 1s coming out np.testing.assert_equal(data_out, 1) -def test_invald_bad_val_mode(): +def test_invald_bad_value_mode(): data_in = np.ones((30, 30)) wcs_in = WCS(naxis=2) @@ -751,7 +751,7 @@ def test_invald_bad_val_mode(): wcs_out = wcs_in.deepcopy() - with pytest.raises(ValueError, match="bad_val_mode 'invalid_mode' not recognized"): + with pytest.raises(ValueError, match="bad_value_mode 'invalid_mode' not recognized"): reproject_adaptive( (data_in, wcs_in), wcs_out, @@ -759,7 +759,7 @@ def test_invald_bad_val_mode(): return_footprint=False, boundary_mode="ignore", sample_region_width=3, - bad_val_mode="invalid_mode", + bad_value_mode="invalid_mode", ) @@ -845,7 +845,7 @@ def _setup_for_broadcast_test( boundary_mode="strict", kernel="gaussian", center_jacobian=False, - bad_val_mode="strict", + bad_value_mode="strict", ): with fits.open(get_pkg_data_filename("data/galactic_2d.fits", package="reproject.tests")) as pf: hdu_in = pf[0] @@ -875,7 +875,7 @@ def _setup_for_broadcast_test( boundary_mode=boundary_mode, kernel=kernel, center_jacobian=center_jacobian, - bad_val_mode=bad_val_mode, + bad_value_mode=bad_value_mode, ) array_ref[i] = array_out footprint_ref[i] = footprint_out @@ -930,14 +930,14 @@ def _test_broadcast_reprojection_algo_specific_options( boundary_mode="strict", kernel="gaussian", center_jacobian=False, - bad_val_mode="strict", + bad_value_mode="strict", ): image_stack, array_ref, footprint_ref, header_in, header_out = _setup_for_broadcast_test( conserve_flux=conserve_flux, boundary_mode=boundary_mode, kernel=kernel, center_jacobian=center_jacobian, - bad_val_mode=bad_val_mode, + bad_value_mode=bad_value_mode, ) array_broadcast, footprint_broadcast = reproject_adaptive( @@ -948,7 +948,7 @@ def _test_broadcast_reprojection_algo_specific_options( boundary_mode=boundary_mode, kernel=kernel, center_jacobian=center_jacobian, - bad_val_mode=bad_val_mode, + bad_value_mode=bad_value_mode, ) np.testing.assert_array_equal(footprint_broadcast, footprint_ref) @@ -978,9 +978,9 @@ def test_broadcast_reprojection_center_jacobian(center_jacobian): _test_broadcast_reprojection_algo_specific_options(center_jacobian=center_jacobian) -@pytest.mark.parametrize("bad_val_mode", ("strict", "ignore", "constant")) -def test_broadcast_reprojection_bad_val_mode(bad_val_mode): - _test_broadcast_reprojection_algo_specific_options(bad_val_mode=bad_val_mode) +@pytest.mark.parametrize("bad_value_mode", ("strict", "ignore", "constant")) +def test_broadcast_reprojection_bad_value_mode(bad_value_mode): + _test_broadcast_reprojection_algo_specific_options(bad_value_mode=bad_value_mode) def test_adaptive_input_output_types(