22 """Support for assembling and disassembling afw Exposures."""
26 from lsst.afw.image import makeExposure, makeMaskedImage, Filter, stripFilterKeywords
28 from lsst.daf.butler
import StorageClassDelegate
33 EXPOSURE_COMPONENTS =
set((
"image",
"variance",
"mask",
"wcs",
"psf"))
34 EXPOSURE_INFO_COMPONENTS =
set((
"apCorrMap",
"coaddInputs",
"photoCalib",
"metadata",
35 "filter",
"transmissionCurve",
"visitInfo",
36 "detector",
"validPolygon"))
37 EXPOSURE_READ_COMPONENTS = {
"bbox",
"dimensions",
"xy0"}
39 COMPONENT_MAP = {
"bbox":
"BBox",
"xy0":
"XY0"}
40 """Map component name to actual getter name."""
42 def _groupRequestedComponents(self):
43 """Group requested components into top level and ExposureInfo.
48 Components associated with the top level Exposure.
50 Components associated with the ExposureInfo
55 There are components defined in the storage class that are not
56 expected by this assembler.
58 requested =
set(self.storageClass.components.keys())
63 raise ValueError(
"Asking for unrecognized component: {}".
format(unknown))
67 return expItems, expInfoItems
70 """Get a component from an Exposure
74 composite : `~lsst.afw.image.Exposure`
75 `Exposure` to access component.
77 Name of component to retrieve.
82 The component. Can be None.
87 The component can not be found.
93 if hasattr(composite,
"getInfo"):
97 composite = composite.getInfo()
100 raise AttributeError(
"Do not know how to retrieve component {} from {}".
format(componentName,
104 """Extract all non-None components from a composite.
109 Composite from which to extract components.
114 Non-None components extracted from the composite, indexed by the
115 component name as derived from the `self.storageClass`.
123 components.update(infoComps)
127 """Disassemble an afw Exposure.
129 This implementation attempts to extract components from the parent
130 by looking for attributes of the same name or getter methods derived
131 from the component name.
135 composite : `~lsst.afw.image.Exposure`
136 `Exposure` composite object consisting of components to be
142 `dict` with keys matching the components defined in
143 `self.storageClass` and values being `DatasetComponent` instances
144 describing the component.
149 A requested component can not be found in the parent using generic
152 The parent object does not match the supplied `self.storageClass`.
154 if not self.storageClass.validateInstance(composite):
155 raise TypeError(
"Unexpected type mismatch between parent and StorageClass"
156 " ({} != {})".
format(
type(composite), self.storageClass.pytype))
162 fromExposure = super().
disassemble(composite, subset=expItems)
163 components.update(fromExposure)
166 subset=expInfoItems, override=composite.getInfo())
167 components.update(fromExposureInfo)
173 if "filter" in components
and "metadata" in components:
174 md = components[
"metadata"].component
175 md[
"FILTER"] = components[
"filter"].component.getName()
180 """Construct an Exposure from components.
185 All the components from which to construct the Exposure.
190 exposure : `~lsst.afw.image.Exposure`
196 Some supplied components are not recognized.
198 components = components.copy()
199 maskedImageComponents = {}
200 hasMaskedImage =
False
201 for component
in (
"image",
"variance",
"mask"):
203 if component
in components:
204 hasMaskedImage =
True
205 value = components.pop(component)
206 maskedImageComponents[component] = value
209 if "wcs" in components:
210 wcs = components.pop(
"wcs")
212 pytype = self.storageClass.pytype
217 if not isinstance(exposure, pytype):
218 raise RuntimeError(
"Unexpected type created in assembly;"
219 " was {} expected {}".
format(
type(exposure), pytype))
227 exposure.setPsf(components.pop(
"psf",
None))
228 exposure.setPhotoCalib(components.pop(
"photoCalib",
None))
230 info = exposure.getInfo()
231 if "visitInfo" in components:
232 info.setVisitInfo(components.pop(
"visitInfo"))
233 info.setApCorrMap(components.pop(
"apCorrMap",
None))
234 info.setCoaddInputs(components.pop(
"coaddInputs",
None))
235 info.setMetadata(components.pop(
"metadata",
None))
236 info.setValidPolygon(components.pop(
"validPolygon",
None))
237 info.setDetector(components.pop(
"detector",
None))
238 info.setTransmissionCurve(components.pop(
"transmissionCurve",
None))
244 md = info.getMetadata()
245 if "filter" in components
and "FILTER" in md:
248 if filter.getName() != components[
"filter"].getName():
249 components[
"filter"] = filter
251 info.setFilter(components.pop(
"filter",
None))
255 raise ValueError(
"The following components were not understood:"
261 """Modify the in-memory dataset using the supplied parameters,
262 returning a possibly new object.
266 inMemoryDataset : `object`
267 Object to modify based on the parameters.
268 parameters : `dict`, optional
269 Parameters to apply. Values are specific to the parameter.
270 Supported parameters are defined in the associated
271 `StorageClass`. If no relevant parameters are specified the
272 inMemoryDataset will be return unchanged.
276 inMemoryDataset : `object`
277 Updated form of supplied in-memory dataset, after parameters
281 understood = (
"bbox",
"origin")
282 use = self.storageClass.filterParameters(parameters, subset=understood)
284 inMemoryDataset = inMemoryDataset.subset(**use)
286 return inMemoryDataset
290 imageComponents = [
"mask",
"image",
"variance"]
292 "bbox": imageComponents,
293 "dimensions": imageComponents,
294 "xy0": imageComponents,
296 forwarder = forwarderMap.get(readComponent)
297 if forwarder
is not None:
299 if c
in fromComponents:
301 raise ValueError(f
"Can not calculate read component {readComponent} from {fromComponents}")