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

DM-46693: Add ability to re-apply bgModel1 in SkyCorrectionTask #989

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
109 changes: 83 additions & 26 deletions python/lsst/pipe/tasks/skyCorrection.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ class SkyCorrectionConfig(PipelineTaskConfig, pipelineConnections=SkyCorrectionC
dtype=FocalPlaneBackgroundConfig,
doc="Initial background model, prior to sky frame subtraction",
)
undoBgModel1 = Field(
dtype=bool,
default=False,
doc="If True, adds back initial background model after sky and removes bgModel1 from the list",
)
sky = ConfigurableField(
target=SkyMeasurementTask,
doc="Sky measurement",
Expand Down Expand Up @@ -210,6 +215,11 @@ def setDefaults(self):
self.bgModel2.ySize = 256
self.bgModel2.smoothScale = 1.0

def validate(self):
super().validate()
if self.undoBgModel1 and not self.doSky and not self.doBgModel2:
raise ValueError("If undoBgModel1 is True, task requires at least one of doSky or doBgModel2.")


class SkyCorrectionTask(PipelineTask):
"""Perform a full focal plane sky correction."""
Expand Down Expand Up @@ -278,37 +288,45 @@ def run(self, calExps, calBkgs, skyFrames, camera):

Parameters
----------
calExps : `list` [`lsst.afw.image.exposure.ExposureF`]
calExps : `list` [`lsst.afw.image.ExposureF`]
Detector calibrated exposure images for the visit.
calBkgs : `list` [`lsst.afw.math.BackgroundList`]
Detector background lists matching the calibrated exposures.
skyFrames : `list` [`lsst.afw.image.exposure.ExposureF`]
skyFrames : `list` [`lsst.afw.image.ExposureF`]
Sky frame calibration data for the input detectors.
camera : `lsst.afw.cameraGeom.Camera`
Camera matching the input data to process.

Returns
-------
results : `Struct` containing:
skyFrameScale : `float`
Scale factor applied to the sky frame.
skyCorr : `list` [`lsst.afw.math.BackgroundList`]
Detector-level sky correction background lists.
calExpMosaic : `lsst.afw.image.exposure.ExposureF`
calExpMosaic : `lsst.afw.image.ExposureF`
Visit-level mosaic of the sky corrected data, binned.
Analogous to `calexp - skyCorr`.
calBkgMosaic : `lsst.afw.image.exposure.ExposureF`
calBkgMosaic : `lsst.afw.image.ExposureF`
Visit-level mosaic of the sky correction background, binned.
Analogous to `calexpBackground + skyCorr`.
"""
# Restore original backgrounds in-place; optionally refine mask maps
numOrigBkgElements = [len(calBkg) for calBkg in calBkgs]
_ = self._restoreBackgroundRefineMask(calExps, calBkgs)
_ = self._restoreOriginalBackgroundRefineMask(calExps, calBkgs)

# Bin exposures, generate full-fp bg, map to CCDs and subtract in-place
_ = self._subtractVisitBackground(calExps, calBkgs, camera, self.config.bgModel1)
initialBackgroundIndex = len(calBkgs[0]._backgrounds) - 1

# Subtract a scaled sky frame from all input exposures
skyFrameScale = None
if self.config.doSky:
self._subtractSkyFrame(calExps, skyFrames, calBkgs)
skyFrameScale = self._subtractSkyFrame(calExps, skyFrames, calBkgs)

# Adds full-fp bg back onto exposures, removes it from list
if self.config.undoBgModel1:
_ = self._undoInitialBackground(calExps, calBkgs, initialBackgroundIndex)

# Bin exposures, generate full-fp bg, map to CCDs and subtract in-place
if self.config.doBgModel2:
Expand All @@ -326,9 +344,11 @@ def run(self, calExps, calBkgs, skyFrames, camera):
skyCorrExtras, camera, self.config.binning, ids=calExpIds, refExps=calExps
)

return Struct(skyCorr=calBkgs, calExpMosaic=calExpMosaic, calBkgMosaic=calBkgMosaic)
return Struct(
skyFrameScale=skyFrameScale, skyCorr=calBkgs, calExpMosaic=calExpMosaic, calBkgMosaic=calBkgMosaic
)

def _restoreBackgroundRefineMask(self, calExps, calBkgs):
def _restoreOriginalBackgroundRefineMask(self, calExps, calBkgs):
"""Restore original background to each calexp and invert the related
background model; optionally refine the mask plane.

Expand All @@ -350,17 +370,17 @@ def _restoreBackgroundRefineMask(self, calExps, calBkgs):

Parameters
----------
calExps : `lsst.afw.image.exposure.ExposureF`
calExps : `lsst.afw.image.ExposureF`
Detector level calexp images to process.
calBkgs : `lsst.afw.math._backgroundList.BackgroundList`
calBkgs : `lsst.afw.math.BackgroundList`
Detector level background lists associated with the calexps.

Returns
-------
calExps : `lsst.afw.image.exposure.ExposureF`
The calexps with the initially subtracted background restored.
skyCorrBases : `lsst.afw.math._backgroundList.BackgroundList`
The inverted initial background models; the genesis for skyCorrs.
calExps : `lsst.afw.image.ExposureF`
The calexps with the originally subtracted background restored.
skyCorrBases : `lsst.afw.math.BackgroundList`
The inverted original background models; the genesis for skyCorrs.
"""
skyCorrBases = []
for calExp, calBkg in zip(calExps, calBkgs):
Expand All @@ -379,14 +399,45 @@ def _restoreBackgroundRefineMask(self, calExps, calBkgs):

stats = np.nanpercentile(skyCorrBase.array, [50, 75, 25])
self.log.info(
"Detector %d: Initial background restored; BG median = %.1f counts, BG IQR = %.1f counts",
"Detector %d: Original background restored; BG median = %.1f counts, BG IQR = %.1f counts",
calExp.getDetector().getId(),
-stats[0],
np.subtract(*stats[1:]),
)
skyCorrBases.append(skyCorrBase)
return calExps, skyCorrBases

def _undoInitialBackground(self, calExps, calBkgs, initialBackgroundIndex):
"""Undo the initial background subtraction (bgModel1) after sky frame
subtraction.

Parameters
----------
calExps : `list` [`lsst.afw.image.ExposureF`]
Calibrated exposures to be background subtracted.
calBkgs : `list` [`lsst.afw.math.BackgroundList`]
Background lists associated with the input calibrated exposures.
initialBackgroundIndex : `int`
Index of the initial background (bgModel1) in the background list.

Notes
-----
Inputs are modified in-place.
"""
for calExp, calBkg in zip(calExps, calBkgs):
image = calExp.getMaskedImage()

# Remove bgModel1 from the background list; restore in the image
initialBackground = calBkg[initialBackgroundIndex][0].getImageF()
image += initialBackground
calBkg._backgrounds.pop(initialBackgroundIndex)

self.log.info(
"Detector %d: The initial background model prior to sky frame subtraction (bgModel1) has "
"been removed from the background list",
calExp.getDetector().getId(),
)

def _subtractVisitBackground(self, calExps, calBkgs, camera, config):
"""Perform a full focal-plane background subtraction for a visit.

Expand All @@ -400,9 +451,9 @@ def _subtractVisitBackground(self, calExps, calBkgs, camera, config):

Parameters
----------
calExps : `list` [`lsst.afw.image.exposure.ExposureF`]
calExps : `list` [`lsst.afw.image.ExposureF`]
Calibrated exposures to be background subtracted.
calBkgs : `list` [`lsst.afw.math._backgroundList.BackgroundList`]
calBkgs : `list` [`lsst.afw.math.BackgroundList`]
Background lists associated with the input calibrated exposures.
camera : `lsst.afw.cameraGeom.Camera`
Camera description.
Expand All @@ -413,7 +464,7 @@ def _subtractVisitBackground(self, calExps, calBkgs, camera, config):
-------
calExps : `list` [`lsst.afw.image.maskedImage.MaskedImageF`]
Background subtracted exposures for creating a focal plane image.
calBkgs : `list` [`lsst.afw.math._backgroundList.BackgroundList`]
calBkgs : `list` [`lsst.afw.math.BackgroundList`]
Updated background lists with a visit-level model appended.
"""
# Set up empty full focal plane background model object
Expand Down Expand Up @@ -478,16 +529,16 @@ def _subtractDetectorBackground(self, calExp, bgModel):

Parameters
----------
calExp : `lsst.afw.image.exposure.ExposureF`
calExp : `lsst.afw.image.ExposureF`
Exposure to subtract the background model from.
bgModel : `lsst.pipe.tasks.background.FocalPlaneBackground`
Full focal plane camera-level background model.

Returns
-------
calExp : `lsst.afw.image.exposure.ExposureF`
calExp : `lsst.afw.image.ExposureF`
Background subtracted input exposure.
calBkgElement : `lsst.afw.math._backgroundList.BackgroundList`
calBkgElement : `lsst.afw.math.BackgroundList`
Detector level realization of the full focal plane bg model.
"""
image = calExp.getMaskedImage()
Expand All @@ -510,12 +561,17 @@ def _subtractSkyFrame(self, calExps, skyFrames, calBkgs):

Parameters
----------
calExps : `list` [`lsst.afw.image.exposure.ExposureF`]
calExps : `list` [`lsst.afw.image.ExposureF`]
Calibrated exposures to be background subtracted.
skyFrames : `list` [`lsst.afw.image.exposure.ExposureF`]
skyFrames : `list` [`lsst.afw.image.ExposureF`]
Sky frame calibration data for the input detectors.
calBkgs : `list` [`lsst.afw.math._backgroundList.BackgroundList`]
calBkgs : `list` [`lsst.afw.math.BackgroundList`]
Background lists associated with the input calibrated exposures.

Returns
-------
scale : `float`
Scale factor applied to the sky frame.
"""
skyFrameBgModels = []
scales = []
Expand All @@ -531,6 +587,7 @@ def _subtractSkyFrame(self, calExps, skyFrames, calBkgs):
# also updating the calBkg list in-place
self.sky.subtractSkyFrame(calExp.getMaskedImage(), skyFrameBgModel, scale, calBkg)
self.log.info("Sky frame subtracted with a scale factor of %.5f", scale)
return scale

def _binAndMosaic(self, exposures, camera, binning, ids=None, refExps=None):
"""Bin input exposures and mosaic across the entire focal plane.
Expand All @@ -549,11 +606,11 @@ def _binAndMosaic(self, exposures, camera, binning, ids=None, refExps=None):
Binning size to be applied to input images.
ids : `list` [`int`], optional
List of detector ids to iterate over.
refExps : `list` [`lsst.afw.image.exposure.ExposureF`], optional
refExps : `list` [`lsst.afw.image.ExposureF`], optional
If supplied, mask planes from these reference images will be used.
Returns
-------
mosaicImage : `lsst.afw.image.exposure.ExposureF`
mosaicImage : `lsst.afw.image.ExposureF`
Mosaicked full focal plane image.
"""
refExps = np.resize(refExps, len(exposures)) # type: ignore
Expand Down
Loading
Loading