LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
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 
22 import lsst.pex.config as pexConfig
23 import lsst.afw.math as afwMath
24 import lsst.afw.detection as afwDet
25 import lsst.meas.algorithms as measAlg
26 import lsst.pipe.base as pipeBase
27 from lsstDebug import getDebugFrame
28 import lsst.afw.display as afwDisplay
29 from lsst.pipe.tasks.interpImage import InterpImageTask
30 from lsst.utils.timer import timeMethod
31 
32 
33 class 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 
66 class 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
86  lsst.meas.algorithms.Defect objects.
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 @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink 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)
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