lsst.obs.base  17.0.1-21-ga02730c+2
fitsRawFormatterBase.py
Go to the documentation of this file.
1 # This file is part of daf_butler.
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 __all__ = ("FitsRawFormatterBase",)
23 
24 from abc import ABCMeta, abstractmethod
25 
26 from lsst.daf.butler.formatters.fitsExposureFormatter import FitsExposureFormatter
27 
28 
29 class FitsRawFormatterBase(FitsExposureFormatter, metaclass=ABCMeta):
30  """Abstract base class for reading and writing raw data to and from
31  FITS files.
32 
33  Subclasses must provide implementations of `readImage` and
34  `makeRawVisitInfo`. Other methods may also be overridden to provide
35  additional components (most default to `None`).
36  """
37 
38  @abstractmethod
39  def readImage(self, fileDescriptor):
40  """Read just the image component of the Exposure.
41 
42  Parameters
43  ----------
44  fileDescriptor : `FileDescriptor`
45  Identifies the file to read and parameters to be used for reading.
46 
47  Returns
48  -------
49  image : `~lsst.afw.image.Image`
50  In-memory image component.
51  """
52  raise NotImplementedError("Must be implemented by subclasses.")
53 
54  def readMask(self, fileDescriptor):
55  """Read just the mask component of the Exposure.
56 
57  May return None (as the default implementation does) to indicate that
58  there is no mask information to be extracted (at least not trivially)
59  from the raw data. This will prohibit direct reading of just the mask,
60  and set the mask of the full Exposure to zeros.
61 
62  Parameters
63  ----------
64  fileDescriptor : `FileDescriptor`
65  Identifies the file to read and parameters to be used for reading.
66 
67  Returns
68  -------
69  mask : `~lsst.afw.image.Mask`
70  In-memory mask component.
71  """
72  return None
73 
74  def readVariance(self, fileDescriptor):
75  """Read just the variance component of the Exposure.
76 
77  May return None (as the default implementation does) to indicate that
78  there is no variance information to be extracted (at least not
79  trivially) from the raw data. This will prohibit direct reading of
80  just the variance, and set the variance of the full Exposure to zeros.
81 
82  Parameters
83  ----------
84  fileDescriptor : `FileDescriptor`
85  Identifies the file to read and parameters to be used for reading.
86 
87  Returns
88  -------
89  image : `~lsst.afw.image.Image`
90  In-memory variance component.
91  """
92  return None
93 
94  def stripMetadata(self, metadata):
95  """Remove metadata entries that are parsed into components.
96 
97  Parameters
98  ----------
99  metadata : `~lsst.daf.base.PropertyList`
100  Header metadata, to be modified in-place.
101  """
102  self.makeVisitInfo(metadata)
103  self.makeWcs(metadata)
104 
105  @abstractmethod
106  def makeVisitInfo(self, metadata):
107  """Construct a VisitInfo from metadata.
108 
109  Parameters
110  ----------
111  metadata : `~lsst.daf.base.PropertyList`
112  Header metadata. May be modified in-place.
113 
114  Returns
115  -------
116  visitInfo : `~lsst.afw.image.VisitInfo`
117  Structured metadata about the observation.
118  """
119  raise NotImplementedError("Must be implemented by subclasses.")
120 
121  def makeWcs(self, metadata):
122  """Construct a SkyWcs from metadata.
123 
124  Parameters
125  ----------
126  metadata : `~lsst.daf.base.PropertyList`
127  Header metadata. May be modified in-place.
128 
129  Returns
130  -------
131  wcs : `~lsst.afw.geom.SkyWcs`
132  Reversible mapping from pixel coordinates to sky coordinates.
133  """
134  from lsst.afw.geom import makeSkyWcs
135  return makeSkyWcs(metadata, strip=True)
136 
137  def makeFilter(self, metadata):
138  """Construct a Filter from metadata.
139 
140  Parameters
141  ----------
142  metadata : `~lsst.daf.base.PropertyList`
143  Header metadata. May be modified in-place.
144 
145  Returns
146  -------
147  filter : `~lsst.afw.image.Filter`
148  Object that identifies the filter for this image.
149  """
150  raise NotImplementedError("Must be implemented by subclasses.")
151 
152  def readImageComponent(self, fileDescriptor, component):
153  """Read the image, mask, or variance component of an Exposure.
154 
155  Parameters
156  ----------
157  fileDescriptor : `FileDescriptor`
158  Identifies the file to read and parameters to be used for reading.
159  component : `str`, optional
160  Component to read from the file. Always one of "image",
161  "variance", or "mask".
162 
163  Returns
164  -------
165  image : `~lsst.afw.image.Image` or `~lsst.afw.image.Mask`
166  In-memory image, variance, or mask component.
167  """
168  if component == "image":
169  return self.readImage(fileDescriptor)
170  elif component == "mask":
171  return self.readMask(fileDescriptor)
172  elif component == "variance":
173  return self.readVariance(fileDescriptor)
174 
175  def readInfoComponent(self, fileDescriptor, component):
176  """Read a component held by ExposureInfo.
177 
178  The implementation provided by FitsRawFormatter provides only "wcs"
179  and "visitInfo". When adding support for other components, subclasses
180  should delegate to `super()` for those and update `readFull` with
181  similar logic.
182 
183  Parameters
184  ----------
185  fileDescriptor : `FileDescriptor`
186  Identifies the file to read and parameters to be used for reading.
187  component : `str`, optional
188  Component to read from the file.
189 
190  Returns
191  -------
192  obj : component-dependent
193  In-memory component object.
194  """
195  if component == "filter":
196  return self.makeFilter(self.readMetadata(fileDescriptor))
197  elif component == "visitInfo":
198  return self.makeVisitInfo(self.readMetadata(fileDescriptor))
199  elif component == "wcs":
200  return self.makeWcs(self.readMetadata(fileDescriptor))
201  return None
202 
203  def readFull(self, fileDescriptor, parameters=None):
204  """Read the full Exposure object.
205 
206  Parameters
207  ----------
208  fileDescriptor : `FileDescriptor`
209  Identifies the file to read and parameters to be used for reading.
210  parameters : `dict`, optional
211  If specified a dictionary of slicing parameters that overrides
212  those in ``fileDescriptor`.
213 
214  Returns
215  -------
216  exposure : `~lsst.afw.image.Exposure`
217  Complete in-memory exposure.
218  """
219  from lsst.afw.image import makeExposure, makeMaskedImage
220  full = makeExposure(makeMaskedImage(self.readImage(fileDescriptor)))
221  mask = self.readMask(fileDescriptor)
222  if mask is not None:
223  full.setMask(mask)
224  variance = self.readVariance(fileDescriptor)
225  if variance is not None:
226  full.setVariance(variance)
227  metadata = self.readMetadata(fileDescriptor)
228  info = full.getInfo()
229  info.setWcs(self.makeWcs(metadata))
230  info.setFilter(self.makeFilter(metadata))
231  info.setVisitInfo(self.makeVisitInfo(metadata))
232  # We shouldn't have to call stripMetadata() here because that should
233  # have been done by makeVisitInfo and makeWcs (or by subclasses that
234  # strip metadata for other components when constructing them).
235  full.setMetadata(metadata)
236  return full
237 
238  def write(self, inMemoryDataset, fileDescriptor):
239  """Write a Python object to a file.
240 
241  Parameters
242  ----------
243  inMemoryDataset : `object`
244  The Python object to store.
245  fileDescriptor : `FileDescriptor`
246  Identifies the file to read, type to read it into and parameters
247  to be used for reading.
248 
249  Returns
250  -------
251  path : `str`
252  The `URI` where the primary file is stored.
253  """
254  raise NotImplementedError("Raw data cannot be `put`.")
def readFull(self, fileDescriptor, parameters=None)
def write(self, inMemoryDataset, fileDescriptor)