26 import lsst.pex.config 
as pexConfig
 
   28 from lsstDebug 
import getDebugFrame
 
   30 __all__ = [
"AssembleCcdTask"]
 
   34     doTrim = pexConfig.Field(
 
   35         doc=
"trim out non-data regions?",
 
   39     keysToRemove = pexConfig.ListField(
 
   40         doc=
"FITS headers to remove (in addition to DATASEC, BIASSEC, TRIMSEC and perhaps GAIN)",
 
   55     @anchor AssembleCcdTask_ 
   57     @brief Assemble a set of amplifier images into a full detector size set of pixels. 
   59     @section ip_isr_assemble_Contents Contents 
   61      - @ref ip_isr_assemble_Purpose 
   62      - @ref ip_isr_assemble_Initialize 
   63      - @ref ip_isr_assemble_IO 
   64      - @ref ip_isr_assemble_Config 
   65      - @ref ip_isr_assemble_Debug 
   66      - @ref ip_isr_assemble_Example 
   68     @section ip_isr_assemble_Purpose Description 
   70     This task assembles sections of an image into a larger mosaic.  The sub-sections 
   71     are typically amplifier sections and are to be assembled into a detector size pixel grid. 
   72     The assembly is driven by the entries in the raw amp information.  The task can be configured 
   73     to return a detector image with non-data (e.g. overscan) pixels included.  The task can also 
   74     renormalize the pixel values to a nominal gain of 1.  The task also removes exposure metadata that 
   75     has context in raw amps, but not in trimmed detectors (e.g. 'BIASSEC'). 
   77     @section ip_isr_assemble_Initialize Task initialization 
   81     @section ip_isr_assemble_IO Inputs/Outputs to the assembleCcd method 
   85     @section ip_isr_assemble_Config Configuration parameters 
   87     See @ref AssembleCcdConfig 
   89     @section ip_isr_assemble_Debug Debug variables 
   91     The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a 
   92     flag @c -d to import @b debug.py from your @c PYTHONPATH; see <a 
   93     href="http://lsst-web.ncsa.illinois.edu/~buildbot/doxygen/x_masterDoxyDoc/base_debug.html"> 
   94     Using lsstDebug to control debugging output</a> for more about @b debug.py files. 
   96     The available variables in AssembleCcdTask are: 
   99       <DD> A dictionary containing debug point names as keys with frame number as value. Valid keys are: 
  101           <DT> assembledExposure 
  102           <DD> display assembled exposure 
  106     @section ip_isr_assemble_Example A complete example of using AssembleCcdTask 
  109     To investigate the @ref ip_isr_assemble_Debug, put something like 
  113         di = lsstDebug.getInfo(name)        # N.b. lsstDebug.Info(name) would call us recursively 
  114         if name == "lsst.ip.isr.assembleCcdTask": 
  115             di.display = {'assembledExposure':2} 
  118     lsstDebug.Info = DebugInfo 
  120     into your debug.py file and run runAssembleTask.py with the @c --debug flag. 
  124         Display code should be updated once we settle on a standard way of controlling what is displayed. 
  126     ConfigClass = AssembleCcdConfig
 
  127     _DefaultName = 
"assembleCcd" 
  130         """!Initialize the AssembleCcdTask 
  132         The keys for removal specified in the config are added to a default set: 
  133         ('DATASEC', 'BIASSEC', 'TRIMSEC', 'GAIN') 
  135         pipeBase.Task.__init__(self, **kwargs)
 
  137         self.
allKeysToRemove = (
'DATASEC', 
'BIASSEC', 
'TRIMSEC', 
'GAIN') + tuple(self.config.keysToRemove)
 
  140         """!Assemble a set of amps into a single CCD size image 
  141         @param[in] assembleInput -- Either a dictionary of amp lsst.afw.image.Exposures or a single 
  142                                     lsst.afw.image.Exposure containing all raw 
  143                                     amps.  If a dictionary of amp exposures, 
  144                                     the key should be the amp name. 
  145         @return assembledCcd -- An lsst.afw.image.Exposure of the assembled amp sections. 
  147         @throws TypeError with the following string: 
  150           <DT> Expected either a dictionary of amp exposures or a single raw exposure 
  151           <DD> The input exposures to be assembled do not adhere to the required format. 
  154         @throws RuntimeError with the following string: 
  157           <DT> No ccd detector found 
  158           <DD> The detector set on the input exposure is not set. 
  162         if isinstance(assembleInput, dict):
 
  166             ccd = 
next(
iter(assembleInput.values())).getDetector()
 
  168             def getNextExposure(amp):
 
  169                 return assembleInput[amp.getName()]
 
  170         elif hasattr(assembleInput, 
"getMaskedImage"):
 
  172             ccd = assembleInput.getDetector()
 
  174             def getNextExposure(amp):
 
  177             raise TypeError(
"Expected either a dictionary of amp exposures or a single raw exposure")
 
  180             raise RuntimeError(
"No ccd detector found")
 
  182         if not self.config.doTrim:
 
  183             outBox = cameraGeomUtils.calcRawCcdBBox(ccd)
 
  185             outBox = ccd.getBBox()
 
  186         outExposure = afwImage.ExposureF(outBox)
 
  187         outMI = outExposure.getMaskedImage()
 
  189         if self.config.doTrim:
 
  190             assemble = cameraGeom.assembleAmplifierImage
 
  192             assemble = cameraGeom.assembleAmplifierRawImage
 
  195             inMI = getNextExposure(amp).getMaskedImage()
 
  196             assemble(outMI, inMI, amp)
 
  202         if not self.config.doTrim:
 
  203             ccd = cameraGeom.makeUpdatedDetector(ccd)
 
  205         outExposure.setDetector(ccd)
 
  211         """Set exposure non-image attributes, including wcs and metadata and display exposure (if requested) 
  213         Call after assembling the pixels 
  215         @param[in,out]  outExposure assembled exposure: 
  216                                     - removes unwanted keywords 
  217                                     - sets photoCalib, filter, and detector 
  218         @param[in]      inExposure  input exposure 
  220         self.
setWcs(outExposure=outExposure, inExposure=inExposure)
 
  222         exposureMetadata = inExposure.getMetadata()
 
  224             if exposureMetadata.exists(key):
 
  225                 exposureMetadata.remove(key)
 
  226         outExposure.setMetadata(exposureMetadata)
 
  229         outExposure.setFilter(inExposure.getFilter())
 
  230         outExposure.getInfo().setVisitInfo(inExposure.getInfo().getVisitInfo())
 
  234             afwDisplay.Display(frame=frame).
mtv(outExposure, title=
"postprocessExposure")
 
  236     def setWcs(self, outExposure, inExposure):
 
  237         """Set output WCS = input WCS, adjusted as required for datasecs not starting at lower left corner 
  239         @param[in,out]  outExposure     assembled exposure; wcs is set 
  240         @param[in]      inExposure      input exposure 
  242         if inExposure.hasWcs():
 
  243             wcs = inExposure.getWcs()
 
  244             ccd = outExposure.getDetector()
 
  247                 raise RuntimeError(
"No amplifier detector information found")
 
  248             adjustedWcs = cameraGeomUtils.prepareWcsData(wcs, amp0, isTrimmed=self.config.doTrim)
 
  249             outExposure.setWcs(adjustedWcs)