Coverage for python/lsst/summit/utils/quickLook.py: 16%
96 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-14 13:09 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-14 13:09 +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 os
23from lsst.ip.isr import IsrTask
24from lsst.ip.isr.isrTask import IsrTaskConnections
25import lsst.pipe.base.connectionTypes as cT
26from lsst.utils import getPackageDir
28import lsst.pex.config as pexConfig
29import lsst.pipe.base as pipeBase
30from lsst.pipe.tasks.characterizeImage import CharacterizeImageTask
31from lsst.meas.algorithms.installGaussianPsf import InstallGaussianPsfTask
33__all__ = ['QuickLookIsrTask', 'QuickLookIsrTaskConfig']
36def _getArgs(connection):
37 """Get the all required args from a connection in order to reconstruct it.
38 """
39 newArgs = {}
40 for attr in ("name", "storageClass", "multiple", "doc", "dimensions", "isCalibration", "deferLoad",
41 "minimum", "lookupFunction"):
42 if hasattr(connection, attr):
43 newArgs[attr] = getattr(connection, attr)
44 return newArgs
47class QuickLookIsrTaskConnections(IsrTaskConnections):
48 """Copy isrTask's connections, changing prereq min values to zero.
50 Copy all the connections directly for IsrTask, keeping ccdExposure as
51 required as non-zero, but changing all the other PrerequisiteInputs'
52 minimum values to zero.
53 """
54 def __init__(self, *, config=None):
55 # programatically clone all of the connections from isrTask
56 # setting minimum values to zero for everything except the ccdExposure
57 super().__init__(config=IsrTask.ConfigClass()) # need a dummy config, isn't used other than for ctor
58 for name, connection in self.allConnections.items():
59 if hasattr(connection, 'minimum'):
60 args = _getArgs(connection)
61 if name != "ccdExposure": # need one input image always
62 args['minimum'] = 0
63 newConnection = type(connection)(**args)
64 self.allConnections[name] = newConnection
65 setattr(self, name, newConnection)
67 exposure = cT.Output( # called just "exposure" to mimic isrTask's return struct
68 name="quickLookExp",
69 doc="The quickLook output exposure.",
70 storageClass="ExposureF",
71 dimensions=("instrument", "exposure", "detector"),
72 )
73 # set like this to make it explicit that the outputExposure
74 # and the exposure are identical. The only reason there are two is for
75 # API compatibility.
76 self.outputExposure = exposure
79class QuickLookIsrTaskConfig(pipeBase.PipelineTaskConfig,
80 pipelineConnections=QuickLookIsrTaskConnections):
81 """Configuration parameters for QuickLookIsrTask."""
83 doRepairCosmics = pexConfig.Field(
84 dtype=bool,
85 doc="Interpolate over cosmic rays?",
86 default=True,
87 )
90class QuickLookIsrTask(pipeBase.PipelineTask):
91 """Task automatically performing as much isr as possible. Should never fail
93 Automatically performs as much isr as is possible, depending on the
94 calibration products available. All calibration products that can be found
95 are applied, and if none are found, the image is assembled, the overscan is
96 subtracted and the assembled image is returned. Optionally, cosmic rays are
97 interpolated over.
98 """
100 ConfigClass = QuickLookIsrTaskConfig
101 _DefaultName = "quickLook"
103 def __init__(self, **kwargs):
104 super().__init__(**kwargs)
106 def run(self, ccdExposure, *,
107 camera=None,
108 bias=None,
109 dark=None,
110 flat=None,
111 defects=None,
112 linearizer=None,
113 crosstalk=None,
114 bfKernel=None,
115 bfGains=None,
116 ptc=None,
117 crosstalkSources=None,
118 isrBaseConfig=None
119 ):
120 """Run isr and cosmic ray repair using, doing as much isr as possible.
122 Retrieves as many calibration products as are available, and runs isr
123 with those settings enabled, but always returns an assembled image at
124 a minimum. Then performs cosmic ray repair if configured to.
126 Parameters
127 ----------
128 ccdExposure : `lsst.afw.image.Exposure`
129 The raw exposure that is to be run through ISR. The
130 exposure is modified by this method.
131 camera : `lsst.afw.cameraGeom.Camera`, optional
132 The camera geometry for this exposure. Required if
133 one or more of ``ccdExposure``, ``bias``, ``dark``, or
134 ``flat`` does not have an associated detector.
135 bias : `lsst.afw.image.Exposure`, optional
136 Bias calibration frame.
137 linearizer : `lsst.ip.isr.linearize.LinearizeBase`, optional
138 Functor for linearization.
139 crosstalk : `lsst.ip.isr.crosstalk.CrosstalkCalib`, optional
140 Calibration for crosstalk.
141 crosstalkSources : `list`, optional
142 List of possible crosstalk sources.
143 dark : `lsst.afw.image.Exposure`, optional
144 Dark calibration frame.
145 flat : `lsst.afw.image.Exposure`, optional
146 Flat calibration frame.
147 ptc : `lsst.ip.isr.PhotonTransferCurveDataset`, optional
148 Photon transfer curve dataset, with, e.g., gains
149 and read noise.
150 bfKernel : `numpy.ndarray`, optional
151 Brighter-fatter kernel.
152 bfGains : `dict` of `float`, optional
153 Gains used to override the detector's nominal gains for the
154 brighter-fatter correction. A dict keyed by amplifier name for
155 the detector in question.
156 defects : `lsst.ip.isr.Defects`, optional
157 List of defects.
158 fringes : `lsst.pipe.base.Struct`, optional
159 Struct containing the fringe correction data, with
160 elements:
161 - ``fringes``: fringe calibration frame (`afw.image.Exposure`)
162 - ``seed``: random seed derived from the ccdExposureId for random
163 number generator (`uint32`)
164 opticsTransmission: `lsst.afw.image.TransmissionCurve`, optional
165 A ``TransmissionCurve`` that represents the throughput of the,
166 optics, to be evaluated in focal-plane coordinates.
167 filterTransmission : `lsst.afw.image.TransmissionCurve`
168 A ``TransmissionCurve`` that represents the throughput of the
169 filter itself, to be evaluated in focal-plane coordinates.
170 sensorTransmission : `lsst.afw.image.TransmissionCurve`
171 A ``TransmissionCurve`` that represents the throughput of the
172 sensor itself, to be evaluated in post-assembly trimmed detector
173 coordinates.
174 atmosphereTransmission : `lsst.afw.image.TransmissionCurve`
175 A ``TransmissionCurve`` that represents the throughput of the
176 atmosphere, assumed to be spatially constant.
177 detectorNum : `int`, optional
178 The integer number for the detector to process.
179 strayLightData : `object`, optional
180 Opaque object containing calibration information for stray-light
181 correction. If `None`, no correction will be performed.
182 illumMaskedImage : `lsst.afw.image.MaskedImage`, optional
183 Illumination correction image.
184 isrBaseConfig : `lsst.ip.isr.IsrTaskConfig`, optional
185 An isrTask config to act as the base configuration. Options which
186 involve applying a calibration product are ignored, but this allows
187 for the configuration of e.g. the number of overscan columns.
189 Returns
190 -------
191 result : `lsst.pipe.base.Struct`
192 Result struct with component:
193 - ``exposure`` : `afw.image.Exposure`
194 The ISRed and cosmic-ray-repaired exposure.
195 """
196 if not isrBaseConfig:
197 isrConfig = IsrTask.ConfigClass()
198 packageDir = getPackageDir("summit_utils")
199 isrConfig.load(os.path.join(packageDir, "config", "quickLookIsr.py"))
200 else:
201 isrConfig = isrBaseConfig
203 isrConfig.doBias = False
204 isrConfig.doDark = False
205 isrConfig.doFlat = False
206 isrConfig.doFringe = False
207 isrConfig.doDefect = False
208 isrConfig.doLinearize = False
209 isrConfig.doCrosstalk = False
210 isrConfig.doBrighterFatter = False
211 isrConfig.usePtcGains = False
213 if bias:
214 isrConfig.doBias = True
215 self.log.info("Running with bias correction")
217 if dark:
218 isrConfig.doDark = True
219 self.log.info("Running with dark correction")
221 if flat:
222 isrConfig.doFlat = True
223 self.log.info("Running with flat correction")
225 # TODO: deal with fringes here
226 if defects:
227 isrConfig.doDefect = True
228 self.log.info("Running with defect correction")
230 if linearizer:
231 isrConfig.doLinearize = True
232 self.log.info("Running with linearity correction")
234 if crosstalk:
235 isrConfig.doCrosstalk = True
236 self.log.info("Running with crosstalk correction")
238 if bfKernel:
239 isrConfig.doBrighterFatter = True
240 self.log.info("Running with brighter-fatter correction")
242 if ptc:
243 isrConfig.usePtcGains = True
244 self.log.info("Running with ptc correction")
246 isrConfig.doWrite = False
247 isrTask = IsrTask(config=isrConfig)
248 result = isrTask.run(ccdExposure,
249 camera=camera,
250 bias=bias,
251 dark=dark,
252 flat=flat,
253 # fringes=pipeBase.Struct(fringes=None),
254 defects=defects,
255 linearizer=linearizer,
256 crosstalk=crosstalk,
257 bfKernel=bfKernel,
258 bfGains=bfGains,
259 ptc=ptc,
260 crosstalkSources=crosstalkSources,)
262 postIsr = result.exposure
264 if self.config.doRepairCosmics:
265 try: # can fail due to too many CRs detected, and we always want an exposure back
266 self.log.info("Repairing cosmics...")
267 if postIsr.getPsf() is None:
268 installPsfTask = InstallGaussianPsfTask()
269 installPsfTask.run(postIsr)
271 # TODO: try adding a reasonably wide Gaussian as a temp PSF
272 # and then just running repairTask on its own without any
273 # imChar. It should work, and be faster.
274 repairConfig = CharacterizeImageTask.ConfigClass()
275 repairConfig.doMeasurePsf = False
276 repairConfig.doApCorr = False
277 repairConfig.doDeblend = False
278 repairConfig.doWrite = False
279 repairConfig.repair.cosmicray.nCrPixelMax = 200000
280 repairTask = CharacterizeImageTask(config=repairConfig)
282 repairTask.repair.run(postIsr)
283 except Exception as e:
284 self.log.warning(f"During CR repair caught: {e}")
286 # exposure is returned for convenience to mimic isrTask's API.
287 return pipeBase.Struct(exposure=postIsr,
288 outputExposure=postIsr)