Coverage for python/lsst/summit/utils/quickLook.py: 18%
86 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-14 14:54 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-14 14:54 +0000
1# This file is part of summit_utils.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import dataclasses
23import os
24from lsst.ip.isr import IsrTask
25from lsst.ip.isr.isrTask import IsrTaskConnections
26import lsst.pipe.base.connectionTypes as cT
27from lsst.utils import getPackageDir
29import lsst.pex.config as pexConfig
30import lsst.pipe.base as pipeBase
31from lsst.pipe.tasks.characterizeImage import CharacterizeImageTask
32from lsst.meas.algorithms.installGaussianPsf import InstallGaussianPsfTask
34__all__ = ['QuickLookIsrTask', 'QuickLookIsrTaskConfig']
37class QuickLookIsrTaskConnections(IsrTaskConnections):
38 """Copy isrTask's connections, changing prereq min values to zero.
40 Copy all the connections directly for IsrTask, keeping ccdExposure as
41 required as non-zero, but changing all the other PrerequisiteInputs'
42 minimum values to zero.
43 """
44 def __init__(self, *, config=None):
45 # programatically clone all of the connections from isrTask
46 # setting minimum values to zero for everything except the ccdExposure
47 super().__init__(config=IsrTask.ConfigClass()) # need a dummy config, isn't used other than for ctor
48 for name, connection in self.allConnections.items():
49 if hasattr(connection, 'minimum'):
50 setattr(
51 self,
52 name,
53 dataclasses.replace(connection, minimum=(0 if name != "ccdExposure" else 1)),
54 )
56 exposure = cT.Output( # called just "exposure" to mimic isrTask's return struct
57 name="quickLookExp",
58 doc="The quickLook output exposure.",
59 storageClass="ExposureF",
60 dimensions=("instrument", "exposure", "detector"),
61 )
62 # set like this to make it explicit that the outputExposure
63 # and the exposure are identical. The only reason there are two is for
64 # API compatibility.
65 self.outputExposure = exposure
68class QuickLookIsrTaskConfig(pipeBase.PipelineTaskConfig,
69 pipelineConnections=QuickLookIsrTaskConnections):
70 """Configuration parameters for QuickLookIsrTask."""
72 doRepairCosmics = pexConfig.Field(
73 dtype=bool,
74 doc="Interpolate over cosmic rays?",
75 default=True,
76 )
79class QuickLookIsrTask(pipeBase.PipelineTask):
80 """Task automatically performing as much isr as possible. Should never fail
82 Automatically performs as much isr as is possible, depending on the
83 calibration products available. All calibration products that can be found
84 are applied, and if none are found, the image is assembled, the overscan is
85 subtracted and the assembled image is returned. Optionally, cosmic rays are
86 interpolated over.
87 """
89 ConfigClass = QuickLookIsrTaskConfig
90 _DefaultName = "quickLook"
92 def __init__(self, **kwargs):
93 super().__init__(**kwargs)
95 def run(self, ccdExposure, *,
96 camera=None,
97 bias=None,
98 dark=None,
99 flat=None,
100 defects=None,
101 linearizer=None,
102 crosstalk=None,
103 bfKernel=None,
104 bfGains=None,
105 ptc=None,
106 crosstalkSources=None,
107 isrBaseConfig=None
108 ):
109 """Run isr and cosmic ray repair using, doing as much isr as possible.
111 Retrieves as many calibration products as are available, and runs isr
112 with those settings enabled, but always returns an assembled image at
113 a minimum. Then performs cosmic ray repair if configured to.
115 Parameters
116 ----------
117 ccdExposure : `lsst.afw.image.Exposure`
118 The raw exposure that is to be run through ISR. The
119 exposure is modified by this method.
120 camera : `lsst.afw.cameraGeom.Camera`, optional
121 The camera geometry for this exposure. Required if
122 one or more of ``ccdExposure``, ``bias``, ``dark``, or
123 ``flat`` does not have an associated detector.
124 bias : `lsst.afw.image.Exposure`, optional
125 Bias calibration frame.
126 linearizer : `lsst.ip.isr.linearize.LinearizeBase`, optional
127 Functor for linearization.
128 crosstalk : `lsst.ip.isr.crosstalk.CrosstalkCalib`, optional
129 Calibration for crosstalk.
130 crosstalkSources : `list`, optional
131 List of possible crosstalk sources.
132 dark : `lsst.afw.image.Exposure`, optional
133 Dark calibration frame.
134 flat : `lsst.afw.image.Exposure`, optional
135 Flat calibration frame.
136 ptc : `lsst.ip.isr.PhotonTransferCurveDataset`, optional
137 Photon transfer curve dataset, with, e.g., gains
138 and read noise.
139 bfKernel : `numpy.ndarray`, optional
140 Brighter-fatter kernel.
141 bfGains : `dict` of `float`, optional
142 Gains used to override the detector's nominal gains for the
143 brighter-fatter correction. A dict keyed by amplifier name for
144 the detector in question.
145 defects : `lsst.ip.isr.Defects`, optional
146 List of defects.
147 fringes : `lsst.pipe.base.Struct`, optional
148 Struct containing the fringe correction data, with
149 elements:
150 - ``fringes``: fringe calibration frame (`afw.image.Exposure`)
151 - ``seed``: random seed derived from the ccdExposureId for random
152 number generator (`uint32`)
153 opticsTransmission: `lsst.afw.image.TransmissionCurve`, optional
154 A ``TransmissionCurve`` that represents the throughput of the,
155 optics, to be evaluated in focal-plane coordinates.
156 filterTransmission : `lsst.afw.image.TransmissionCurve`
157 A ``TransmissionCurve`` that represents the throughput of the
158 filter itself, to be evaluated in focal-plane coordinates.
159 sensorTransmission : `lsst.afw.image.TransmissionCurve`
160 A ``TransmissionCurve`` that represents the throughput of the
161 sensor itself, to be evaluated in post-assembly trimmed detector
162 coordinates.
163 atmosphereTransmission : `lsst.afw.image.TransmissionCurve`
164 A ``TransmissionCurve`` that represents the throughput of the
165 atmosphere, assumed to be spatially constant.
166 detectorNum : `int`, optional
167 The integer number for the detector to process.
168 strayLightData : `object`, optional
169 Opaque object containing calibration information for stray-light
170 correction. If `None`, no correction will be performed.
171 illumMaskedImage : `lsst.afw.image.MaskedImage`, optional
172 Illumination correction image.
173 isrBaseConfig : `lsst.ip.isr.IsrTaskConfig`, optional
174 An isrTask config to act as the base configuration. Options which
175 involve applying a calibration product are ignored, but this allows
176 for the configuration of e.g. the number of overscan columns.
178 Returns
179 -------
180 result : `lsst.pipe.base.Struct`
181 Result struct with component:
182 - ``exposure`` : `afw.image.Exposure`
183 The ISRed and cosmic-ray-repaired exposure.
184 """
185 if not isrBaseConfig:
186 isrConfig = IsrTask.ConfigClass()
187 packageDir = getPackageDir("summit_utils")
188 isrConfig.load(os.path.join(packageDir, "config", "quickLookIsr.py"))
189 else:
190 isrConfig = isrBaseConfig
192 isrConfig.doBias = False
193 isrConfig.doDark = False
194 isrConfig.doFlat = False
195 isrConfig.doFringe = False
196 isrConfig.doDefect = False
197 isrConfig.doLinearize = False
198 isrConfig.doCrosstalk = False
199 isrConfig.doBrighterFatter = False
200 isrConfig.usePtcGains = False
202 if bias:
203 isrConfig.doBias = True
204 self.log.info("Running with bias correction")
206 if dark:
207 isrConfig.doDark = True
208 self.log.info("Running with dark correction")
210 if flat:
211 isrConfig.doFlat = True
212 self.log.info("Running with flat correction")
214 # TODO: deal with fringes here
215 if defects:
216 isrConfig.doDefect = True
217 self.log.info("Running with defect correction")
219 if linearizer:
220 isrConfig.doLinearize = True
221 self.log.info("Running with linearity correction")
223 if crosstalk:
224 isrConfig.doCrosstalk = True
225 self.log.info("Running with crosstalk correction")
227 if bfKernel:
228 isrConfig.doBrighterFatter = True
229 self.log.info("Running with brighter-fatter correction")
231 if ptc:
232 isrConfig.usePtcGains = True
233 self.log.info("Running with ptc correction")
235 isrConfig.doWrite = False
236 isrTask = IsrTask(config=isrConfig)
237 result = isrTask.run(ccdExposure,
238 camera=camera,
239 bias=bias,
240 dark=dark,
241 flat=flat,
242 # fringes=pipeBase.Struct(fringes=None),
243 defects=defects,
244 linearizer=linearizer,
245 crosstalk=crosstalk,
246 bfKernel=bfKernel,
247 bfGains=bfGains,
248 ptc=ptc,
249 crosstalkSources=crosstalkSources,)
251 postIsr = result.exposure
253 if self.config.doRepairCosmics:
254 try: # can fail due to too many CRs detected, and we always want an exposure back
255 self.log.info("Repairing cosmics...")
256 if postIsr.getPsf() is None:
257 installPsfTask = InstallGaussianPsfTask()
258 installPsfTask.run(postIsr)
260 # TODO: try adding a reasonably wide Gaussian as a temp PSF
261 # and then just running repairTask on its own without any
262 # imChar. It should work, and be faster.
263 repairConfig = CharacterizeImageTask.ConfigClass()
264 repairConfig.doMeasurePsf = False
265 repairConfig.doApCorr = False
266 repairConfig.doDeblend = False
267 repairConfig.doWrite = False
268 repairConfig.repair.cosmicray.nCrPixelMax = 200000
269 repairTask = CharacterizeImageTask(config=repairConfig)
271 repairTask.repair.run(postIsr)
272 except Exception as e:
273 self.log.warning(f"During CR repair caught: {e}")
275 # exposure is returned for convenience to mimic isrTask's API.
276 return pipeBase.Struct(exposure=postIsr,
277 outputExposure=postIsr)