LSST Applications  21.0.0+75b29a8a7f,21.0.0+e70536a077,21.0.0-1-ga51b5d4+62c747d40b,21.0.0-10-gbfb87ad6+3307648ee3,21.0.0-15-gedb9d5423+47cba9fc36,21.0.0-2-g103fe59+fdf0863a2a,21.0.0-2-g1367e85+d38a93257c,21.0.0-2-g45278ab+e70536a077,21.0.0-2-g5242d73+d38a93257c,21.0.0-2-g7f82c8f+e682ffb718,21.0.0-2-g8dde007+d179fbfa6a,21.0.0-2-g8f08a60+9402881886,21.0.0-2-ga326454+e682ffb718,21.0.0-2-ga63a54e+08647d4b1b,21.0.0-2-gde069b7+26c92b3210,21.0.0-2-gecfae73+0445ed2f95,21.0.0-2-gfc62afb+d38a93257c,21.0.0-27-gbbd0d29+ae871e0f33,21.0.0-28-g5fc5e037+feb0e9397b,21.0.0-3-g21c7a62+f4b9c0ff5c,21.0.0-3-g357aad2+57b0bddf0b,21.0.0-3-g4be5c26+d38a93257c,21.0.0-3-g65f322c+3f454acf5d,21.0.0-3-g7d9da8d+75b29a8a7f,21.0.0-3-gaa929c8+9e4ef6332c,21.0.0-3-ge02ed75+4b120a55c4,21.0.0-4-g3300ddd+e70536a077,21.0.0-4-g591bb35+4b120a55c4,21.0.0-4-gc004bbf+4911b9cd27,21.0.0-4-gccdca77+f94adcd104,21.0.0-4-ge8fba5a+2b3a696ff9,21.0.0-5-gb155db7+2c5429117a,21.0.0-5-gdf36809+637e4641ee,21.0.0-6-g00874e7+c9fd7f7160,21.0.0-6-g4e60332+4b120a55c4,21.0.0-7-gc8ca178+40eb9cf840,21.0.0-8-gfbe0b4b+9e4ef6332c,21.0.0-9-g2fd488a+d83b7cd606,w.2021.05
LSST Data Management Base Package
filters.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 # (https://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 <https://www.gnu.org/licenses/>.
21 
22 """Classes to allow obs packages to define the filters used by an Instrument
23 and for use by `lsst.afw.image.Filter`, gen2 dataIds, and gen3 Dimensions.
24 """
25 
26 __all__ = ("FilterDefinition", "FilterDefinitionCollection")
27 
28 import dataclasses
29 import collections.abc
30 import warnings
31 
32 import numpy as np
33 
35 
36 
37 class FilterDefinitionCollection(collections.abc.Sequence):
38  """An order-preserving collection of multiple `FilterDefinition`.
39 
40  Parameters
41  ----------
42  filters : `~collections.abc.Sequence`
43  The filters in this collection.
44  """
45 
46  _defined = None
47  """Whether these filters have been defined via
48  `~lsst.afw.image.utils.defineFilter`. If so, set to ``self`` to identify
49  the filter collection that defined them.
50  """
51 
52  physical_to_band = {}
53  """A mapping from physical filter name to band name.
54  This is a convenience feature to allow file readers to create a FilterLabel
55  when reading a raw file that only has a physical filter name, without
56  iterating over the entire collection.
57  """
58 
59  def __init__(self, *filters):
60  self._filters_filters = list(filters)
61  self.physical_to_bandphysical_to_bandphysical_to_band = {filter.physical_filter: filter.band for filter in self._filters_filters}
62 
63  def __getitem__(self, key):
64  return self._filters_filters[key]
65 
66  def __len__(self):
67  return len(self._filters_filters)
68 
69  def __str__(self):
70  return "FilterDefinitions(" + ', '.join(str(f) for f in self._filters_filters) + ')'
71 
72  def defineFilters(self):
73  """Define all the filters to `lsst.afw.image.Filter`.
74 
75  `~lsst.afw.image.Filter` objects are singletons, so we protect against
76  filters being defined multiple times.
77 
78  Raises
79  ------
80  RuntimeError
81  Raised if any other `FilterDefinitionCollection` has already called
82  ``defineFilters``.
83  """
84  if self._defined_defined is None:
85  with warnings.catch_warnings():
86  # surpress Filter warnings; we already know this is deprecated
87  warnings.simplefilter('ignore', category=FutureWarning)
88  self.resetreset()
89  for filter in self._filters_filters:
90  filter.defineFilter()
91  FilterDefinitionCollection._defined = self
92  elif self._defined_defined is self:
93  # noop: we've already defined these filters, so do nothing
94  pass
95  else:
96  msg = f"afw Filters were already defined on: {self._defined}"
97  raise RuntimeError(msg)
98 
99  @classmethod
100  def reset(cls):
101  """Reset the afw Filter definitions and clear the `defined` singleton.
102  Use this in unittests that define different filters.
103  """
104  with warnings.catch_warnings():
105  # surpress Filter warnings; we already know this is deprecated
106  warnings.simplefilter('ignore', category=FutureWarning)
108  cls._defined_defined = None
109 
110  def findAll(self, name):
111  """Return the FilterDefinitions that match a particular name.
112 
113  This method makes no attempt to prioritize, e.g., band names over
114  physical filter names; any definition that makes *any* reference
115  to the name is returned.
116 
117  Parameters
118  ----------
119  name : `str`
120  The name to search for. May be any band, physical, or alias name.
121 
122  Returns
123  -------
124  matches : `set` [`FilterDefinition`]
125  All FilterDefinitions containing ``name`` as one of their
126  filter names.
127  """
128  matches = set()
129  for filter in self._filters_filters:
130  if name == filter.physical_filter or name == filter.band or name == filter.afw_name \
131  or name in filter.alias:
132  matches.add(filter)
133  return matches
134 
135 
136 @dataclasses.dataclass(frozen=True)
138  """The definition of an instrument's filter bandpass.
139 
140  This class is used to interface between the `~lsst.afw.image.Filter` class
141  and the Gen2 `~lsst.daf.persistence.CameraMapper` and Gen3
142  `~lsst.obs.base.Instruments` and ``physical_filter``/``band``
143  `~lsst.daf.butler.Dimension`.
144 
145  This class is likely temporary, until we have a better versioned filter
146  definition system that includes complete transmission information.
147  """
148 
149  physical_filter: str
150  """The name of a filter associated with a particular instrument: unique for
151  each piece of glass. This should match the exact filter name used in the
152  observatory's metadata.
153 
154  This name is used to define the ``physical_filter`` gen3 Butler Dimension.
155 
156  If neither ``band`` or ``afw_name`` is defined, this is used
157  as the `~lsst.afw.image.Filter` ``name``, otherwise it is added to the
158  list of `~lsst.afw.image.Filter` aliases.
159  """
160 
161  lambdaEff: float
162  """The effective wavelength of this filter (nm)."""
163 
164  band: str = None
165  """The generic name of a filter not associated with a particular instrument
166  (e.g. `r` for the SDSS Gunn r-band, which could be on SDSS, LSST, or HSC).
167 
168  Not all filters have an abstract filter: engineering or test filters may
169  not have a genericly-termed filter name.
170 
171  If specified and if `afw_name` is None, this is used as the
172  `~lsst.afw.image.Filter` ``name`` field, otherwise it is added to the list
173  of `~lsst.afw.image.Filter` aliases.
174  """
175 
176  doc: str = None
177  """A short description of this filter, possibly with a link to more
178  information.
179  """
180 
181  afw_name: str = None
182  """If not None, the name of the `~lsst.afw.image.Filter` object.
183 
184  This is distinct from physical_filter and band to maintain
185  backwards compatibility in some obs packages.
186  For example, for HSC there are two distinct ``r`` and ``i`` filters, named
187  ``r/r2`` and ``i/i2``.
188  """
189 
190  lambdaMin: float = np.nan
191  """The minimum wavelength of this filter (nm; defined as 1% throughput)"""
192  lambdaMax: float = np.nan
193  """The maximum wavelength of this filter (nm; defined as 1% throughput)"""
194 
195  alias: set = frozenset()
196  """Alternate names for this filter. These are added to the
197  `~lsst.afw.image.Filter` alias list.
198  """
199 
200  def __post_init__(self):
201  # force alias to be immutable, so that hashing works
202  if not isinstance(self.alias, frozenset):
203  object.__setattr__(self, 'alias', frozenset(self.alias))
204 
205  def __str__(self):
206  txt = f"FilterDefinition(physical_filter='{self.physical_filter}', lambdaEff='{self.lambdaEff}'"
207  if self.band is not None:
208  txt += f", band='{self.band}'"
209  if self.afw_name is not None:
210  txt += f", afw_name='{self.afw_name}'"
211  if not np.isnan(self.lambdaMin):
212  txt += f", lambdaMin='{self.lambdaMin}'"
213  if not np.isnan(self.lambdaMax):
214  txt += f", lambdaMax='{self.lambdaMax}'"
215  if len(self.alias) != 0:
216  txt += f", alias='{self.alias}'"
217  return txt + ")"
218 
219  def defineFilter(self):
220  """Declare the filters via afw.image.Filter.
221  """
222  aliases = set(self.alias)
223  name = self.physical_filter
224  if self.band is not None:
225  name = self.band
226  aliases.add(self.physical_filter)
227  if self.afw_name is not None:
228  name = self.afw_name
229  aliases.add(self.physical_filter)
230  # Only add `physical_filter/band` as an alias if afw_name is defined.ee
231  if self.afw_name is not None:
232  if self.band is not None:
233  aliases.add(self.band)
234  with warnings.catch_warnings():
235  # surpress Filter warnings; we already know this is deprecated
236  warnings.simplefilter('ignore', category=FutureWarning)
238  lambdaEff=self.lambdaEff,
239  lambdaMin=self.lambdaMin,
240  lambdaMax=self.lambdaMax,
241  alias=sorted(aliases))
242 
243  def makeFilterLabel(self):
244  """Create a complete FilterLabel for this filter.
245  """
246  return lsst.afw.image.FilterLabel(band=self.band, physical=self.physical_filter)
A group of labels for a filter in an exposure or coadd.
Definition: FilterLabel.h:58
def defineFilter(name, lambdaEff, lambdaMin=np.nan, lambdaMax=np.nan, alias=[], force=False)
Definition: utils.py:66
daf::base::PropertyList * list
Definition: fits.cc:913
daf::base::PropertySet * set
Definition: fits.cc:912