Skip to content

Commit 40d01f5

Browse files
authored
Merge pull request #407 from lsst/tickets/DM-51360
DM-51360: also use template mask plane for kernel candidate selection
2 parents af1552e + afb128c commit 40d01f5

File tree

4 files changed

+49
-46
lines changed

4 files changed

+49
-46
lines changed

python/lsst/ip/diffim/makeKernel.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,11 @@ def makeCandidateList(self, convolved, reference, kernelSize,
335335
if (reference.subset(bbox).mask.array & bitmask).any():
336336
good[i] = False
337337
continue
338+
339+
# Reject footprints with any bad mask bits set.
340+
if (convolved.subset(bbox).mask.array & bitmask).any():
341+
good[i] = False
342+
continue
338343
candidates = candidateList[good].copy(deep=True)
339344

340345
self.log.info("Selected %d / %d sources as kernel candidates.", good.sum(), len(candidateList))

python/lsst/ip/diffim/subtractImages.py

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,6 @@ def _sourceSelector(self, sources, mask):
858858

859859
selected = self.sourceSelector.selectSources(sources).selected
860860
nInitialSelected = np.count_nonzero(selected)
861-
selected *= self._checkMask(mask, sources, self.config.excludeMaskPlanes)
862861
nSelected = np.count_nonzero(selected)
863862
self.log.info("Rejecting %i candidate sources: an excluded template mask plane is set.",
864863
nInitialSelected - nSelected)
@@ -885,47 +884,6 @@ def _sourceSelector(self, sources, mask):
885884

886885
return selectSources
887886

888-
@staticmethod
889-
def _checkMask(mask, sources, excludeMaskPlanes, checkAdjacent=True):
890-
"""Exclude sources that are located on or adjacent to masked pixels.
891-
892-
Parameters
893-
----------
894-
mask : `lsst.afw.image.Mask`
895-
The image mask plane to use to reject sources
896-
based on the location of their centroid on the ccd.
897-
sources : `lsst.afw.table.SourceCatalog`
898-
The source catalog to evaluate.
899-
excludeMaskPlanes : `list` of `str`
900-
List of the names of the mask planes to exclude.
901-
902-
Returns
903-
-------
904-
flags : `numpy.ndarray` of `bool`
905-
Array indicating whether each source in the catalog should be
906-
kept (True) or rejected (False) based on the value of the
907-
mask plane at its location.
908-
"""
909-
setExcludeMaskPlanes = [
910-
maskPlane for maskPlane in excludeMaskPlanes if maskPlane in mask.getMaskPlaneDict()
911-
]
912-
913-
excludePixelMask = mask.getPlaneBitMask(setExcludeMaskPlanes)
914-
915-
xv = (np.rint(sources.getX() - mask.getX0())).astype(int)
916-
yv = (np.rint(sources.getY() - mask.getY0())).astype(int)
917-
918-
flags = np.ones(len(sources), dtype=bool)
919-
if checkAdjacent:
920-
pixRange = (0, -1, 1)
921-
else:
922-
pixRange = (0,)
923-
for j in pixRange:
924-
for i in pixRange:
925-
mv = mask.array[yv + j, xv + i]
926-
flags *= np.bitwise_and(mv, excludePixelMask) == 0
927-
return flags
928-
929887
def _prepareInputs(self, template, science, visitSummary=None):
930888
"""Perform preparatory calculations common to all Alard&Lupton Tasks.
931889

tests/test_detectAndMeasure.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import lsst.utils.tests
3333
import lsst.meas.base.tests
3434

35-
from utils import makeTestImage
35+
from utils import makeTestImage, checkMask
3636

3737

3838
class DetectAndMeasureTestBase:
@@ -505,7 +505,6 @@ def test_exclude_mask_detections(self):
505505
science, sources = makeTestImage(noiseLevel=noiseLevel, noiseSeed=6, **kwargs)
506506
matchedTemplate, _ = makeTestImage(noiseLevel=noiseLevel/4, noiseSeed=7, **kwargs)
507507

508-
_checkMask = subtractImages.AlardLuptonSubtractTask._checkMask
509508
# Configure the detection Task
510509
detectionTask = self._setup_detection()
511510
excludeMaskPlanes = detectionTask.config.detection.excludeMaskPlanes
@@ -530,7 +529,7 @@ def _detection_wrapper(setFlags=True):
530529
difference[srcBbox].mask.array |= lsst.afw.image.Mask.getPlaneBitMask(badMask)
531530
output = detectionTask.run(science, matchedTemplate, difference)
532531
refIds = []
533-
goodSrcFlags = _checkMask(difference.mask, transientSources, excludeMaskPlanes)
532+
goodSrcFlags = checkMask(difference.mask, transientSources, excludeMaskPlanes)
534533
if setFlags:
535534
self.assertEqual(np.sum(~goodSrcFlags), nBad)
536535
self.assertFalse(hasattr(output, "diaSources"))
@@ -965,7 +964,7 @@ def _detection_wrapper(setFlags=True):
965964
score = subtractTask._convolveExposure(difference, scienceKernel, subtractTask.convolutionControl)
966965
output = detectionTask.run(science, matchedTemplate, difference, score)
967966
refIds = []
968-
goodSrcFlags = subtractTask._checkMask(difference.mask, transientSources, excludeMaskPlanes)
967+
goodSrcFlags = checkMask(difference.mask, transientSources, excludeMaskPlanes)
969968
if setFlags:
970969
self.assertEqual(np.sum(~goodSrcFlags), nBad)
971970
self.assertFalse(hasattr(output, "diaSources"))

tests/utils.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,3 +1219,44 @@ def generate_data_id(*,
12191219

12201220
data_id = DataCoordinate.standardize(record_id, universe=universe)
12211221
return data_id.expanded(record)
1222+
1223+
1224+
def checkMask(mask, sources, excludeMaskPlanes, checkAdjacent=True):
1225+
"""Exclude sources that are located on or adjacent to masked pixels.
1226+
1227+
Parameters
1228+
----------
1229+
mask : `lsst.afw.image.Mask`
1230+
The image mask plane to use to reject sources
1231+
based on the location of their centroid on the ccd.
1232+
sources : `lsst.afw.table.SourceCatalog`
1233+
The source catalog to evaluate.
1234+
excludeMaskPlanes : `list` of `str`
1235+
List of the names of the mask planes to exclude.
1236+
1237+
Returns
1238+
-------
1239+
flags : `numpy.ndarray` of `bool`
1240+
Array indicating whether each source in the catalog should be
1241+
kept (True) or rejected (False) based on the value of the
1242+
mask plane at its location.
1243+
"""
1244+
setExcludeMaskPlanes = [
1245+
maskPlane for maskPlane in excludeMaskPlanes if maskPlane in mask.getMaskPlaneDict()
1246+
]
1247+
1248+
excludePixelMask = mask.getPlaneBitMask(setExcludeMaskPlanes)
1249+
1250+
xv = (np.rint(sources.getX() - mask.getX0())).astype(int)
1251+
yv = (np.rint(sources.getY() - mask.getY0())).astype(int)
1252+
1253+
flags = np.ones(len(sources), dtype=bool)
1254+
if checkAdjacent:
1255+
pixRange = (0, -1, 1)
1256+
else:
1257+
pixRange = (0,)
1258+
for j in pixRange:
1259+
for i in pixRange:
1260+
mv = mask.array[yv + j, xv + i]
1261+
flags *= np.bitwise_and(mv, excludePixelMask) == 0
1262+
return flags

0 commit comments

Comments
 (0)