2424__all__ = ["BrightStarStamp" , "BrightStarStamps" ]
2525
2626import logging
27- from collections .abc import Collection
27+ from collections .abc import Collection , Mapping
2828from dataclasses import dataclass
2929from functools import reduce
3030from operator import ior
3434from lsst .afw .image import MaskedImageF
3535from lsst .afw .math import Property , StatisticsControl , makeStatistics , stringToStatisticsProperty
3636from lsst .afw .table .io import Persistable
37+ from lsst .daf .base import PropertyList
3738from lsst .geom import Point2I
3839
39- from .stamps import AbstractStamp , Stamps , readFitsWithOptions
40+ from .stamps import StampBase , Stamps , readFitsWithOptions
4041
4142logger = logging .getLogger (__name__ )
4243
4344
4445@dataclass
45- class BrightStarStamp (AbstractStamp ):
46+ class BrightStarStamp (StampBase ):
4647 """Single stamp centered on a bright star, normalized by its annularFlux.
4748
4849 Parameters
@@ -55,8 +56,9 @@ class BrightStarStamp(AbstractStamp):
5556 Gaia object identifier
5657 position : `~lsst.geom.Point2I`
5758 Origin of the stamps in its origin exposure (pixels)
58- archive_element : `~lsst.afw.table.io.Persistable` or None, optional
59- Archive element (e.g. Transform or WCS) associated with this stamp.
59+ archive_elements : `~collections.abc.Mapping`[ `str` , \
60+ `~lsst.afw.table.io.Persistable`], optional
61+ Archive elements (e.g. Transform / WCS) associated with this stamp.
6062 annularFlux : `float` or None, optional
6163 Flux in an annulus around the object
6264 """
@@ -65,15 +67,15 @@ class BrightStarStamp(AbstractStamp):
6567 gaiaGMag : float
6668 gaiaId : int
6769 position : Point2I
68- archive_element : Persistable | None = None
70+ archive_elements : Mapping [ str , Persistable ] | None = None
6971 annularFlux : float | None = None
7072 minValidAnnulusFraction : float = 0.0
7173 validAnnulusFraction : float | None = None
7274 optimalInnerRadius : int | None = None
7375 optimalOuterRadius : int | None = None
7476
7577 @classmethod
76- def factory (cls , stamp_im , metadata , idx , archive_element = None , minValidAnnulusFraction = 0.0 ):
78+ def factory (cls , stamp_im , metadata , idx , archive_elements = None , minValidAnnulusFraction = 0.0 ):
7779 """This method is needed to service the FITS reader. We need a standard
7880 interface to construct objects like this. Parameters needed to
7981 construct this object are passed in via a metadata dictionary and then
@@ -90,8 +92,9 @@ def factory(cls, stamp_im, metadata, idx, archive_element=None, minValidAnnulusF
9092 needed by the constructor.
9193 idx : `int`
9294 Index into the lists in ``metadata``
93- archive_element : `~lsst.afw.table.io.Persistable` or None, optional
94- Archive element (e.g. Transform or WCS) associated with this stamp.
95+ archive_elements : `~collections.abc.Mapping`[ `str` , \
96+ `~lsst.afw.table.io.Persistable`], optional
97+ Archive elements (e.g. Transform / WCS) associated with this stamp.
9598 minValidAnnulusFraction : `float`, optional
9699 The fraction of valid pixels within the normalization annulus of a
97100 star.
@@ -101,23 +104,39 @@ def factory(cls, stamp_im, metadata, idx, archive_element=None, minValidAnnulusF
101104 brightstarstamp : `BrightStarStamp`
102105 An instance of this class
103106 """
104- if "X0S " in metadata and "Y0S " in metadata :
105- x0 = metadata . getArray ( "X0S" )[ idx ]
106- y0 = metadata . getArray ( "Y0S" )[ idx ]
107+ if "X0 " in metadata and "Y0 " in metadata :
108+ x0 = metadata [ "X0" ]
109+ y0 = metadata [ "X0" ]
107110 position = Point2I (x0 , y0 )
108111 else :
109112 position = None
110113 return cls (
111114 stamp_im = stamp_im ,
112- gaiaGMag = metadata . getArray ( "G_MAGS" )[ idx ],
113- gaiaId = metadata . getArray ( "GAIA_IDS" )[ idx ],
115+ gaiaGMag = metadata [ "G_MAGS" ],
116+ gaiaId = metadata [ "GAIA_IDS" ],
114117 position = position ,
115- archive_element = archive_element ,
116- annularFlux = metadata . getArray ( "ANNULAR_FLUXES" )[ idx ],
118+ archive_elements = archive_elements ,
119+ annularFlux = metadata [ "ANNULAR_FLUXES" ],
117120 minValidAnnulusFraction = minValidAnnulusFraction ,
118- validAnnulusFraction = metadata . getArray ( "VALID_PIXELS_FRACTION" )[ idx ],
121+ validAnnulusFraction = metadata [ "VALID_PIXELS_FRACTION" ],
119122 )
120123
124+ def _getMaskedImage (self ):
125+ return self .stamp_im
126+
127+ def _getArchiveElements (self ):
128+ return self .archive_elements
129+
130+ def _getMetadata (self ) -> PropertyList | None :
131+ md = PropertyList ()
132+ md ["G_MAG" ] = self .gaiaGMag
133+ md ["GAIA_ID" ] = self .gaiaId
134+ md ["X0" ] = self .position .x
135+ md ["Y0" ] = self .position .y
136+ md ["ANNULAR_FLUX" ] = self .annularFlux
137+ md ["VALID_PIXELS_FRACTION" ] = self .validAnnulusFraction
138+ return md
139+
121140 def measureAndNormalize (
122141 self ,
123142 annulus : SpanSet ,
@@ -248,13 +267,8 @@ def __init__(
248267 use_archive = False ,
249268 ):
250269 super ().__init__ (starStamps , metadata , use_mask , use_variance , use_archive )
251- # Ensure stamps contain a flux measure if expected to be normalized.
252- self ._checkNormalization (False , innerRadius , outerRadius )
253- self ._innerRadius , self ._outerRadius = innerRadius , outerRadius
254- if innerRadius is not None and outerRadius is not None :
255- self .normalized = True
256- else :
257- self .normalized = False
270+ # From v2 onwards, stamps are now always assumed to be unnormalized
271+ self .normalized = False
258272 self .nb90Rots = nb90Rots
259273
260274 @classmethod
@@ -449,26 +463,6 @@ def initAndNormalize(
449463 return bss , badStamps
450464 return bss
451465
452- def _refresh_metadata (self ):
453- """Refresh metadata. Should be called before writing the object out.
454-
455- This method adds full lists of positions, Gaia magnitudes, IDs and
456- annular fluxes to the shared metadata.
457- """
458- self ._metadata ["G_MAGS" ] = self .getMagnitudes ()
459- self ._metadata ["GAIA_IDS" ] = self .getGaiaIds ()
460- positions = self .getPositions ()
461- self ._metadata ["X0S" ] = [xy0 [0 ] for xy0 in positions ]
462- self ._metadata ["Y0S" ] = [xy0 [1 ] for xy0 in positions ]
463- self ._metadata ["ANNULAR_FLUXES" ] = self .getAnnularFluxes ()
464- self ._metadata ["VALID_PIXELS_FRACTION" ] = self .getValidPixelsFraction ()
465- self ._metadata ["NORMALIZED" ] = self .normalized
466- self ._metadata ["INNER_RADIUS" ] = self ._innerRadius
467- self ._metadata ["OUTER_RADIUS" ] = self ._outerRadius
468- if self .nb90Rots is not None :
469- self ._metadata ["NB_90_ROTS" ] = self .nb90Rots
470- return None
471-
472466 @classmethod
473467 def readFits (cls , filename ):
474468 """Build an instance of this class from a file.
@@ -493,26 +487,16 @@ def readFitsWithOptions(cls, filename, options):
493487 """
494488 stamps , metadata = readFitsWithOptions (filename , BrightStarStamp .factory , options )
495489 nb90Rots = metadata ["NB_90_ROTS" ] if "NB_90_ROTS" in metadata else None
496- if metadata ["NORMALIZED" ]:
497- return cls (
498- stamps ,
499- innerRadius = metadata ["INNER_RADIUS" ],
500- outerRadius = metadata ["OUTER_RADIUS" ],
501- nb90Rots = nb90Rots ,
502- metadata = metadata ,
503- use_mask = metadata ["HAS_MASK" ],
504- use_variance = metadata ["HAS_VARIANCE" ],
505- use_archive = metadata ["HAS_ARCHIVE" ],
506- )
507- else :
508- return cls (
509- stamps ,
510- nb90Rots = nb90Rots ,
511- metadata = metadata ,
512- use_mask = metadata ["HAS_MASK" ],
513- use_variance = metadata ["HAS_VARIANCE" ],
514- use_archive = metadata ["HAS_ARCHIVE" ],
515- )
490+ # For backwards compatibility, always assume stamps are unnormalized.
491+ # This allows older stamps to be read in successfully.
492+ return cls (
493+ stamps ,
494+ nb90Rots = nb90Rots ,
495+ metadata = metadata ,
496+ use_mask = metadata ["HAS_MASK" ],
497+ use_variance = metadata ["HAS_VARIANCE" ],
498+ use_archive = metadata ["HAS_ARCHIVE" ],
499+ )
516500
517501 def append (self , item , innerRadius = None , outerRadius = None ):
518502 """Add an additional bright star stamp.
0 commit comments