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