27 from lsstDebug
import getDebugFrame
29 from .isr
import calcEffectiveGain
31 __all__ = [
"AssembleCcdTask"]
35 setGain = pexConfig.Field(
40 doRenorm = pexConfig.Field(
41 doc=
"renormalize to a gain of 1? (ignored if setGain false). "
42 "Setting to True gives 1 ADU per electron. "
43 "Setting to True is not recommended for mosaic cameras because it breaks normalization across "
44 "the focal plane. However, if the CCDs are sufficiently flat then the resulting error "
49 doTrim = pexConfig.Field(
50 doc=
"trim out non-data regions?",
54 keysToRemove = pexConfig.ListField(
55 doc=
"FITS headers to remove (in addition to DATASEC, BIASSEC, TRIMSEC and perhaps GAIN)",
70 \anchor AssembleCcdTask_
72 \brief Assemble a set of amplifier images into a full detector size set of pixels.
74 \section ip_isr_assemble_Contents Contents
76 - \ref ip_isr_assemble_Purpose
77 - \ref ip_isr_assemble_Initialize
78 - \ref ip_isr_assemble_IO
79 - \ref ip_isr_assemble_Config
80 - \ref ip_isr_assemble_Debug
81 - \ref ip_isr_assemble_Example
83 \section ip_isr_assemble_Purpose Description
85 This task assembles sections of an image into a larger mosaic. The sub-sections
86 are typically amplifier sections and are to be assembled into a detector size pixel grid.
87 The assembly is driven by the entries in the raw amp information. The task can be configured
88 to return a detector image with non-data (e.g. overscan) pixels included. The task can also
89 renormalize the pixel values to a nominal gain of 1. The task also removes exposure metadata that
90 has context in raw amps, but not in trimmed detectors (e.g. 'BIASSEC').
92 \section ip_isr_assemble_Initialize Task initialization
96 \section ip_isr_assemble_IO Inputs/Outputs to the assembleCcd method
100 \section ip_isr_assemble_Config Configuration parameters
102 See \ref AssembleCcdConfig
104 \section ip_isr_assemble_Debug Debug variables
106 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
107 flag \c -d to import \b debug.py from your \c PYTHONPATH; see <a
108 href="http://lsst-web.ncsa.illinois.edu/~buildbot/doxygen/x_masterDoxyDoc/base_debug.html">
109 Using lsstDebug to control debugging output</a> for more about \b debug.py files.
111 The available variables in AssembleCcdTask are:
114 <DD> A dictionary containing debug point names as keys with frame number as value. Valid keys are:
116 <DT> assembledExposure
117 <DD> display assembled exposure
121 \section ip_isr_assemble_Example A complete example of using AssembleCcdTask
123 This code is in runAssembleTask.py in the examples directory, and can be run as \em e.g.
125 python examples/runAssembleTask.py
128 \dontinclude runAssembleTask.py
129 Import the task. There are other imports. Read the source file for more info.
130 \skipline AssembleCcdTask
132 \dontinclude exampleUtils.py
133 Create some input images with the help of some utilities in examples/exampleUtils.py
134 \skip makeAssemblyInput
136 The above numbers can be changed. The assumption that the readout corner is flipped on every other amp is
137 hardcoded in createDetector.
139 \dontinclude runAssembleTask.py
140 Run the assembler task
145 To investigate the \ref ip_isr_assemble_Debug, put something like
149 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
150 if name == "lsst.ip.isr.assembleCcdTask":
151 di.display = {'assembledExposure':2}
154 lsstDebug.Info = DebugInfo
156 into your debug.py file and run runAssembleTask.py with the \c --debug flag.
160 Display code should be updated once we settle on a standard way of controlling what is displayed.
162 ConfigClass = AssembleCcdConfig
163 _DefaultName =
"assembleCcd"
166 """!Initialize the AssembleCcdTask
168 The keys for removal specified in the config are added to a default set:
169 ('DATASEC', 'BIASSEC', 'TRIMSEC', 'GAIN')
171 pipeBase.Task.__init__(self, **kwargs)
173 self.
allKeysToRemove = (
'DATASEC',
'BIASSEC',
'TRIMSEC',
'GAIN') + tuple(self.config.keysToRemove)
176 """!Assemble a set of amps into a single CCD size image
177 \param[in] assembleInput -- Either a dictionary of amp lsst.afw.image.Exposures or a single
178 lsst.afw.image.Exposure containing all raw
179 amps. If a dictionary of amp exposures,
180 the key should be the amp name.
181 \return assembledCcd -- An lsst.afw.image.Exposure of the assembled amp sections.
183 \throws TypeError with the following string:
186 <DT> Expected either a dictionary of amp exposures or a single raw exposure
187 <DD> The input exposures to be assembled do not adhere to the required format.
190 \throws RuntimeError with the following string:
193 <DT> No ccd detector found
194 <DD> The detector set on the input exposure is not set.
198 if isinstance(assembleInput, dict):
202 ccd = next(
iter(assembleInput.values())).getDetector()
204 def getNextExposure(amp):
205 return assembleInput[amp.getName()]
206 elif hasattr(assembleInput,
"getMaskedImage"):
208 ccd = assembleInput.getDetector()
210 def getNextExposure(amp):
213 raise TypeError(
"Expected either a dictionary of amp exposures or a single raw exposure")
216 raise RuntimeError(
"No ccd detector found")
218 if not self.config.doTrim:
219 outBox = cameraGeomUtils.calcRawCcdBBox(ccd)
221 outBox = ccd.getBBox()
222 outExposure = afwImage.ExposureF(outBox)
223 outMI = outExposure.getMaskedImage()
225 if self.config.doTrim:
226 assemble = cameraGeom.assembleAmplifierImage
228 assemble = cameraGeom.assembleAmplifierRawImage
231 inMI = getNextExposure(amp).getMaskedImage()
232 assemble(outMI, inMI, amp)
233 outExposure.setDetector(ccd)
239 """Set exposure non-image attributes, including wcs and metadata and display exposure (if requested)
241 Call after assembling the pixels
243 @param[in,out] outExposure assembled exposure:
244 - removes unwanted keywords
245 - sets calib, filter, and detector
246 @param[in] inExposure input exposure
248 self.
setWcs(outExposure=outExposure, inExposure=inExposure)
250 exposureMetadata = inExposure.getMetadata()
252 if exposureMetadata.exists(key):
253 exposureMetadata.remove(key)
254 outExposure.setMetadata(exposureMetadata)
256 if self.config.setGain:
257 self.
setGain(outExposure=outExposure)
260 outExposure.setFilter(inExposure.getFilter())
261 outExposure.getInfo().setVisitInfo(inExposure.getInfo().getVisitInfo())
267 def setWcs(self, outExposure, inExposure):
268 """Set output WCS = input WCS, adjusted as required for datasecs not starting at lower left corner
270 @param[in,out] outExposure assembled exposure; wcs is set
271 @param[in] inExposure input exposure
273 if inExposure.hasWcs():
274 wcs = inExposure.getWcs()
275 ccd = outExposure.getDetector()
278 raise RuntimeError(
"No amplifier detector information found")
279 cameraGeomUtils.prepareWcsData(wcs, amp0, isTrimmed=self.config.doTrim)
280 outExposure.setWcs(wcs)
282 self.log.warn(
"No WCS found in input exposure")
285 """Renormalize, if requested, and set gain metadata
287 @param[in,out] outExposure assembled exposure:
288 - scales the pixels if config.doRenorm is true
289 - adds some gain keywords to the metadata
291 if outExposure.getMaskedImage().getVariance().getArray().max() == 0:
292 raise RuntimeError(
"Can't calculate the effective gain since the variance plane is set to zero")
293 ccd = outExposure.getDetector()
294 exposureMetadata = outExposure.getMetadata()
298 gain += amp.getGain()
301 if self.config.doRenorm:
302 mi = outExposure.getMaskedImage()
304 exposureMetadata.set(
"GAIN", 1.0)
306 exposureMetadata.add(
"MEDGAIN", medgain)
307 exposureMetadata.add(
"MEANGAIN", meangain)
308 exposureMetadata.add(
"GAINEFF", medgain)
Assemble a set of amplifier images into a full detector size set of pixels.
def assembleCcd
Assemble a set of amps into a single CCD size image.
def __init__
Initialize the AssembleCcdTask.