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
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
22import lsst.afw.cameraGeom as cameraGeom
23import lsst.afw.cameraGeom.utils as cameraGeomUtils
24import lsst.afw.display as afwDisplay
25import lsst.afw.image as afwImage
26import lsst.pex.config as pexConfig
27import lsst.pipe.base as pipeBase
28from lsstDebug import getDebugFrame
29
30__all__ = ["AssembleCcdTask"]
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 @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink
95 interface supports a flag @c -d to import @b debug.py from your
96 @c PYTHONPATH; see <a
97 href="https://developer.lsst.io/stack/debug.html">Debugging Tasks with
98 lsstDebug</a> for more about @b debug.py files.
99
100 The available variables in AssembleCcdTask are:
101 <DL>
102 <DT> @c display
103 <DD> A dictionary containing debug point names as keys with frame number
104 as value. Valid keys are:
105 <DL>
106 <DT> assembledExposure
107 <DD> display assembled exposure
108 </DL>
109 </DL>
110
111 @section ip_isr_assemble_Example A complete example of using
112 AssembleCcdTask
113
114 <HR>
115 To investigate the @ref ip_isr_assemble_Debug, put something like
116 @code{.py}
117 import lsstDebug
118 def DebugInfo(name):
119 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call
120 # us recursively
121 if name == "lsst.ip.isr.assembleCcdTask":
122 di.display = {'assembledExposure':2}
123 return di
124
125 lsstDebug.Info = DebugInfo
126 @endcode
127 into your debug.py file and run runAssembleTask.py with the @c --debug
128 flag.
129
130
131 Conversion notes:
132 Display code should be updated once we settle on a standard way of
133 controlling what is displayed.
134 """
135 ConfigClass = AssembleCcdConfig
136 _DefaultName = "assembleCcd"
137
138 def __init__(self, **kwargs):
139 """!Initialize the AssembleCcdTask
140
141 The keys for removal specified in the config are added to a default
142 set: ('DATASEC', 'BIASSEC', 'TRIMSEC', 'GAIN')
143 """
144 pipeBase.Task.__init__(self, **kwargs)
145
146 self.allKeysToRemoveallKeysToRemove = ('DATASEC', 'BIASSEC', 'TRIMSEC', 'GAIN') + tuple(self.config.keysToRemove)
147
148 def assembleCcd(self, assembleInput):
149 """!Assemble a set of amps into a single CCD size image
150 @param[in] assembleInput -- Either a dictionary of amp
151 lsst.afw.image.Exposures or a single
152 lsst.afw.image.Exposure containing all raw
153 amps. If a dictionary of amp exposures,
154 the key should be the amp name.
155 @return assembledCcd -- An lsst.afw.image.Exposure of the assembled
156 amp sections.
157
158 @throws TypeError with the following string:
159
160 <DL>
161 <DT> Expected either a dictionary of amp exposures or a single raw
162 exposure.
163 <DD> The input exposures to be assembled do not adhere to the
164 required format.
165 </DL>
166
167 @throws RuntimeError with the following string:
168
169 <DL>
170 <DT> No ccd detector found
171 <DD> The detector set on the input exposure is not set.
172 </DL>
173 """
174 ccd = None
175 if isinstance(assembleInput, dict):
176 # assembleInput is a dictionary of amp name: amp exposure
177
178 # Assume all amps have the same detector, so get the detector from
179 # an arbitrary amp.
180 ccd = next(iter(assembleInput.values())).getDetector()
181
182 def getNextExposure(amp):
183 return assembleInput[amp.getName()]
184 elif hasattr(assembleInput, "getMaskedImage"):
185 # assembleInput is a single exposure
186 ccd = assembleInput.getDetector()
187
188 def getNextExposure(amp):
189 return assembleInput
190 else:
191 raise TypeError("Expected either a dictionary of amp exposures or a single raw exposure")
192
193 if ccd is None:
194 raise RuntimeError("No ccd detector found")
195
196 if not self.config.doTrim:
197 outBox = cameraGeomUtils.calcRawCcdBBox(ccd)
198 else:
199 outBox = ccd.getBBox()
200 outExposure = afwImage.ExposureF(outBox)
201 outMI = outExposure.getMaskedImage()
202
203 if self.config.doTrim:
204 assemble = cameraGeom.assembleAmplifierImage
205 else:
206 assemble = cameraGeom.assembleAmplifierRawImage
207
208 for amp in ccd:
209 inMI = getNextExposure(amp).getMaskedImage()
210 assemble(outMI, inMI, amp)
211 #
212 # If we are returning an "untrimmed" image (with overscans and
213 # extended register) we need to update the ampInfo table in the
214 # Detector as we've moved the amp images into
215 # place in a single Detector image
216 #
217 if not self.config.doTrim:
218 ccd = cameraGeom.makeUpdatedDetector(ccd)
219
220 outExposure.setDetector(ccd)
221 self.postprocessExposurepostprocessExposure(outExposure=outExposure, inExposure=getNextExposure(ccd[0]))
222
223 return outExposure
224
225 def postprocessExposure(self, outExposure, inExposure):
226 """Set exposure non-image attributes, including wcs and metadata and
227 display exposure (if requested)
228
229 Call after assembling the pixels
230
231 @param[in,out] outExposure assembled exposure:
232 - removes unwanted keywords
233 - sets wcs, filter, and detector
234 @param[in] inExposure input exposure
235 """
236 if inExposure.hasWcs():
237 outExposure.setWcs(inExposure.getWcs())
238
239 exposureMetadata = inExposure.getMetadata()
240 for key in self.allKeysToRemoveallKeysToRemove:
241 if exposureMetadata.exists(key):
242 exposureMetadata.remove(key)
243 outExposure.setMetadata(exposureMetadata)
244
245 # note: don't copy PhotoCalib, because it is assumed to be unknown in
246 # raw data.
247 outExposure.info.id = inExposure.info.id
248 outExposure.setFilter(inExposure.getFilter())
249 outExposure.getInfo().setVisitInfo(inExposure.getInfo().getVisitInfo())
250
251 frame = getDebugFrame(self._display, "assembledExposure")
252 if frame:
253 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
def assembleCcd(self, assembleInput)
Assemble a set of amps into a single CCD size image.
def __init__(self, **kwargs)
Initialize the AssembleCcdTask.
def postprocessExposure(self, outExposure, inExposure)
def mtv(data, frame=None, title="", wcs=None, *args, **kwargs)
Definition: ds9.py:92
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
def getDebugFrame(debugDisplay, name)
Definition: lsstDebug.py:95