LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
repair.py
Go to the documentation of this file.
1# This file is part of pipe_tasks.
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/>.
21
22import lsst.pex.config as pexConfig
23import lsst.afw.math as afwMath
24import lsst.afw.detection as afwDet
25import lsst.meas.algorithms as measAlg
26import lsst.pipe.base as pipeBase
27from lsstDebug import getDebugFrame
28import lsst.afw.display as afwDisplay
29from lsst.pipe.tasks.interpImage import InterpImageTask
30from lsst.utils.timer import timeMethod
31
32
33class RepairConfig(pexConfig.Config):
34 doInterpolate = pexConfig.Field(
35 dtype=bool,
36 doc="Interpolate over defects? (ignored unless you provide a list of defects)",
37 default=True,
38 )
39 doCosmicRay = pexConfig.Field(
40 dtype=bool,
41 doc="Find and mask out cosmic rays?",
42 default=True,
43 )
44 cosmicray = pexConfig.ConfigField(
45 dtype=measAlg.FindCosmicRaysConfig,
46 doc="Options for finding and masking cosmic rays",
47 )
48 interp = pexConfig.ConfigurableField(
49 target=InterpImageTask,
50 doc="Interpolate over bad image pixels",
51 )
52
53 def setDefaults(self):
54 self.interpinterp.useFallbackValueAtEdge = True
55 self.interpinterp.fallbackValueType = "MEANCLIP"
56 self.interpinterp.negativeFallbackAllowed = True
57
58
64
65
66class RepairTask(pipeBase.Task):
67 r"""!
68 @anchor RepairTask_
69
70 @brief Interpolate over defects in an exposure and handle cosmic rays
71
72 @section pipe_tasks_repair_Contents Contents
73
74 - @ref pipe_tasks_repair_Purpose
75 - @ref pipe_tasks_repair_Initialize
76 - @ref pipe_tasks_repair_IO
77 - @ref pipe_tasks_repair_Config
78 - @ref pipe_tasks_repair_Debug
79 - @ref pipe_tasks_repair_Example
80
81 @section pipe_tasks_repair_Purpose Description
82
83 @copybrief RepairTask
84
85 This task operates on an lsst.afw.image.Exposure in place to interpolate over a set of
87 It will also, optionally, find and interpolate any cosmic rays in the lsst.afw.image.Exposure.
88
89 @section pipe_tasks_repair_Initialize Task initialization
90
91 See: lsst.pipe.base.task.Task.__init__
92
93 @section pipe_tasks_repair_IO Inputs/Outputs to the run method
94
95 @copydoc run
96
97 @section pipe_tasks_repair_Config Configuration parameters
98
99 See @ref RepairConfig
100
101 @section pipe_tasks_repair_Debug Debug variables
102
103 The command line task interface supports a
104 flag @c -d to import @b debug.py from your @c PYTHONPATH; see <a
105 href="https://developer.lsst.io/stack/debug.html">Debugging Tasks with lsstDebug</a> for more
106 about @b debug.py files.
107
108 The available variables in RepairTask are:
109 <DL>
110 <DT> @c display
111 <DD> A dictionary containing debug point names as keys with frame number as value. Valid keys are:
112 <DL>
113 <DT> repair.before
114 <DD> display image before any repair is done
115 <DT> repair.after
116 <DD> display image after cosmic ray and defect correction
117 </DL>
118 <DT> @c displayCR
119 <DD> If True, display the exposure on display's frame 1 and overlay bounding boxes around detects CRs.
120 </DL>
121 @section pipe_tasks_repair_Example A complete example of using RepairTask
122
123 This code is in runRepair.py in the examples directory, and can be run as @em e.g.
124 @code
125 examples/runRepair.py
126 @endcode
127 @dontinclude runRepair.py
128 Import the task. There are other imports. Read the source file for more info.
129 @skipline RepairTask
130
131 For this example, we manufacture a test image to run on.
132
133 First, create a pure Poisson noise image and a Psf to go with it. The mask plane
134 and variance can be constructed at the same time.
135 @skip poisson
136 @until mask
137
138 Inject some cosmic rays and generate the Exposure. Exposures are MaskedImages (image + mask + variance)
139 with other metadata (e.g. Psf and Wcs objects).
140 @skip some CRs
141 @until setPsf
142
143 Defects are represented as bad columns of random lengths. A defect list must be constructed to pass
144 on to the RepairTask.
145 @bug This is addressed in <a href="https://jira.lsstcorp.org/browse/DM-963"> DM-963</a>
146
147 @skip addDefects
148 @until push_back
149
150 Finally, the exposure can be repaired. Create an instance of the task and run it. The exposure
151 is modified in place.
152 @skip RepairTask
153 @until repair.run
154
155 <HR>
156 To investigate the @ref pipe_tasks_repair_Debug, put something like
157 @code{.py}
158 import lsstDebug
159 def DebugInfo(name):
160 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
161 if name == "lsst.pipe.tasks.repair":
162 di.display = {'repair.before':2, 'repair.after':3}
163 di.displayCR = True
164 return di
165
166 lsstDebug.Info = DebugInfo
167 @endcode
168 into your debug.py file and run runRepair.py with the @c --debug flag.
169
170
171 Conversion notes:
172 Display code should be updated once we settle on a standard way of controlling what is displayed.
173 """
174 ConfigClass = RepairConfig
175 _DefaultName = "repair"
176
177 def __init__(self, **kwargs):
178 pipeBase.Task.__init__(self, **kwargs)
179 if self.config.doInterpolate:
180 self.makeSubtask("interp")
181
182 @timeMethod
183 def run(self, exposure, defects=None, keepCRs=None):
184 """!Repair an Exposure's defects and cosmic rays
185
186 @param[in, out] exposure lsst.afw.image.Exposure to process. Exposure must have a valid Psf.
187 Modified in place.
188 @param[in] defects an lsst.meas.algorithms.DefectListT object. If None, do no
189 defect correction.
190 @param[in] keepCRs don't interpolate over the CR pixels (defer to RepairConfig if None)
191
192 @throws AssertionError with the following strings:
193
194 <DL>
195 <DT> No exposure provided
196 <DD> The object provided as exposure evaluates to False
197 <DT> No PSF provided
198 <DD> The Exposure has no associated Psf
199 </DL>
200 """
201 assert exposure, "No exposure provided"
202 psf = exposure.getPsf()
203 assert psf, "No PSF provided"
204
205 frame = getDebugFrame(self._display, "repair.before")
206 if frame:
207 afwDisplay.Display(frame).mtv(exposure)
208
209 if defects is not None and self.config.doInterpolate:
210 self.interp.run(exposure, defects=defects)
211
212 if self.config.doCosmicRay:
213 self.cosmicRaycosmicRay(exposure, keepCRs=keepCRs)
214
215 frame = getDebugFrame(self._display, "repair.after")
216 if frame:
217 afwDisplay.Display(frame).mtv(exposure)
218
219 def cosmicRay(self, exposure, keepCRs=None):
220 """Mask cosmic rays
221
222 @param[in,out] exposure Exposure to process
223 @param[in] keepCRs Don't interpolate over the CR pixels (defer to pex_config if None)
224 """
225 import lsstDebug
226 display = lsstDebug.Info(__name__).display
227 displayCR = lsstDebug.Info(__name__).displayCR
228
229 assert exposure, "No exposure provided"
230 psf = exposure.getPsf()
231 assert psf, "No psf provided"
232
233 # Blow away old mask
234 try:
235 mask = exposure.getMaskedImage().getMask()
236 crBit = mask.getMaskPlane("CR")
237 mask.clearMaskPlane(crBit)
238 except Exception:
239 pass
240
241 exposure0 = exposure # initial value of exposure
242 binSize = self.config.cosmicray.background.binSize
243 nx, ny = exposure.getWidth()/binSize, exposure.getHeight()/binSize
244 # Treat constant background as a special case to avoid the extra complexity in calling
245 # measAlg.SubtractBackgroundTask().
246 if nx*ny <= 1:
247 medianBg = afwMath.makeStatistics(exposure.getMaskedImage(), afwMath.MEDIAN).getValue()
248 modelBg = None
249 else:
250 # make a deep copy of the exposure before subtracting its background,
251 # because this routine is only allowed to modify the exposure by setting mask planes
252 # and interpolating over defects, not changing the background level
253 exposure = exposure.Factory(exposure, True)
254 subtractBackgroundTask = measAlg.SubtractBackgroundTask(config=self.config.cosmicray.background)
255 modelBg = subtractBackgroundTask.run(exposure).background
256 medianBg = 0.0
257
258 if keepCRs is None:
259 keepCRs = self.config.cosmicray.keepCRs
260 try:
261 crs = measAlg.findCosmicRays(exposure.getMaskedImage(), psf, medianBg,
262 pexConfig.makePropertySet(self.config.cosmicray), keepCRs)
263 if modelBg:
264 # Add back background image
265 img = exposure.getMaskedImage()
266 img += modelBg.getImageF()
267 del img
268 # Replace original image with CR subtracted image
269 exposure0.setMaskedImage(exposure.getMaskedImage())
270
271 except Exception:
272 if display:
273 afwDisplay.Display().mtv(exposure0, title="Failed CR")
274 raise
275
276 num = 0
277 if crs is not None:
278 mask = exposure0.getMaskedImage().getMask()
279 crBit = mask.getPlaneBitMask("CR")
280 afwDet.setMaskFromFootprintList(mask, crs, crBit)
281 num = len(crs)
282
283 if display and displayCR:
284 disp = afwDisplay.Display()
285 disp.incrDefaultFrame()
286 disp.mtv(exposure0, title="Post-CR")
287
288 with disp.Buffering():
289 for cr in crs:
290 afwDisplay.utils.drawBBox(cr.getBBox(), borderWidth=0.55)
291
292 self.log.info("Identified %s cosmic rays.", num)
A class to contain the data, WCS, and other information needed to describe an image of the sky.
Definition: Exposure.h:72
Encapsulate information about a bad portion of a detector.
Definition: Interp.h:72
def __init__(self, **kwargs)
Definition: repair.py:177
def run(self, exposure, defects=None, keepCRs=None)
Repair an Exposure's defects and cosmic rays.
Definition: repair.py:183
def cosmicRay(self, exposure, keepCRs=None)
Definition: repair.py:219
def mtv(data, frame=None, title="", wcs=None, *args, **kwargs)
Definition: ds9.py:92
Statistics makeStatistics(lsst::afw::image::Image< Pixel > const &img, lsst::afw::image::Mask< image::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Handle a watered-down front-end to the constructor (no variance)
Definition: Statistics.h:359
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.
def getDebugFrame(debugDisplay, name)
Definition: lsstDebug.py:95