diff --git a/python/lsst/ip/diffim/getTemplate.py b/python/lsst/ip/diffim/getTemplate.py index bab20f28..2b95aa73 100644 --- a/python/lsst/ip/diffim/getTemplate.py +++ b/python/lsst/ip/diffim/getTemplate.py @@ -384,6 +384,9 @@ def _merge(self, maskedImages, bbox, wcs): maskedImage.image *= weight maskedImage.variance *= weight merged.maskedImage[maskedImage.getBBox()] += maskedImage + # Clear the NaNs to ensure that areas missing from this input are + # masked with NO_DATA after the loop. + weight.array[np.isnan(weight.array)] = 0 weights[maskedImage.getBBox()] += weight # Cannot use `merged.maskedImage /= weights` because that operator # divides the variance by the weight twice; in this case `weights` are diff --git a/tests/test_getTemplate.py b/tests/test_getTemplate.py index 979ee374..5359f428 100644 --- a/tests/test_getTemplate.py +++ b/tests/test_getTemplate.py @@ -250,6 +250,23 @@ def testRunNoTemplate(self): with self.assertRaisesRegex(lsst.pipe.base.NoWorkFound, "No patches found"): task.run(self.patches, lsst.geom.Box2I(box), self.exposure.wcs, self.dataIds, "a_test") + def testMissingPatches(self): + """Test that a missing patch results in an appropriate mask. + + This fixes the bug reported on DM-44997 (image and variance were NaN + but the mask was not set to NO_DATA for those pixels). + """ + # tract=0, patch=1 is the lower-left corner, as displayed in DS9. + self.patches[0].pop(1) + box = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Point2I(180, 180)) + task = lsst.ip.diffim.GetTemplateTask() + # Task modifies the input bbox, so pass a copy. + result = task.run(self.patches, lsst.geom.Box2I(box), self.exposure.wcs, self.dataIds, "a_test") + no_data = (result.template.mask.array & result.template.mask.getPlaneBitMask("NO_DATA")) != 0 + self.assertTrue(all(np.isnan(result.template.image.array[no_data]))) + self.assertTrue(all(np.isnan(result.template.variance.array[no_data]))) + self.assertEqual(no_data.sum(), 22118) + def setup_module(module): lsst.utils.tests.init()