LSST Applications 26.0.0,g0265f82a02+6660c170cc,g07994bdeae+30b05a742e,g0a0026dc87+17526d298f,g0a60f58ba1+17526d298f,g0e4bf8285c+96dd2c2ea9,g0ecae5effc+c266a536c8,g1e7d6db67d+6f7cb1f4bb,g26482f50c6+6346c0633c,g2bbee38e9b+6660c170cc,g2cc88a2952+0a4e78cd49,g3273194fdb+f6908454ef,g337abbeb29+6660c170cc,g337c41fc51+9a8f8f0815,g37c6e7c3d5+7bbafe9d37,g44018dc512+6660c170cc,g4a941329ef+4f7594a38e,g4c90b7bd52+5145c320d2,g58be5f913a+bea990ba40,g635b316a6c+8d6b3a3e56,g67924a670a+bfead8c487,g6ae5381d9b+81bc2a20b4,g93c4d6e787+26b17396bd,g98cecbdb62+ed2cb6d659,g98ffbb4407+81bc2a20b4,g9ddcbc5298+7f7571301f,ga1e77700b3+99e9273977,gae46bcf261+6660c170cc,gb2715bf1a1+17526d298f,gc86a011abf+17526d298f,gcf0d15dbbd+96dd2c2ea9,gdaeeff99f8+0d8dbea60f,gdb4ec4c597+6660c170cc,ge23793e450+96dd2c2ea9,gf041782ebf+171108ac67
LSST Data Management Base Package
Loading...
Searching...
No Matches
assembleCcdTask.py
Go to the documentation of this file.
1# This file is part of ip_isr.
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__ = ["AssembleCcdTask"]
23
24import lsst.afw.cameraGeom as cameraGeom
25import lsst.afw.cameraGeom.utils as cameraGeomUtils
26import lsst.afw.display as afwDisplay
27import lsst.afw.image as afwImage
28import lsst.pex.config as pexConfig
29import lsst.pipe.base as pipeBase
30from lsstDebug import getDebugFrame
31
32
33class AssembleCcdConfig(pexConfig.Config):
34 doTrim = pexConfig.Field(
35 doc="trim out non-data regions?",
36 dtype=bool,
37 default=True,
38 )
39 keysToRemove = pexConfig.ListField(
40 doc="FITS headers to remove (in addition to DATASEC, BIASSEC, TRIMSEC and perhaps GAIN)",
41 dtype=str,
42 default=(),
43 )
44
45
51
52
53class AssembleCcdTask(pipeBase.Task):
54 r"""!
55 @anchor AssembleCcdTask_
56
57 @brief Assemble a set of amplifier images into a full detector size set of
58 pixels.
59
60 @section ip_isr_assemble_Contents Contents
61
62 - @ref ip_isr_assemble_Purpose
63 - @ref ip_isr_assemble_Initialize
64 - @ref ip_isr_assemble_IO
65 - @ref ip_isr_assemble_Config
66 - @ref ip_isr_assemble_Debug
67 - @ref ip_isr_assemble_Example
68
69 @section ip_isr_assemble_Purpose Description
70
71 This task assembles sections of an image into a larger mosaic. The
72 sub-sections are typically amplifier sections and are to be assembled
73 into a detector size pixel grid. The assembly is driven by the entries in
74 the raw amp information. The task can be configured to return a detector
75 image with non-data (e.g. overscan) pixels included. The task can also
76 renormalize the pixel values to a nominal gain of 1. The task also
77 removes exposure metadata that has context in raw amps, but not in trimmed
78 detectors (e.g. 'BIASSEC').
79
80 @section ip_isr_assemble_Initialize Task initialization
81
82 @copydoc __init__
83
84 @section ip_isr_assemble_IO Inputs/Outputs to the assembleCcd method
85
86 @copydoc assembleCcd
87
88 @section ip_isr_assemble_Config Configuration parameters
89
90 See @ref AssembleCcdConfig
91
92 @section ip_isr_assemble_Debug Debug variables
93
94 The command line task interface supports a flag @c -d to import @b debug.py from your
95 @c PYTHONPATH; see <a
96 href="https://developer.lsst.io/stack/debug.html">Debugging Tasks with
97 lsstDebug</a> for more about @b debug.py files.
98
99 The available variables in AssembleCcdTask are:
100 <DL>
101 <DT> @c display
102 <DD> A dictionary containing debug point names as keys with frame number
103 as value. Valid keys are:
104 <DL>
105 <DT> assembledExposure
106 <DD> display assembled exposure
107 </DL>
108 </DL>
109
110 @section ip_isr_assemble_Example A complete example of using
111 AssembleCcdTask
112
113 <HR>
114 To investigate the @ref ip_isr_assemble_Debug, put something like
115 @code{.py}
116 import lsstDebug
117 def DebugInfo(name):
118 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call
119 # us recursively
120 if name == "lsst.ip.isr.assembleCcdTask":
121 di.display = {'assembledExposure':2}
122 return di
123
124 lsstDebug.Info = DebugInfo
125 @endcode
126 into your debug.py file and run runAssembleTask.py with the @c --debug
127 flag.
128
129
130 Conversion notes:
131 Display code should be updated once we settle on a standard way of
132 controlling what is displayed.
133 """
134 ConfigClass = AssembleCcdConfig
135 _DefaultName = "assembleCcd"
136
137 def __init__(self, **kwargs):
138 """!Initialize the AssembleCcdTask
139
140 The keys for removal specified in the config are added to a default
141 set: ('DATASEC', 'BIASSEC', 'TRIMSEC', 'GAIN')
142 """
143 pipeBase.Task.__init__(self, **kwargs)
144
145 self.allKeysToRemove = ('DATASEC', 'BIASSEC', 'TRIMSEC', 'GAIN') + tuple(self.config.keysToRemove)
146
147 def assembleCcd(self, assembleInput):
148 """!Assemble a set of amps into a single CCD size image
149 @param[in] assembleInput -- Either a dictionary of amp
150 lsst.afw.image.Exposures or a single
151 lsst.afw.image.Exposure containing all raw
152 amps. If a dictionary of amp exposures,
153 the key should be the amp name.
154 @return assembledCcd -- An lsst.afw.image.Exposure of the assembled
155 amp sections.
156
157 @throws TypeError with the following string:
158
159 <DL>
160 <DT> Expected either a dictionary of amp exposures or a single raw
161 exposure.
162 <DD> The input exposures to be assembled do not adhere to the
163 required format.
164 </DL>
165
166 @throws RuntimeError with the following string:
167
168 <DL>
169 <DT> No ccd detector found
170 <DD> The detector set on the input exposure is not set.
171 </DL>
172 """
173 ccd = None
174 if isinstance(assembleInput, dict):
175 # assembleInput is a dictionary of amp name: amp exposure
176
177 # Assume all amps have the same detector, so get the detector from
178 # an arbitrary amp.
179 ccd = next(iter(assembleInput.values())).getDetector()
180
181 def getNextExposure(amp):
182 return assembleInput[amp.getName()]
183 elif hasattr(assembleInput, "getMaskedImage"):
184 # assembleInput is a single exposure
185 ccd = assembleInput.getDetector()
186
187 def getNextExposure(amp):
188 return assembleInput
189 else:
190 raise TypeError("Expected either a dictionary of amp exposures or a single raw exposure")
191
192 if ccd is None:
193 raise RuntimeError("No ccd detector found")
194
195 if not self.config.doTrim:
196 outBox = cameraGeomUtils.calcRawCcdBBox(ccd)
197 else:
198 outBox = ccd.getBBox()
199 outExposure = afwImage.ExposureF(outBox)
200 outMI = outExposure.getMaskedImage()
201
202 if self.config.doTrim:
203 assemble = cameraGeom.assembleAmplifierImage
204 else:
205 assemble = cameraGeom.assembleAmplifierRawImage
206
207 for amp in ccd:
208 inMI = getNextExposure(amp).getMaskedImage()
209 assemble(outMI, inMI, amp)
210 #
211 # If we are returning an "untrimmed" image (with overscans and
212 # extended register) we need to update the ampInfo table in the
213 # Detector as we've moved the amp images into
214 # place in a single Detector image
215 #
216 if not self.config.doTrim:
217 ccd = cameraGeom.makeUpdatedDetector(ccd)
218
219 outExposure.setDetector(ccd)
220 self.postprocessExposure(outExposure=outExposure, inExposure=getNextExposure(ccd[0]))
221
222 return outExposure
223
224 def postprocessExposure(self, outExposure, inExposure):
225 """Set exposure non-image attributes, including wcs and metadata and
226 display exposure (if requested)
227
228 Call after assembling the pixels
229
230 @param[in,out] outExposure assembled exposure:
231 - removes unwanted keywords
232 - sets wcs, filter, and detector
233 @param[in] inExposure input exposure
234 """
235 if inExposure.hasWcs():
236 outExposure.setWcs(inExposure.getWcs())
237
238 exposureMetadata = inExposure.getMetadata()
239 for key in self.allKeysToRemove:
240 if exposureMetadata.exists(key):
241 exposureMetadata.remove(key)
242 outExposure.setMetadata(exposureMetadata)
243
244 # note: don't copy PhotoCalib, because it is assumed to be unknown in
245 # raw data.
246 outExposure.info.id = inExposure.info.id
247 outExposure.setFilter(inExposure.getFilter())
248 outExposure.getInfo().setVisitInfo(inExposure.getInfo().getVisitInfo())
249
250 frame = getDebugFrame(self._display, "assembledExposure")
251 if frame:
252 afwDisplay.Display(frame=frame).mtv(outExposure, title="postprocessExposure")
A class to contain the data, WCS, and other information needed to describe an image of the sky.
Definition Exposure.h:72
postprocessExposure(self, outExposure, inExposure)
assembleCcd(self, assembleInput)
Assemble a set of amps into a single CCD size image.
__init__(self, **kwargs)
Initialize the AssembleCcdTask.