Coverage for python/lsst/obs/lsstSim/lsstSimIsrTask.py : 22%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#
2# LSST Data Management System
3# Copyright 2008-2016 AURA/LSST.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
22import lsst.pex.config as pexConfig
23import lsst.pipe.base as pipeBase
24from lsstDebug import getDebugFrame
25from lsst.afw.display import getDisplay
26from lsst.ip.isr import IsrTask
27from lsst.pipe.tasks.snapCombine import SnapCombineTask
28import numpy
30__all__ = ["LsstSimIsrTask"]
33class LsstSimIsrConfig(IsrTask.ConfigClass):
34 doWriteSnaps = pexConfig.Field(
35 dtype=bool,
36 doc="Persist snapExp for each snap?",
37 default=True,
38 )
39 doSnapCombine = pexConfig.Field(
40 dtype=bool,
41 doc="Combine Snaps? If False then use snap 0 as output exposure.",
42 default=True,
43 )
44 snapCombine = pexConfig.ConfigurableField(
45 target=SnapCombineTask,
46 doc="Combine snaps task",
47 )
49 def setDefaults(self):
50 IsrTask.ConfigClass.setDefaults(self)
51 self.doDark = False # LSSTSims do not include darks at this time
52 self.snapCombine.averageKeys = ("TAI", "MJD-OBS", "AIRMASS", "AZIMUTH", "ZENITH",
53 "ROTANG", "SPIDANG", "ROTRATE")
54 self.snapCombine.sumKeys = ("EXPTIME", "CREXPTM", "DARKTIME")
57class LsstSimIsrTask(IsrTask):
59 r"""
60 \section obs_lsstSim_isr_Debug Debug variables
62 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
63 flag \c --debug, \c -d to import \b debug.py from your \c PYTHONPATH; see <a
64 href="http://lsst-web.ncsa.illinois.edu/~buildbot/doxygen/x_masterDoxyDoc/base_debug.html">
65 Using lsstDebug to control debugging output</a> for more about \b debug.py files.
67 The available variables in LsstSimIsrTask are:
68 <DL>
69 <DT> \c display
70 <DD> A dictionary containing debug point names as keys with frame number as value. Valid keys are:
71 <DL>
72 <DT> snapExp0
73 <DD> Display ISR-corrected snap 0
74 <DT> snapExp1
75 <DD> Display ISR-corrected snap 1
76 <DT> postISRCCD
77 <DD> Display final exposure
78 </DL>
79 </DL>
80 """
81 ConfigClass = LsstSimIsrConfig
83 def __init__(self, **kwargs):
84 IsrTask.__init__(self, **kwargs)
85 self.makeSubtask("snapCombine")
87 def unmaskSatHotPixels(self, exposure):
88 mi = exposure.getMaskedImage()
89 mask = mi.getMask()
90 maskarr = mask.getArray()
91 badBitmask = numpy.array(mask.getPlaneBitMask("BAD"), dtype=maskarr.dtype)
92 satBitmask = numpy.array(mask.getPlaneBitMask("SAT"), dtype=maskarr.dtype)
93 orBitmask = badBitmask | satBitmask
94 andMask = ~satBitmask
95 idx = numpy.where((maskarr & orBitmask) == orBitmask)
96 maskarr[idx] &= andMask
98 def saturationInterpolation(self, ccdExposure):
99 r"""!Unmask hot pixels and interpolate over saturated pixels, in place
101 \param[in,out] ccdExposure exposure to process
103 \warning:
104 - Call saturationDetection first, so that saturated pixels have been identified in the "SAT" mask.
105 - Call this after CCD assembly, since saturated regions may cross amplifier boundaries
106 """
107 self.unmaskSatHotPixels(ccdExposure)
108 super(LsstSimIsrTask, self).saturationInterpolation(ccdExposure)
110 @pipeBase.timeMethod
111 def runDataRef(self, sensorRef):
112 """Do instrument signature removal on an exposure
114 Correct for saturation, bias, overscan, dark, flat..., perform CCD assembly,
115 optionally combine snaps, and interpolate over defects and saturated pixels.
117 If config.doSnapCombine true then combine the two ISR-corrected snaps to produce the final exposure.
118 If config.doSnapCombine false then uses ISR-corrected snap 0 as the final exposure.
119 In either case, the final exposure is persisted as "postISRCCD" if config.doWriteSpans is True,
120 and the two snaps are persisted as "snapExp" if config.doWriteSnaps is True.
122 @param sensorRef daf.persistence.butlerSubset.ButlerDataRef of the data to be processed
123 @return a pipeBase.Struct with fields:
124 - exposure: the exposure after application of ISR
125 """
126 self.log.info("Performing ISR on sensor %s", sensorRef.dataId)
127 camera = sensorRef.get("camera")
128 snapDict = dict()
129 for snapRef in sensorRef.subItems(level="snap"):
130 snapId = snapRef.dataId['snap']
131 if snapId not in (0, 1):
132 raise RuntimeError("Unrecognized snapId=%s" % (snapId,))
134 self.log.info("Performing ISR on snap %s", snapRef.dataId)
135 ccdExposure = snapRef.get('raw')
136 isrData = self.readIsrData(snapRef, ccdExposure)
137 ccdExposure = self.run(ccdExposure, camera=camera, **isrData.getDict()).exposure
138 snapDict[snapId] = ccdExposure
140 if self.config.doWriteSnaps:
141 sensorRef.put(ccdExposure, "snapExp", snap=snapId)
143 frame = getDebugFrame(self._display, "snapExp%d" % (snapId,))
144 if frame:
145 getDisplay(frame).mtv(ccdExposure)
147 if self.config.doSnapCombine:
148 loadSnapDict(snapDict, snapIdList=(0, 1), sensorRef=sensorRef)
149 postIsrExposure = self.snapCombine.run(snapDict[0], snapDict[1]).exposure
150 else:
151 self.log.warn("doSnapCombine false; using snap 0 as the result")
152 loadSnapDict(snapDict, snapIdList=(0,), sensorRef=sensorRef)
153 postIsrExposure = snapDict[0]
155 if self.config.doWrite:
156 sensorRef.put(postIsrExposure, "postISRCCD")
158 frame = getDebugFrame(self._display, "postISRCCD")
159 if frame:
160 getDisplay(frame).mtv(postIsrExposure)
162 return pipeBase.Struct(
163 exposure=postIsrExposure,
164 )
167def loadSnapDict(snapDict, snapIdList, sensorRef):
168 """Load missing snaps from disk.
170 @paramp[in,out] snapDict: a dictionary of snapId: snap exposure ("snapExp")
171 @param[in] snapIdList: a list of snap IDs
172 @param[in] sensorRef: sensor reference for snap, excluding the snap ID.
173 """
174 for snapId in snapIdList:
175 if snapId not in snapDict:
176 snapExposure = sensorRef.get("snapExp", snap=snapId)
177 if snapExposure is None:
178 raise RuntimeError("Could not find snapExp for snap=%s; id=%s" % (snapId, sensorRef.dataId))
179 snapDict[snapId] = snapExposure