From ad63436dd508b4e41ac772d6addbbd294d057917 Mon Sep 17 00:00:00 2001 From: Brett Date: Tue, 9 Jul 2024 10:13:04 -0400 Subject: [PATCH] change back to old abs_deriv --- src/stcal/outlier_detection/utils.py | 28 +++++++++++++++++++++++++-- tests/outlier_detection/test_utils.py | 16 +++++++++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/stcal/outlier_detection/utils.py b/src/stcal/outlier_detection/utils.py index 638f8790d..036823f28 100644 --- a/src/stcal/outlier_detection/utils.py +++ b/src/stcal/outlier_detection/utils.py @@ -73,9 +73,33 @@ def compute_weight_threshold(weight, maskpt): return weight_threshold -def _abs_deriv(array): +def _valid_abs_deriv(array): """Take the absolute derivate of a numpy array.""" - # TODO is there a more efficient way to do this? + out = np.zeros_like(array) # use same dtype as input + + # compute row-wise absolute diffference + d = np.abs(np.diff(array, axis=0)) + out[1:] = d # no need to do max yet + # since these are absolute differences |r0-r1| = |r1-r0| + # make a view of the target portion of the array + v = out[:-1] + # compute an in-place maximum + np.putmask(v, d > v, d) + + # compute col-wise absolute difference + d = np.abs(np.diff(array, axis=1)) + v = out[:, 1:] + np.putmask(v, d > v, d) + v = out[:, :-1] + np.putmask(v, d > v, d) + return out + + +def _abs_deriv(array): + # FIXME this assumes off-edge pixels are 0 + # FIXME this upcasts to float64 + # FIXME _valid_abs_deriv fixes the above issues and is more efficient + # but fixing the bugs will likely change the output tmp = np.zeros(array.shape, dtype=np.float64) out = np.zeros(array.shape, dtype=np.float64) diff --git a/tests/outlier_detection/test_utils.py b/tests/outlier_detection/test_utils.py index c35222487..6e0302119 100644 --- a/tests/outlier_detection/test_utils.py +++ b/tests/outlier_detection/test_utils.py @@ -12,20 +12,28 @@ @pytest.mark.parametrize("shape,diff", [ - ([5, 5], 100), - ([7, 7], 200), + ([5, 7], 100), + ([17, 13], -200), ]) -def test_abs_deriv(shape, diff): +def test_abs_deriv_single_value(shape, diff): arr = np.zeros(shape) # put diff at the center np.put(arr, arr.size // 2, diff) # since abs_deriv with a single non-zero value is the same as a # convolution with a 3x3 cross kernel use it to test the result - expected = scipy.signal.convolve2d(arr, [[0, 1, 0], [1, 1, 1], [0, 1, 0]], mode='same') + expected = scipy.signal.convolve2d(np.abs(arr), [[0, 1, 0], [1, 1, 1], [0, 1, 0]], mode='same') result = _abs_deriv(arr) np.testing.assert_allclose(result, expected) +@pytest.mark.skip(reason="_abs_deriv has edge effects due to treating off-edge pixels as 0") +@pytest.mark.parametrize("nrows,ncols", [(5, 5), (7, 11), (17, 13)]) +def test_abs_deriv_range(nrows, ncols): + arr = np.arange(nrows * ncols).reshape(nrows, ncols) + result = _abs_deriv(arr) + np.testing.assert_allclose(result, ncols) + + @pytest.mark.parametrize("shape,mean,maskpt,expected", [ ([5, 5], 11, 0.5, 5.5), ([5, 5], 11, 0.25, 2.75),