LSSTApplications  18.1.0
LSSTDataManagementBasePackage
visualizeVisit.py
Go to the documentation of this file.
1 from __future__ import absolute_import, division, print_function
2 
3 import numpy as np
4 
5 import lsst.afw.math as afwMath
6 import lsst.afw.image as afwImage
7 
8 from lsst.afw.cameraGeom.utils import makeImageFromCamera
9 from lsst.pipe.base import ArgumentParser
10 from lsst.pex.config import Config, Field
11 from lsst.ctrl.pool.pool import Pool
12 from lsst.ctrl.pool.parallel import BatchPoolTask
13 
14 
15 def makeCameraImage(camera, exposures, binning):
16  """Make and write an image of an entire focal plane
17 
18  Parameters
19  ----------
20  camera : `lsst.afw.cameraGeom.Camera`
21  Camera description.
22  exposures : `dict` mapping detector ID to `lsst.afw.image.Exposure`
23  CCD exposures, binned by `binning`.
24  binning : `int`
25  Binning size that has been applied to images.
26  """
27  class ImageSource(object):
28  """Source of images for makeImageFromCamera"""
29  def __init__(self, exposures):
30  """Constructor
31 
32  Parameters
33  ----------
34  exposures : `dict` mapping detector ID to `lsst.afw.image.Exposure`
35  CCD exposures, already binned.
36  """
37  self.isTrimmed = True
38  self.exposures = exposures
39  self.background = np.nan
40 
41  def getCcdImage(self, detector, imageFactory, binSize):
42  """Provide image of CCD to makeImageFromCamera"""
43  detId = detector.getId()
44  if detId not in self.exposures:
45  dims = detector.getBBox().getDimensions()/binSize
46  image = imageFactory(*[int(xx) for xx in dims])
47  image.set(self.background)
48  else:
49  image = self.exposures[detector.getId()]
50  if hasattr(image, "getMaskedImage"):
51  image = image.getMaskedImage()
52  if hasattr(image, "getMask"):
53  mask = image.getMask()
54  isBad = mask.getArray() & mask.getPlaneBitMask("NO_DATA") > 0
55  image = image.clone()
56  image.getImage().getArray()[isBad] = self.background
57  if hasattr(image, "getImage"):
58  image = image.getImage()
59 
60  image = afwMath.rotateImageBy90(image, detector.getOrientation().getNQuarter())
61 
62  return image, detector
63 
64  image = makeImageFromCamera(
65  camera,
66  imageSource=ImageSource(exposures),
67  imageFactory=afwImage.ImageF,
68  binSize=binning
69  )
70  return image
71 
72 
74  binning = Field(dtype=int, default=8, doc="Binning factor to apply")
75 
76 
78  ConfigClass = VisualizeVisitConfig
79  _DefaultName = "visualizeVisit"
80 
81  def __init__(self, *args, **kwargs):
82  BatchPoolTask.__init__(self, *args, **kwargs)
83  self._storedButler = False # Stored butler in the Pool? Doing this once increases efficiency
84 
85  @classmethod
86  def _makeArgumentParser(cls, *args, **kwargs):
87  kwargs.pop("doBatch", False)
88  parser = ArgumentParser(name="visualizeVisit", *args, **kwargs)
89  parser.add_id_argument("--id", datasetType="calexp", level="visit",
90  help="data ID, e.g. --id visit=12345")
91  return parser
92 
93  @classmethod
94  def batchWallTime(cls, time, parsedCmd, numCores):
95  """Return walltime request for batch job
96 
97  Subclasses should override if the walltime should be calculated
98  differently (e.g., addition of some serial time).
99 
100  Parameters
101  ----------
102  time : `float`
103  Requested time per iteration.
104  parsedCmd : `argparse.Namespace`
105  Results of argument parsing.
106  numCores : `int`
107  Number of cores.
108  """
109  numTargets = len(cls.RunnerClass.getTargetList(parsedCmd))
110  return time*numTargets
111 
112  def runDataRef(self, expRef):
113  """Generate an image of the entire visit
114 
115  Only the master node executes this method; it controls the slave nodes,
116  which do the data retrieval.
117 
118  Parameters
119  ----------
120  expRef : `lsst.daf.persistence.ButlerDataRef`
121  Data reference for exposure.
122  """
123  pool = Pool()
124 
125  if not self._storedButler:
126  pool.storeSet(butler=expRef.getButler())
127 
128  with self.logOperation("processing %s" % (expRef.dataId,)):
129  camera = expRef.get("camera")
130  dataIdList = [ccdRef.dataId for ccdRef in expRef.subItems("ccd") if
131  ccdRef.datasetExists("calexp")]
132 
133  exposures = pool.map(self.readImage, dataIdList)
134  exposures = dict(keyValue for keyValue in exposures if keyValue is not None)
135  image = makeCameraImage(camera, exposures, self.config.binning)
136  expRef.put(image, "calexp_camera")
137 
138  def readImage(self, cache, dataId):
139  """Collect original image for visualisation
140 
141  This method runs on the slave nodes.
142 
143  Parameters
144  ----------
145  cache : `lsst.pipe.base.Struct`
146  Process pool cache.
147  dataId : `dict`
148  Data identifier.
149 
150  Returns
151  -------
152  detId : `int`
153  Detector identifier.
154  image : `lsst.afw.image.MaskedImage`
155  Binned image.
156  """
157  exposure = cache.butler.get("calexp", dataId)
158  return (exposure.getDetector().getId(),
159  afwMath.binImage(exposure.getMaskedImage(), self.config.binning))
160 
161  def _getConfigName(self):
162  """It's not worth preserving the configuration"""
163  return None
164 
165  def _getMetadataName(self):
166  """There's no metadata to write out"""
167  return None
def makeImageFromCamera(camera, detectorNameList=None, background=numpy.nan, bufferSize=10, imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageU, binSize=1)
Definition: utils.py:867
std::shared_ptr< ImageT > rotateImageBy90(ImageT const &image, int nQuarter)
Rotate an image by an integral number of quarter turns.
Definition: rotateImage.cc:39
def __init__(self, minimum, dataRange, Q)
def batchWallTime(cls, time, parsedCmd, numCores)
def logOperation(self, operation, catch=False, trace=True)
Provide a context manager for logging an operation.
Definition: parallel.py:497
std::shared_ptr< ImageT > binImage(ImageT const &inImage, int const binsize, lsst::afw::math::Property const flags=lsst::afw::math::MEAN)
Definition: binImage.cc:38
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
def makeCameraImage(camera, exposures, binning)