From 99df4787e52fdb3f26be972bd22244363f21f03b Mon Sep 17 00:00:00 2001 From: Arun Kannawadi Date: Fri, 6 Sep 2024 16:22:23 -0400 Subject: [PATCH 1/6] Introduce a flipXY config field --- python/lsst/meas/algorithms/cloughTocher2DInterpolator.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py b/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py index 92aa1d6d7..960ea2773 100644 --- a/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py +++ b/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py @@ -51,6 +51,13 @@ class CloughTocher2DInterpolateConfig(Config): default=4, check=lambda x: x >= 1, ) + flipXY = Field[bool]( + doc="Whether to flip the x and y coordinates before constructing the " + "Delaunay triangulation. This may produce a slightly different result " + "since the triangulation is not guaranteed to be invariant under " + "coordinate flips.", + default=False, + ) class CloughTocher2DInterpolateTask(Task): From a9d7c8aebbe57ebbb90228544768ce25c49a6662 Mon Sep 17 00:00:00 2001 From: Arun Kannawadi Date: Fri, 6 Sep 2024 16:22:47 -0400 Subject: [PATCH 2/6] Change ordering depending on flipXY --- .../meas/algorithms/cloughTocher2DInterpolator.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py b/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py index 960ea2773..03fe8cae9 100644 --- a/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py +++ b/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py @@ -136,14 +136,21 @@ def run( ctUtils.updateArrayFromImage(goodpix, maskedImage.image) # Construct the interpolant with goodpix. + if self.config.flipXY: + anchor_points = list(zip(goodpix[:, 1], goodpix[:, 0])) + query_points = badpix[:, 1::-1] + else: + anchor_points = list(zip(goodpix[:, 0], goodpix[:, 1])) + query_points = badpix[:, :2] + interpolator = CloughTocher2DInterpolator( - list(zip(goodpix[:, 0], goodpix[:, 1])), + anchor_points, goodpix[:, 2], fill_value=self.config.fillValue, ) # Compute the interpolated values at bad pixel locations. - badpix[:, 2] = interpolator(badpix[:, :2]) + badpix[:, 2] = interpolator(query_points) # Fill in the bad pixels. ctUtils.updateImageFromArray(maskedImage.image, badpix) From 942c665d56196e435a2bd2c594eac3c60af42084 Mon Sep 17 00:00:00 2001 From: Arun Kannawadi Date: Fri, 6 Sep 2024 16:36:42 -0400 Subject: [PATCH 3/6] Add more SAT pixels for unit tests --- tests/test_cloughTocher2DInterpolate.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_cloughTocher2DInterpolate.py b/tests/test_cloughTocher2DInterpolate.py index d507a3733..a1e4aa091 100644 --- a/tests/test_cloughTocher2DInterpolate.py +++ b/tests/test_cloughTocher2DInterpolate.py @@ -63,6 +63,14 @@ def setUp(self): self.maskedimage.mask[:, 110:111] = afwImage.Mask.getPlaneBitMask("BAD") self.maskedimage.image[:, 110:111] = np.nan + # Set an asymmetric region as BAD + self.maskedimage.mask[41:42, 63:66] = afwImage.Mask.getPlaneBitMask("SAT") + self.maskedimage.image[41:42, 63:66] = np.nan + self.maskedimage.mask[42:43, 63:65] = afwImage.Mask.getPlaneBitMask("SAT") + self.maskedimage.image[42:43, 63:65] = np.nan + self.maskedimage.mask[44, 63] = afwImage.Mask.getPlaneBitMask("SAT") + self.maskedimage.image[44, 63] = np.nan + # Set a diagonal set of pixels as CR for i in range(74, 78): self.maskedimage.mask[i, i] = afwImage.Mask.getPlaneBitMask("CR") From 7415e8b6f2afd0f8722ee223960ccf9087875a1e Mon Sep 17 00:00:00 2001 From: Arun Kannawadi Date: Mon, 9 Sep 2024 10:29:13 -0400 Subject: [PATCH 4/6] Add flipXY arguments to existing tests --- tests/test_cloughTocher2DInterpolate.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/test_cloughTocher2DInterpolate.py b/tests/test_cloughTocher2DInterpolate.py index a1e4aa091..77aa52fe2 100644 --- a/tests/test_cloughTocher2DInterpolate.py +++ b/tests/test_cloughTocher2DInterpolate.py @@ -93,8 +93,8 @@ def setUp(self): np.random.seed(12345) self.noise.image.array[:, :] = np.random.normal(size=self.noise.image.array.shape) - @lsst.utils.tests.methodParameters(n_runs=(1, 2)) - def test_interpolation(self, n_runs: int): + @lsst.utils.tests.methodParametersProduct(n_runs=(1, 2), flipXY=(False, True)) + def test_interpolation(self, n_runs: int, flipXY: bool): """Test that the interpolation is done correctly. Parameters @@ -102,6 +102,8 @@ def test_interpolation(self, n_runs: int): n_runs : `int` Number of times to run the task. Running the task more than once should have no effect. + flipXY : `bool` + Whether to set the flipXY config parameter to True. """ config = CloughTocher2DInterpolateTask.ConfigClass() config.badMaskPlanes = ( @@ -111,6 +113,7 @@ def test_interpolation(self, n_runs: int): "EDGE", ) config.fillValue = 0.5 + config.flipXY = flipXY task = CloughTocher2DInterpolateTask(config) for n in range(n_runs): task.run(self.maskedimage) @@ -135,8 +138,14 @@ def test_interpolation(self, n_runs: int): atol=1e-08, ) - @lsst.utils.tests.methodParametersProduct(pass_badpix=(True, False), pass_goodpix=(True, False)) - def test_interpolation_with_noise(self, pass_badpix: bool = True, pass_goodpix: bool = True): + @lsst.utils.tests.methodParametersProduct( + pass_badpix=(True, False), + pass_goodpix=(True, False), + flipXY=(False, True), + ) + def test_interpolation_with_noise( + self, pass_badpix: bool = True, pass_goodpix: bool = True, flipXY: bool = False + ): """Test that we can reuse the badpix and goodpix. Parameters @@ -145,9 +154,12 @@ def test_interpolation_with_noise(self, pass_badpix: bool = True, pass_goodpix: Whether to pass the badpix to the task? pass_goodpix : `bool` Whether to pass the goodpix to the task? + flipXY : `bool` + Whether to set the flipXY config parameter to True. """ config = CloughTocher2DInterpolateTask.ConfigClass() + config.flipXY = flipXY config.badMaskPlanes = ( "BAD", "SAT", From 7b8d789c5350f9cd914d344d4b4fb5b1570f8b9f Mon Sep 17 00:00:00 2001 From: Arun Kannawadi Date: Mon, 9 Sep 2024 10:31:31 -0400 Subject: [PATCH 5/6] Add a new unit test to check flipXY parity --- tests/test_cloughTocher2DInterpolate.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test_cloughTocher2DInterpolate.py b/tests/test_cloughTocher2DInterpolate.py index 77aa52fe2..75c2be468 100644 --- a/tests/test_cloughTocher2DInterpolate.py +++ b/tests/test_cloughTocher2DInterpolate.py @@ -191,6 +191,31 @@ def test_interpolation_with_noise( atol=1e-08, ) + def test_interpolation_with_flipXY(self): + """Test that the interpolation with both values for flipXY.""" + config = CloughTocher2DInterpolateTask.ConfigClass() + config.badMaskPlanes = ( + "BAD", + "SAT", + "CR", + "EDGE", + ) + config.flipXY = True + task = CloughTocher2DInterpolateTask(config) + badpix_true, goodpix_true = task.run(self.maskedimage) + + config.flipXY = False + task = CloughTocher2DInterpolateTask(config) + badpix_false, goodpix_false = task.run(self.maskedimage) + + # Check that the locations of the bad and the good pixels, and the good + # pixel values themselves are identical. + np.testing.assert_array_equal(goodpix_false, goodpix_true) + np.testing.assert_array_equal(badpix_false[:, :2], badpix_true[:, :2]) + + # Check that the interpolated values at at least approximately equal. + np.testing.assert_array_equal(badpix_false[:, 2], badpix_true[:, 2]) + class CloughTocher2DInterpolatorUtilsTestCase(CloughTocher2DInterpolateTestCase): """Test the CloughTocher2DInterpolatorUtils.""" From 39d1079ff7597191bbbc7b25b7d4d27957fa8ce5 Mon Sep 17 00:00:00 2001 From: Arun Kannawadi Date: Mon, 9 Sep 2024 10:32:23 -0400 Subject: [PATCH 6/6] Default flipXY to True --- python/lsst/meas/algorithms/cloughTocher2DInterpolator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py b/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py index 03fe8cae9..ce8e1664a 100644 --- a/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py +++ b/python/lsst/meas/algorithms/cloughTocher2DInterpolator.py @@ -56,7 +56,7 @@ class CloughTocher2DInterpolateConfig(Config): "Delaunay triangulation. This may produce a slightly different result " "since the triangulation is not guaranteed to be invariant under " "coordinate flips.", - default=False, + default=True, )