LSSTApplications  20.0.0
LSSTDataManagementBasePackage
exposureAssembler.py
Go to the documentation of this file.
1 # This file is part of obs_base.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (http://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 
22 """Support for assembling and disassembling afw Exposures."""
23 
24 # Need to enable PSFs to be instantiated
25 import lsst.afw.detection # noqa: F401
26 from lsst.afw.image import makeExposure, makeMaskedImage
27 
28 from lsst.daf.butler import CompositeAssembler
29 
30 
31 class ExposureAssembler(CompositeAssembler):
32 
33  EXPOSURE_COMPONENTS = set(("image", "variance", "mask", "wcs", "psf"))
34  EXPOSURE_INFO_COMPONENTS = set(("apCorrMap", "coaddInputs", "photoCalib", "metadata",
35  "filter", "transmissionCurve", "visitInfo"))
36 
37  def _groupRequestedComponents(self):
38  """Group requested components into top level and ExposureInfo.
39 
40  Returns
41  -------
42  expComps : `dict`
43  Components associated with the top level Exposure.
44  expInfoComps : `dict`
45  Components associated with the ExposureInfo
46 
47  Raises
48  ------
49  ValueError
50  There are components defined in the storage class that are not
51  expected by this assembler.
52  """
53  requested = set(self.storageClass.components.keys())
54 
55  # Check that we are requesting something that we support
56  unknown = requested - (self.EXPOSURE_COMPONENTS | self.EXPOSURE_INFO_COMPONENTS)
57  if unknown:
58  raise ValueError("Asking for unrecognized component: {}".format(unknown))
59 
60  expItems = requested & self.EXPOSURE_COMPONENTS
61  expInfoItems = requested & self.EXPOSURE_INFO_COMPONENTS
62  return expItems, expInfoItems
63 
64  def getComponent(self, composite, componentName):
65  """Get a component from an Exposure
66 
67  Parameters
68  ----------
69  composite : `~lsst.afw.image.Exposure`
70  `Exposure` to access component.
71  componentName : `str`
72  Name of component to retrieve.
73 
74  Returns
75  -------
76  component : `object`
77  The component. Can be None.
78 
79  Raises
80  ------
81  AttributeError
82  The component can not be found.
83  """
84  if componentName in self.EXPOSURE_COMPONENTS:
85  return super().getComponent(composite, componentName)
86  elif componentName in self.EXPOSURE_INFO_COMPONENTS:
87  if hasattr(composite, "getInfo"):
88  # it is possible for this method to be called with
89  # an ExposureInfo composite so trap for that and only get
90  # the ExposureInfo if the method is supported
91  composite = composite.getInfo()
92  return super().getComponent(composite, componentName)
93  else:
94  raise AttributeError("Do not know how to retrieve component {} from {}".format(componentName,
95  type(composite)))
96 
97  def getValidComponents(self, composite):
98  """Extract all non-None components from a composite.
99 
100  Parameters
101  ----------
102  composite : `object`
103  Composite from which to extract components.
104 
105  Returns
106  -------
107  comps : `dict`
108  Non-None components extracted from the composite, indexed by the
109  component name as derived from the `self.storageClass`.
110  """
111  # For Exposure we call the generic version twice: once for top level
112  # components, and again for ExposureInfo.
113  expItems, expInfoItems = self._groupRequestedComponents()
114 
115  components = super().getValidComponents(composite)
116  infoComps = super().getValidComponents(composite.getInfo())
117  components.update(infoComps)
118  return components
119 
120  def disassemble(self, composite):
121  """Disassemble an afw Exposure.
122 
123  This implementation attempts to extract components from the parent
124  by looking for attributes of the same name or getter methods derived
125  from the component name.
126 
127  Parameters
128  ----------
129  composite : `~lsst.afw.image.Exposure`
130  `Exposure` composite object consisting of components to be
131  extracted.
132 
133  Returns
134  -------
135  components : `dict`
136  `dict` with keys matching the components defined in
137  `self.storageClass` and values being `DatasetComponent` instances
138  describing the component.
139 
140  Raises
141  ------
142  ValueError
143  A requested component can not be found in the parent using generic
144  lookups.
145  TypeError
146  The parent object does not match the supplied `self.storageClass`.
147  """
148  if not self.storageClass.validateInstance(composite):
149  raise TypeError("Unexpected type mismatch between parent and StorageClass"
150  " ({} != {})".format(type(composite), self.storageClass.pytype))
151 
152  # Only look for components that are defined by the StorageClass
153  components = {}
154  expItems, expInfoItems = self._groupRequestedComponents()
155 
156  fromExposure = super().disassemble(composite, subset=expItems)
157  components.update(fromExposure)
158 
159  fromExposureInfo = super().disassemble(composite,
160  subset=expInfoItems, override=composite.getInfo())
161  components.update(fromExposureInfo)
162 
163  return components
164 
165  def assemble(self, components):
166  """Construct an Exposure from components.
167 
168  Parameters
169  ----------
170  components : `dict`
171  All the components from which to construct the Exposure.
172  Some can be missing.
173 
174  Returns
175  -------
176  exposure : `~lsst.afw.image.Exposure`
177  Assembled exposure.
178 
179  Raises
180  ------
181  ValueError
182  Some supplied components are not recognized.
183  """
184  components = components.copy()
185  maskedImageComponents = {}
186  hasMaskedImage = False
187  for component in ("image", "variance", "mask"):
188  value = None
189  if component in components:
190  hasMaskedImage = True
191  value = components.pop(component)
192  maskedImageComponents[component] = value
193 
194  wcs = None
195  if "wcs" in components:
196  wcs = components.pop("wcs")
197 
198  pytype = self.storageClass.pytype
199  if hasMaskedImage:
200  maskedImage = makeMaskedImage(**maskedImageComponents)
201  exposure = makeExposure(maskedImage, wcs=wcs)
202 
203  if not isinstance(exposure, pytype):
204  raise RuntimeError("Unexpected type created in assembly;"
205  " was {} expected {}".format(type(exposure), pytype))
206 
207  else:
208  exposure = pytype()
209  if wcs is not None:
210  exposure.setWcs(wcs)
211 
212  # Set other components
213  exposure.setPsf(components.pop("psf", None))
214  exposure.setPhotoCalib(components.pop("photoCalib", None))
215 
216  info = exposure.getInfo()
217  if "visitInfo" in components:
218  info.setVisitInfo(components.pop("visitInfo"))
219  info.setApCorrMap(components.pop("apCorrMap", None))
220  info.setCoaddInputs(components.pop("coaddInputs", None))
221  info.setMetadata(components.pop("metadata", None))
222 
223  # If we have some components left over that is a problem
224  if components:
225  raise ValueError("The following components were not understood:"
226  " {}".format(list(components.keys())))
227 
228  return exposure
229 
230  def handleParameters(self, inMemoryDataset, parameters=None):
231  """Modify the in-memory dataset using the supplied parameters,
232  returning a possibly new object.
233 
234  Parameters
235  ----------
236  inMemoryDataset : `object`
237  Object to modify based on the parameters.
238  parameters : `dict`, optional
239  Parameters to apply. Values are specific to the parameter.
240  Supported parameters are defined in the associated
241  `StorageClass`. If no relevant parameters are specified the
242  inMemoryDataset will be return unchanged.
243 
244  Returns
245  -------
246  inMemoryDataset : `object`
247  Updated form of supplied in-memory dataset, after parameters
248  have been used.
249  """
250  # Understood by *this* subset command
251  understood = ("bbox", "origin")
252  use = self.storageClass.filterParameters(parameters, subset=understood)
253  if use:
254  inMemoryDataset = inMemoryDataset.subset(**use)
255 
256  return inMemoryDataset
lsst::afw::image
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Definition: imageAlgorithm.dox:1
lsst::afw::image::makeExposure
std::shared_ptr< Exposure< ImagePixelT, MaskPixelT, VariancePixelT > > makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, std::shared_ptr< geom::SkyWcs const > wcs=std::shared_ptr< geom::SkyWcs const >())
A function to return an Exposure of the correct type (cf.
Definition: Exposure.h:442
pex.config.history.format
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
lsst.obs.base.exposureAssembler.ExposureAssembler
Definition: exposureAssembler.py:31
lsst.obs.base.exposureAssembler.ExposureAssembler.EXPOSURE_INFO_COMPONENTS
EXPOSURE_INFO_COMPONENTS
Definition: exposureAssembler.py:34
lsst.obs.base.exposureAssembler.ExposureAssembler._groupRequestedComponents
def _groupRequestedComponents(self)
Definition: exposureAssembler.py:37
lsst.obs.base.exposureAssembler.ExposureAssembler.getComponent
def getComponent(self, composite, componentName)
Definition: exposureAssembler.py:64
lsst.obs.base.exposureAssembler.ExposureAssembler.getValidComponents
def getValidComponents(self, composite)
Definition: exposureAssembler.py:97
lsst.obs.base.exposureAssembler.ExposureAssembler.disassemble
def disassemble(self, composite)
Definition: exposureAssembler.py:120
lsst.obs.base.exposureAssembler.ExposureAssembler.handleParameters
def handleParameters(self, inMemoryDataset, parameters=None)
Definition: exposureAssembler.py:230
lsst::afw::detection
Definition: Footprint.h:50
lsst.obs.base.exposureAssembler.ExposureAssembler.EXPOSURE_COMPONENTS
EXPOSURE_COMPONENTS
Definition: exposureAssembler.py:33
list
daf::base::PropertyList * list
Definition: fits.cc:913
type
table::Key< int > type
Definition: Detector.cc:163
lsst::afw::image::makeMaskedImage
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > * makeMaskedImage(typename std::shared_ptr< Image< ImagePixelT >> image, typename std::shared_ptr< Mask< MaskPixelT >> mask=Mask< MaskPixelT >(), typename std::shared_ptr< Image< VariancePixelT >> variance=Image< VariancePixelT >())
A function to return a MaskedImage of the correct type (cf.
Definition: MaskedImage.h:1279
lsst.obs.base.exposureAssembler.ExposureAssembler.assemble
def assemble(self, components)
Definition: exposureAssembler.py:165
set
daf::base::PropertySet * set
Definition: fits.cc:912