22 """Collection of small images (stamps), each centered on a bright star.
25 __all__ = [
"BrightStarStamp",
"BrightStarStamps"]
27 from dataclasses
import dataclass
28 from enum
import Enum, auto
31 from .stamps
import StampsBase, AbstractStamp, readFitsWithOptions
44 """Single stamp centered on a bright star, normalized by its
49 stamp_im : `lsst.afw.image.MaskedImage`
50 Pixel data for this postage stamp
52 Gaia G magnitude for the object in this stamp
54 Gaia object identifier
56 Flux in an annulus around the object
64 def factory(cls, stamp_im, metadata, idx):
65 """This method is needed to service the FITS reader.
66 We need a standard interface to construct objects like this.
67 Parameters needed to construct this object are passed in via
68 a metadata dictionary and then passed to the constructor of
69 this class. This particular factory method requires keys:
70 G_MAGS, GAIA_IDS, and ANNULAR_FLUXES. They should each
71 point to lists of values.
75 stamp_im : `lsst.afw.image.MaskedImage`
76 Pixel data to pass to the constructor
78 Dictionary containing the information
79 needed by the constructor.
81 Index into the lists in ``metadata``
85 brightstarstamp : `BrightStarStamp`
86 An instance of this class
88 return cls(stamp_im=stamp_im,
89 gaiaGMag=metadata[
'G_MAGS'][idx],
90 gaiaId=metadata[
'GAIA_IDS'][idx],
91 annularFlux=metadata[
'ANNULAR_FLUXES'][idx])
95 """Collection of bright star stamps and associated metadata.
99 starStamps : `collections.abc.Sequence` [`BrightStarStamp`]
100 Sequence of star stamps.
101 innerRadius : `int`, optional
102 Inner radius value, in pixels. This and ``outerRadius`` define the
103 annulus used to compute the ``"annularFlux"`` values within each
104 ``starStamp``. Must be provided if ``"INNER_RADIUS"`` and
105 ``"OUTER_RADIUS"`` are not present in ``metadata``.
106 outerRadius : `int`, optional
107 Outer radius value, in pixels. This and ``innerRadius`` define the
108 annulus used to compute the ``"annularFlux"`` values within each
109 ``starStamp``. Must be provided if ``"INNER_RADIUS"`` and
110 ``"OUTER_RADIUS"`` are not present in ``metadata``.
111 metadata : `lsst.daf.base.PropertyList`, optional
112 Metadata associated with the bright stars.
114 If `True` read and write mask data. Default `True`.
115 use_variance : `bool`
116 If ``True`` read and write variance data. Default ``False``.
121 Raised if one of the star stamps provided does not contain the
124 Raised if the definition of the annulus used to compute each star's
125 normalization factor are not provided, that is, if ``"INNER_RADIUS"``
126 and ``"OUTER_RADIUS"`` are not present in ``metadata`` _and_
127 ``innerRadius`` and ``outerRadius`` are not provided.
131 A (gen2) butler can be used to read only a part of the stamps,
134 >>> starSubregions = butler.get("brightStarStamps_sub", dataId, bbox=bbox)
137 def __init__(self, starStamps, innerRadius=None, outerRadius=None,
138 metadata=None, use_mask=True, use_variance=False):
139 super().
__init__(starStamps, metadata, use_mask, use_variance)
146 def _refresh_metadata(self):
147 """Refresh the metadata. Should be called before writing this object out.
158 """Build an instance of this class from a file.
163 Name of the file to read
169 """Build an instance of this class with options.
174 Name of the file to read
175 options : `PropertyList`
176 Collection of metadata parameters
179 return cls(stamps, metadata=metadata, use_mask=metadata[
'HAS_MASK'],
180 use_variance=metadata[
'HAS_VARIANCE'])
182 def append(self, item, innerRadius, outerRadius):
183 """Add an additional bright star stamp.
187 item : `BrightStarStamp`
188 Bright star stamp to append.
190 Inner radius value, in pixels. This and ``outerRadius`` define the
191 annulus used to compute the ``"annularFlux"`` values within each
193 outerRadius : `int`, optional
194 Outer radius value, in pixels. This and ``innerRadius`` define the
195 annulus used to compute the ``"annularFlux"`` values within each
198 if not isinstance(item, BrightStarStamp):
199 raise ValueError(f
"Can only add instances of BrightStarStamp, got {type(item)}.")
206 """Extend BrightStarStamps instance by appending elements from another
211 bss : `BrightStarStamps`
212 Other instance to concatenate.
214 if not isinstance(bss, BrightStarStamps):
215 raise ValueError(
'Can only extend with a BrightStarStamps object. '
217 self.
_checkRadius(bss._innerRadius, RadiiEnum.INNER_RADIUS)
218 self.
_checkRadius(bss._outerRadius, RadiiEnum.OUTER_RADIUS)
222 """Retrieve Gaia G magnitudes for each star.
226 gaiaGMags : `list` [`float`]
228 return [stamp.gaiaGMag
for stamp
in self.
_stamps]
231 """Retrieve Gaia IDs for each star.
235 gaiaIds : `list` [`int`]
237 return [stamp.gaiaId
for stamp
in self.
_stamps]
240 """Retrieve normalization factors for each star.
242 These are computed by integrating the flux in annulus centered on the
243 bright star, far enough from center to be beyond most severe ghosts and
244 saturation. The inner and outer radii that define the annulus can be
245 recovered from the metadata.
249 annularFluxes : `list` [`float`]
251 return [stamp.annularFlux
for stamp
in self.
_stamps]
254 """Return the subset of bright star stamps for objects with specified
255 magnitude cuts (in Gaia G).
259 magMin : `float`, optional
260 Keep only stars fainter than this value.
261 magMax : `float`, optional
262 Keep only stars brighter than this value.
264 subset = [stamp
for stamp
in self.
_stamps
265 if (magMin
is None or stamp.gaiaGMag > magMin)
266 and (magMax
is None or stamp.gaiaGMag < magMax)]
270 instance._stamps = subset
273 def _checkRadius(self, radiusValue, metadataEnum):
274 """Ensure provided annulus radius is consistent with that present
275 in metadata. If metadata does not contain annulus radius, add it.
279 metadataName = str(metadataEnum)
281 if radiusValue
is not None:
282 if self.
_metadata[metadataName] != radiusValue:
283 raise AttributeError(
"BrightStarStamps instance already contains different annulus radii "
284 + f
"values ({metadataName}).")
286 elif radiusValue
is None:
287 raise AttributeError(
"No radius value provided for the AnnularFlux measurement "
288 + f
"({metadataName}), and none present in metadata.")
290 self.
_metadata[metadataName] = radiusValue