Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions python/lsst/ip/diffim/makeKernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,11 @@ def makeCandidateList(self, convolved, reference, kernelSize,
if (reference.subset(bbox).mask.array & bitmask).any():
good[i] = False
continue

# Reject footprints with any bad mask bits set.
if (convolved.subset(bbox).mask.array & bitmask).any():
good[i] = False
continue
candidates = candidateList[good].copy(deep=True)

self.log.info("Selected %d / %d sources as kernel candidates.", good.sum(), len(candidateList))
Expand Down
42 changes: 0 additions & 42 deletions python/lsst/ip/diffim/subtractImages.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,6 @@ def _sourceSelector(self, sources, mask):

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

return selectSources

@staticmethod
def _checkMask(mask, sources, excludeMaskPlanes, checkAdjacent=True):
"""Exclude sources that are located on or adjacent to masked pixels.

Parameters
----------
mask : `lsst.afw.image.Mask`
The image mask plane to use to reject sources
based on the location of their centroid on the ccd.
sources : `lsst.afw.table.SourceCatalog`
The source catalog to evaluate.
excludeMaskPlanes : `list` of `str`
List of the names of the mask planes to exclude.

Returns
-------
flags : `numpy.ndarray` of `bool`
Array indicating whether each source in the catalog should be
kept (True) or rejected (False) based on the value of the
mask plane at its location.
"""
setExcludeMaskPlanes = [
maskPlane for maskPlane in excludeMaskPlanes if maskPlane in mask.getMaskPlaneDict()
]

excludePixelMask = mask.getPlaneBitMask(setExcludeMaskPlanes)

xv = (np.rint(sources.getX() - mask.getX0())).astype(int)
yv = (np.rint(sources.getY() - mask.getY0())).astype(int)

flags = np.ones(len(sources), dtype=bool)
if checkAdjacent:
pixRange = (0, -1, 1)
else:
pixRange = (0,)
for j in pixRange:
for i in pixRange:
mv = mask.array[yv + j, xv + i]
flags *= np.bitwise_and(mv, excludePixelMask) == 0
return flags

def _prepareInputs(self, template, science, visitSummary=None):
"""Perform preparatory calculations common to all Alard&Lupton Tasks.

Expand Down
7 changes: 3 additions & 4 deletions tests/test_detectAndMeasure.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import lsst.utils.tests
import lsst.meas.base.tests

from utils import makeTestImage
from utils import makeTestImage, checkMask


class DetectAndMeasureTestBase:
Expand Down Expand Up @@ -505,7 +505,6 @@ def test_exclude_mask_detections(self):
science, sources = makeTestImage(noiseLevel=noiseLevel, noiseSeed=6, **kwargs)
matchedTemplate, _ = makeTestImage(noiseLevel=noiseLevel/4, noiseSeed=7, **kwargs)

_checkMask = subtractImages.AlardLuptonSubtractTask._checkMask
# Configure the detection Task
detectionTask = self._setup_detection()
excludeMaskPlanes = detectionTask.config.detection.excludeMaskPlanes
Expand All @@ -530,7 +529,7 @@ def _detection_wrapper(setFlags=True):
difference[srcBbox].mask.array |= lsst.afw.image.Mask.getPlaneBitMask(badMask)
output = detectionTask.run(science, matchedTemplate, difference)
refIds = []
goodSrcFlags = _checkMask(difference.mask, transientSources, excludeMaskPlanes)
goodSrcFlags = checkMask(difference.mask, transientSources, excludeMaskPlanes)
if setFlags:
self.assertEqual(np.sum(~goodSrcFlags), nBad)
self.assertFalse(hasattr(output, "diaSources"))
Expand Down Expand Up @@ -965,7 +964,7 @@ def _detection_wrapper(setFlags=True):
score = subtractTask._convolveExposure(difference, scienceKernel, subtractTask.convolutionControl)
output = detectionTask.run(science, matchedTemplate, difference, score)
refIds = []
goodSrcFlags = subtractTask._checkMask(difference.mask, transientSources, excludeMaskPlanes)
goodSrcFlags = checkMask(difference.mask, transientSources, excludeMaskPlanes)
if setFlags:
self.assertEqual(np.sum(~goodSrcFlags), nBad)
self.assertFalse(hasattr(output, "diaSources"))
Expand Down
41 changes: 41 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1219,3 +1219,44 @@ def generate_data_id(*,

data_id = DataCoordinate.standardize(record_id, universe=universe)
return data_id.expanded(record)


def checkMask(mask, sources, excludeMaskPlanes, checkAdjacent=True):
"""Exclude sources that are located on or adjacent to masked pixels.

Parameters
----------
mask : `lsst.afw.image.Mask`
The image mask plane to use to reject sources
based on the location of their centroid on the ccd.
sources : `lsst.afw.table.SourceCatalog`
The source catalog to evaluate.
excludeMaskPlanes : `list` of `str`
List of the names of the mask planes to exclude.

Returns
-------
flags : `numpy.ndarray` of `bool`
Array indicating whether each source in the catalog should be
kept (True) or rejected (False) based on the value of the
mask plane at its location.
"""
setExcludeMaskPlanes = [
maskPlane for maskPlane in excludeMaskPlanes if maskPlane in mask.getMaskPlaneDict()
]

excludePixelMask = mask.getPlaneBitMask(setExcludeMaskPlanes)

xv = (np.rint(sources.getX() - mask.getX0())).astype(int)
yv = (np.rint(sources.getY() - mask.getY0())).astype(int)

flags = np.ones(len(sources), dtype=bool)
if checkAdjacent:
pixRange = (0, -1, 1)
else:
pixRange = (0,)
for j in pixRange:
for i in pixRange:
mv = mask.array[yv + j, xv + i]
flags *= np.bitwise_and(mv, excludePixelMask) == 0
return flags