LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
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
22__all__ = ["RepairConfig", "RepairTask"]
23
24import lsst.pex.config as pexConfig
25import lsst.afw.math as afwMath
26import lsst.afw.detection as afwDet
27import lsst.meas.algorithms as measAlg
28import lsst.pipe.base as pipeBase
29from lsstDebug import getDebugFrame
30import lsst.afw.display as afwDisplay
31from lsst.pipe.tasks.interpImage import InterpImageTask
32from lsst.utils.timer import timeMethod
33
34
35class RepairConfig(pexConfig.Config):
36 doInterpolate = pexConfig.Field(
37 dtype=bool,
38 doc="Interpolate over defects? (ignored unless you provide a list of defects)",
39 default=True,
40 )
41 doCosmicRay = pexConfig.Field(
42 dtype=bool,
43 doc="Find and mask out cosmic rays?",
44 default=True,
45 )
46 cosmicray = pexConfig.ConfigField(
47 dtype=measAlg.FindCosmicRaysConfig,
48 doc="Options for finding and masking cosmic rays",
49 )
50 interp = pexConfig.ConfigurableField(
51 target=InterpImageTask,
52 doc="Interpolate over bad image pixels",
53 )
54
55 def setDefaults(self):
56 self.interp.useFallbackValueAtEdge = True
57 self.interp.fallbackValueType = "MEANCLIP"
58 self.interp.negativeFallbackAllowed = True
59
60
61class RepairTask(pipeBase.Task):
62 """Repair an exposures defects and cosmic rays via interpolation.
63
64 This task operates on an lsst.afw.image.Exposure in place to
65 interpolate over a set of `~lsst.meas.algorithms.Defect` objects.
66
67 It will also, optionally, find and interpolate any cosmic rays in the lsst.afw.image.Exposure.
68
69 Notes
70 -----
71 Debugging:
72 The available debug variables in RepairTask are:
73
74 display :
75 A dictionary containing debug point names as keys with frame number as value. Valid keys are:
76 repair.before :
77 display image before any repair is done
78 repair.after :
79 display image after cosmic ray and defect correction
80 displayCR :
81 If True, display the exposure on ds9's frame 1 and overlay bounding boxes around detects CRs.
82
83 To investigate the pipe_tasks_repair_Debug, put something like
84
85 .. code-block :: none
86
87 import lsstDebug
88 def DebugInfo(name):
89 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
90 if name == "lsst.pipe.tasks.repair":
91 di.display = {'repair.before':2, 'repair.after':3}
92 di.displayCR = True
93 return di
94
95 lsstDebug.Info = DebugInfo
96 into your debug.py file and run runRepair.py with the --debug flag.
97
98 Conversion notes:
99 Display code should be updated once we settle on a standard way of controlling what is displayed.
100 """
101
102 ConfigClass = RepairConfig
103 _DefaultName = "repair"
104
105 def __init__(self, **kwargs):
106 pipeBase.Task.__init__(self, **kwargs)
107 if self.config.doInterpolate:
108 self.makeSubtask("interp")
109
110 @timeMethod
111 def run(self, exposure, defects=None, keepCRs=None):
112 """Repair an Exposure's defects and cosmic rays.
113
114 Parameters
115 ----------
116 exposure : `lsst.afw.image.Exposure`
117 Exposure must have a valid Psf.
118 Modified in place.
119 defects : `lsst.meas.algorithms.DefectListT` or `None`, optional
120 If `None`, do no defect correction.
121 keepCRs : `Unknown` or `None`, optional
122 Don't interpolate over the CR pixels (defer to ``RepairConfig`` if `None`).
123
124 Raises
125 ------
126 AssertionError
127 Raised if any of the following occur:
128 - No exposure provided.
129 - The object provided as exposure evaluates to False.
130 - No PSF provided.
131 - The Exposure has no associated Psf.
132 """
133 assert exposure, "No exposure provided"
134 psf = exposure.getPsf()
135 assert psf, "No PSF provided"
136
137 frame = getDebugFrame(self._display, "repair.before")
138 if frame:
139 afwDisplay.Display(frame).mtv(exposure)
140
141 if defects is not None and self.config.doInterpolate:
142 self.interp.run(exposure, defects=defects)
143
144 if self.config.doCosmicRay:
145 self.cosmicRay(exposure, keepCRs=keepCRs)
146
147 frame = getDebugFrame(self._display, "repair.after")
148 if frame:
149 afwDisplay.Display(frame).mtv(exposure)
150
151 def cosmicRay(self, exposure, keepCRs=None):
152 """Mask cosmic rays.
153
154 Parameters
155 ----------
156 exposure : `lsst.afw.image.Exposure`
157 Exposure to process.
158 keepCRs : `Unknown` or `None`, optional
159 Don't interpolate over the CR pixels (defer to ``pex_config`` if `None`).
160 """
161 import lsstDebug
162 display = lsstDebug.Info(__name__).display
163 displayCR = lsstDebug.Info(__name__).displayCR
164
165 assert exposure, "No exposure provided"
166 psf = exposure.getPsf()
167 assert psf, "No psf provided"
168
169 # Blow away old mask
170 try:
171 mask = exposure.getMaskedImage().getMask()
172 crBit = mask.getMaskPlane("CR")
173 mask.clearMaskPlane(crBit)
174 except Exception:
175 pass
176
177 exposure0 = exposure # initial value of exposure
178 binSize = self.config.cosmicray.background.binSize
179 nx, ny = exposure.getWidth()/binSize, exposure.getHeight()/binSize
180 # Treat constant background as a special case to avoid the extra complexity in calling
181 # measAlg.SubtractBackgroundTask().
182 if nx*ny <= 1:
183 medianBg = afwMath.makeStatistics(exposure.getMaskedImage(), afwMath.MEDIAN).getValue()
184 modelBg = None
185 else:
186 # make a deep copy of the exposure before subtracting its background,
187 # because this routine is only allowed to modify the exposure by setting mask planes
188 # and interpolating over defects, not changing the background level
189 exposure = exposure.Factory(exposure, True)
190 subtractBackgroundTask = measAlg.SubtractBackgroundTask(config=self.config.cosmicray.background)
191 modelBg = subtractBackgroundTask.run(exposure).background
192 medianBg = 0.0
193
194 if keepCRs is None:
195 keepCRs = self.config.cosmicray.keepCRs
196 try:
197 crs = measAlg.findCosmicRays(exposure.getMaskedImage(), psf, medianBg,
198 pexConfig.makePropertySet(self.config.cosmicray), keepCRs)
199 if modelBg:
200 # Add back background image
201 img = exposure.getMaskedImage()
202 img += modelBg.getImageF()
203 del img
204 # Replace original image with CR subtracted image
205 exposure0.setMaskedImage(exposure.getMaskedImage())
206
207 except Exception:
208 if display:
209 afwDisplay.Display().mtv(exposure0, title="Failed CR")
210 raise
211
212 num = 0
213 if crs is not None:
214 mask = exposure0.getMaskedImage().getMask()
215 crBit = mask.getPlaneBitMask("CR")
216 afwDet.setMaskFromFootprintList(mask, crs, crBit)
217 num = len(crs)
218
219 if display and displayCR:
220 disp = afwDisplay.Display()
221 disp.incrDefaultFrame()
222 disp.mtv(exposure0, title="Post-CR")
223
224 with disp.Buffering():
225 for cr in crs:
226 afwDisplay.utils.drawBBox(cr.getBBox(), borderWidth=0.55)
227
228 text = "kept" if keepCRs else "interpolated over"
229 self.log.info("Identified and %s %s cosmic rays.", text, num)
230 self.metadata["cosmic_ray_count"] = num
cosmicRay(self, exposure, keepCRs=None)
Definition repair.py:151
run(self, exposure, defects=None, keepCRs=None)
Definition repair.py:111
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:361