Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tickets/dm 42572: Add background subtraction to pipeline #213

Merged
merged 1 commit into from
Jan 25, 2024
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
8 changes: 8 additions & 0 deletions doc/versionHistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
Version History
##################

.. _lsst.ts.wep-8.2.0:

-------------
8.2.0
-------------

* Add background subtraction to cutOutDonutsBase.

.. _lsst.ts.wep-8.1.1:

-------------
Expand Down
10 changes: 10 additions & 0 deletions python/lsst/ts/wep/task/cutOutDonutsBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ class CutOutDonutsBaseTaskConfig(
dtype=int,
default=6,
)
subtractBackground = pexConfig.ConfigurableField(
target=lsst.meas.algorithms.SubtractBackgroundTask,
doc="Task to perform background subtraction.",
)


class CutOutDonutsBaseTask(pipeBase.PipelineTask):
Expand Down Expand Up @@ -185,6 +189,8 @@ def __init__(self, **kwargs):
# Parameters for mask multiplication (for deblending)
self.multiplyMask = self.config.multiplyMask
self.maskGrowthIter = self.config.maskGrowthIter
# Set up background subtraction task
self.makeSubtask("subtractBackground")

def _checkAndSetOffset(self, dataOffsetValue):
"""Check offset in instParams dictionary and if it
Expand Down Expand Up @@ -384,6 +390,10 @@ def cutOutStamps(self, exposure, donutCatalog, defocalType, cameraName):
pixelScale = exposure.getWcs().getPixelScale().asArcseconds()
camType = getCamTypeFromButlerName(cameraName, detectorType)
bandpass = exposure.filter.bandLabel

# Run background subtraction
self.subtractBackground.run(exposure=exposure).background

jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
# Get template
template = self.getTemplate(
detectorName,
Expand Down
15 changes: 6 additions & 9 deletions python/lsst/ts/wep/task/donutStamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,17 +269,14 @@ def makeMasks(self, inst, model, boundaryT, maskScalingFactorLocal):

self.comp_im.makeBlendedMask(inst, model, boundaryT, maskScalingFactorLocal)

# 0 flag in mask is part of image that is not donut
# 1 flag in mask means it is part of the model donut
maskDict = {"BKGRD": 0, "DONUT": 1}

# Set masks
self.mask_comp = afwImage.Mask(np.array(self.comp_im.mask_comp, dtype=np.int32))
self.mask_comp.clearMaskPlaneDict()
self.mask_comp.conformMaskPlanes(maskDict)
# Will inherit conformed MaskPlaneDict
afwImage.Mask.addMaskPlane("DONUT")
jbkalmbach marked this conversation as resolved.
Show resolved Hide resolved
donutMaskVal = afwImage.Mask.getPlaneBitMask("DONUT")
self.mask_comp = afwImage.Mask(
np.array(self.comp_im.mask_comp, dtype=np.int32) * donutMaskVal
)
self.mask_pupil = afwImage.Mask(
np.array(self.comp_im.mask_pupil, dtype=np.int32)
np.array(self.comp_im.mask_pupil, dtype=np.int32) * donutMaskVal
)

def getLinearWCS(self):
Expand Down
53 changes: 43 additions & 10 deletions tests/task/test_cutOutDonutsBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,52 @@ def testCalculateFinalCentroid(self):
self.assertEqual(cornerX, 0)
self.assertEqual(cornerY, 0)

def testCutOutStamps(self):
def _getExpAndCatalog(self, defocalType):
"""
Helper function to get exposure and donutCatalog for
testing cutOutStamps.

Parameters
----------
defocalType : lsst.ts.wep.utils.DefocalType
Defocal type of stamp to cut out.

Returns
-------
lsst.afw.image.Exposure
Exposure related to given defocal type
pandas.DataFrame
Donut Catalog for exposure
"""

if defocalType is DefocalType.Extra:
dataId = self.dataIdExtra
else:
dataId = self.dataIdIntra

exposure = self.butler.get(
"postISRCCD", dataId=self.dataIdExtra, collections=[self.runName]
"postISRCCD", dataId=dataId, collections=[self.runName]
)
donutCatalog = self.butler.get(
"donutCatalog", dataId=self.dataIdExtra, collections=[self.runName]
"donutCatalog", dataId=dataId, collections=[self.runName]
)

return exposure, donutCatalog

def testBackgroundSubtractionApplied(self):
exposure, donutCatalog = self._getExpAndCatalog(DefocalType.Extra)
with self.assertRaises(KeyError):
exposure.getMetadata()["BGMEAN"]
self.task.cutOutStamps(
exposure, donutCatalog, DefocalType.Extra, self.cameraName
)
# cutOutStamps runs background subtraction which is automatically
# applied to the exposure. Thus, BGMEAN should now exist in the
# exposure metadata.
self.assertIsInstance(exposure.getMetadata()["BGMEAN"], float)

def testCutOutStamps(self):
exposure, donutCatalog = self._getExpAndCatalog(DefocalType.Extra)
donutStamps = self.task.cutOutStamps(
exposure, donutCatalog, DefocalType.Extra, self.cameraName
)
Expand Down Expand Up @@ -287,13 +326,7 @@ def testCutOutStamps(self):
)

def testCutOutStampsBlended(self):
exposure = self.butler.get(
"postISRCCD", dataId=self.dataIdExtra, collections=[self.runName]
)
donutCatalog = self.butler.get(
"donutCatalog", dataId=self.dataIdExtra, collections=[self.runName]
)

exposure, donutCatalog = self._getExpAndCatalog(DefocalType.Extra)
donutStampsNoBlend = self.task.cutOutStamps(
exposure, donutCatalog, DefocalType.Extra, self.cameraName
)
Expand Down
17 changes: 11 additions & 6 deletions tests/task/test_donutStamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,8 @@ def testMakeMasks(self):
donutStamp.makeMasks(inst, "offAxis", 0, 1)
self.assertEqual(afwImage.MaskX, type(donutStamp.mask_comp))
self.assertEqual(afwImage.MaskX, type(donutStamp.mask_pupil))
self.assertDictEqual(
{"BKGRD": 0, "DONUT": 1}, donutStamp.mask_comp.getMaskPlaneDict()
)
self.assertDictEqual(
{"BKGRD": 0, "DONUT": 1}, donutStamp.mask_pupil.getMaskPlaneDict()
)
self.assertIn("DONUT", list(donutStamp.mask_comp.getMaskPlaneDict().keys()))
self.assertIn("DONUT", list(donutStamp.mask_pupil.getMaskPlaneDict().keys()))
maskC = donutStamp.mask_comp.getArray()
maskP = donutStamp.mask_pupil.getArray()
# Donut should match
Expand All @@ -281,6 +277,15 @@ def testMakeMasks(self):
# Make sure not just an empty array
self.assertTrue(np.sum(maskC) > 0.0)
self.assertTrue(np.sum(maskP) > 0.0)
# Make sure bits set are donut bits
self.assertCountEqual(
[0, afwImage.Mask.getPlaneBitMask("DONUT")],
list(np.unique(donutStamp.mask_comp.array)),
)
self.assertCountEqual(
[0, afwImage.Mask.getPlaneBitMask("DONUT")],
list(np.unique(donutStamp.mask_pupil.array)),
)
# Donut at center of focal plane should be symmetric
np.testing.assert_array_equal(maskC[:63], maskC[-63:][::-1])
np.testing.assert_array_equal(maskP[:63], maskP[-63:][::-1])
Loading