Skip to content

Commit

Permalink
Merge branch 'tickets/DM-47195'
Browse files Browse the repository at this point in the history
  • Loading branch information
czwa committed Nov 1, 2024
2 parents bb4f38f + 5bb2d52 commit fb853ff
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
22 changes: 21 additions & 1 deletion python/lsst/ip/isr/crosstalk.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ def calculateBackground(mi, badPixels=["BAD"]):

def subtractCrosstalk(self, thisExposure, sourceExposure=None, crosstalkCoeffs=None,
crosstalkCoeffsSqr=None, crosstalkCoeffsValid=None,
badPixels=["BAD"], minPixelToMask=45000,
badPixels=["BAD"], minPixelToMask=45000, doSubtrahendMasking=False,
crosstalkStr="CROSSTALK", isTrimmed=False,
backgroundMethod="None", doSqrCrosstalk=False, fullAmplifier=False,
parallelOverscan=False, detectorConfig=None, badAmpDict=None):
Expand Down Expand Up @@ -773,12 +773,26 @@ def subtractCrosstalk(self, thisExposure, sourceExposure=None, crosstalkCoeffs=N
fullAmplifier=fullAmplifier,
parallelOverscan=parallelOverscan,
)
tImageSqr.getMask().getArray()[:] &= crosstalk # Remove all other masks
tImageSqr -= backgrounds[tt]**2
sImage.scaledPlus(coeffsSqr[ss, tt], tImageSqr)

# Set crosstalkStr bit only for those pixels that have been
# significantly modified (i.e., those masked as such in 'subtrahend'),
# not necessarily those that are bright originally.
mask.clearMaskPlane(crosstalkPlane)

if doSubtrahendMasking:
subtrahend.mask.clearMaskPlane(crosstalkPlane)
# Run detection twice to avoid needing an absolute value image
threshold = lsst.afw.detection.Threshold(minPixelToMask, polarity=True)
footprints = lsst.afw.detection.FootprintSet(subtrahend, threshold)
footprints.setMask(subtrahend.mask, crosstalkStr)

threshold = lsst.afw.detection.Threshold(minPixelToMask, polarity=False)
footprints = lsst.afw.detection.FootprintSet(subtrahend, threshold)
footprints.setMask(subtrahend.mask, crosstalkStr)

mi -= subtrahend # also sets crosstalkStr bit for bright pixels


Expand All @@ -794,6 +808,11 @@ class CrosstalkConfig(Config):
doc="Name for crosstalk mask plane.",
default="CROSSTALK"
)
doSubtrahendMasking = Field(
dtype=bool,
doc="Use subtrahend image thresholding instead of input image thesholding to set crosstalk mask?",
default=False,
)
crosstalkBackgroundMethod = ChoiceField(
dtype=str,
doc="Type of background subtraction to use when applying correction.",
Expand Down Expand Up @@ -1037,6 +1056,7 @@ def run(
crosstalkCoeffsSqr=crosstalkCoeffsSqr,
crosstalkCoeffsValid=crosstalk.coeffValid,
minPixelToMask=self.config.minPixelToMask,
doSubtrahendMasking=self.config.doSubtrahendMasking,
crosstalkStr=self.config.crosstalkMaskPlane,
isTrimmed=isTrimmed,
backgroundMethod=self.config.crosstalkBackgroundMethod,
Expand Down
16 changes: 14 additions & 2 deletions tests/test_crosstalk.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ def construct(imageList):
self.exposure = lsst.afw.image.makeExposure(lsst.afw.image.makeMaskedImage(construct(withCrosstalk)))
self.exposure.setDetector(ccd1)

# Add a saturated region so we can confirm it doesn't get duplicated.
saturatedBit = self.exposure.mask.getPlaneBitMask("SAT")
self.exposure.mask.array[0:5, 0:5] |= saturatedBit

# Create a single ctSource that will be used for interChip CT
# correction.
self.ctSource = lsst.afw.image.makeExposure(lsst.afw.image.makeMaskedImage(construct(withCrosstalk)))
Expand Down Expand Up @@ -218,21 +222,28 @@ def checkSubtracted(self, exposure):
self.assertFloatsAlmostEqual(image.getArray(), self.corrected.getArray(), atol=2.0e-2)
self.assertIn(self.crosstalkStr, mask.getMaskPlaneDict())
self.assertGreater((mask.getArray() & mask.getPlaneBitMask(self.crosstalkStr) > 0).sum(), 0)
self.assertEqual((mask.getArray() & mask.getPlaneBitMask("SAT") > 0).sum(), 25)

def checkTaskAPI_NL(self, this_isr_task):
def checkTaskAPI_NL(self, this_isr_task, doSubtrahendMasking=False):
"""Check the the crosstalk task under different ISR tasks.
(e.g., IsrTask and IsrTaskLSST)
Parameters
----------
this_isr_task : `lsst.pipe.base.PipelineTask`
The ISR Task instance to use.
doSubtrahendMasking : `bool`
Enable subtrahend masking code.
"""
self.setUp_general(doSqrCrosstalk=True)
coeff = np.array(self.crosstalk).transpose()
coeffSqr = np.array(self.crosstalk_sqr).transpose()
config = this_isr_task.ConfigClass()
config.crosstalk.minPixelToMask = self.value - 1
config.crosstalk.crosstalkMaskPlane = self.crosstalkStr
if doSubtrahendMasking:
config.crosstalk.doSubtrahendMasking = True
config.crosstalk.minPixelToMask = 1.0
# Turn on the NL correction
config.crosstalk.doQuadraticCrosstalkCorrection = True
isr = this_isr_task(config=config)
Expand Down Expand Up @@ -282,7 +293,8 @@ def testTaskAPI_NL(self):
correction.
"""
for this_isr_task in [IsrTask, IsrTaskLSST]:
self.checkTaskAPI_NL(this_isr_task)
for subtrahendMasking in [False, True]:
self.checkTaskAPI_NL(this_isr_task, subtrahendMasking)

def test_nullCrosstalkTask(self):
"""Test that the null crosstalk task does not create an error.
Expand Down

0 comments on commit fb853ff

Please sign in to comment.