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