Skip to content

Commit

Permalink
Merge pull request #864 from lsst/tickets/DM-36638
Browse files Browse the repository at this point in the history
DM-36638: Add snap combination as a subtask at the beginning of CalibrateImageTask
  • Loading branch information
parejkoj committed Dec 8, 2023
2 parents 97fd7b4 + 2e9afd5 commit 9527b94
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 410 deletions.
59 changes: 52 additions & 7 deletions python/lsst/pipe/tasks/calibrateImage.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import collections.abc

import numpy as np

import lsst.afw.table as afwTable
Expand All @@ -35,7 +37,8 @@
from lsst.pipe.base import connectionTypes
from lsst.utils.timer import timeMethod

from . import measurePsf, repair, setPrimaryFlags, photoCal, computeExposureSummaryStats, maskStreaks
from . import measurePsf, repair, setPrimaryFlags, photoCal, \
computeExposureSummaryStats, maskStreaks, snapCombine


class CalibrateImageConnections(pipeBase.PipelineTaskConnections,
Expand All @@ -58,10 +61,11 @@ class CalibrateImageConnections(pipeBase.PipelineTaskConnections,
multiple=True
)

exposure = connectionTypes.Input(
doc="Exposure to be calibrated, and detected and measured on.",
exposures = connectionTypes.Input(
doc="Exposure (or two snaps) to be calibrated, and detected and measured on.",
name="postISRCCD",
storageClass="Exposure",
multiple=True, # to handle 1 exposure or 2 snaps
dimensions=["instrument", "exposure", "detector"],
)

Expand Down Expand Up @@ -144,6 +148,11 @@ class CalibrateImageConfig(pipeBase.PipelineTaskConfig, pipelineConnections=Cali
optional=True
)

snap_combine = pexConfig.ConfigurableField(
target=snapCombine.SnapCombineTask,
doc="Task to combine two snaps to make one exposure.",
)

# subtasks used during psf characterization
install_simple_psf = pexConfig.ConfigurableField(
target=lsst.meas.algorithms.installGaussianPsf.InstallGaussianPsfTask,
Expand Down Expand Up @@ -340,6 +349,8 @@ class CalibrateImageTask(pipeBase.PipelineTask):
def __init__(self, initial_stars_schema=None, **kwargs):
super().__init__(**kwargs)

self.makeSubtask("snap_combine")

# PSF determination subtasks
self.makeSubtask("install_simple_psf")
self.makeSubtask("psf_repair")
Expand Down Expand Up @@ -394,15 +405,17 @@ def runQuantum(self, butlerQC, inputRefs, outputRefs):
butlerQC.put(outputs, outputRefs)

@timeMethod
def run(self, *, exposure):
def run(self, *, exposures):
"""Find stars and perform psf measurement, then do a deeper detection
and measurement and calibrate astrometry and photometry from that.
Parameters
----------
exposure : `lsst.afw.image.Exposure`
Post-ISR exposure, with an initial WCS, VisitInfo, and Filter.
Modified in-place during processing.
exposures : `lsst.afw.image.Exposure` or `list` [`lsst.afw.image.Exposure`]
Post-ISR exposure(s), with an initial WCS, VisitInfo, and Filter.
Modified in-place during processing if only one is passed.
If two exposures are passed, treat them as snaps and combine
before doing further processing.
Returns
-------
Expand Down Expand Up @@ -432,6 +445,8 @@ def run(self, *, exposure):
Reference catalog stars matches used in the photometric fit.
(`list` [`lsst.afw.table.ReferenceMatch`] or `lsst.afw.table.BaseCatalog`)
"""
exposure = self._handle_snaps(exposures)

psf_stars, background, candidates = self._compute_psf(exposure)

self._measure_aperture_correction(exposure, psf_stars)
Expand All @@ -455,6 +470,36 @@ def run(self, *, exposure):
astrometry_matches=astrometry_matches,
photometry_matches=photometry_matches)

def _handle_snaps(self, exposure):
"""Combine two snaps into one exposure, or return a single exposure.
Parameters
----------
exposure : `lsst.afw.image.Exposure` or `list` [`lsst.afw.image.Exposure]`
One or two exposures to combine as snaps.
Returns
-------
exposure : `lsst.afw.image.Exposure`
A single exposure to continue processing.
Raises
------
RuntimeError
Raised if input does not contain either 1 or 2 exposures.
"""
if isinstance(exposure, lsst.afw.image.Exposure):
return exposure

if isinstance(exposure, collections.abc.Sequence):
match len(exposure):
case 1:
return exposure[0]
case 2:
return self.snap_combine.run(exposure[0], exposure[1]).exposure
case n:
raise RuntimeError(f"Can only process 1 or 2 snaps, not {n}.")

def _compute_psf(self, exposure, guess_psf=True):
"""Find bright sources detected on an exposure and fit a PSF model to
them, repairing likely cosmic rays before detection.
Expand Down

0 comments on commit 9527b94

Please sign in to comment.