22from __future__
import annotations
25 "ExtendedPsfCandidateInfo",
26 "ExtendedPsfCandidateSerializationModel",
27 "ExtendedPsfCandidatesSerializationModel",
28 "ExtendedPsfCandidate",
29 "ExtendedPsfCandidates",
33from collections.abc
import Sequence
34from types
import EllipsisType
37from astro_metadata_translator
import ObservationInfo
38from pydantic
import BaseModel, Field
40from lsst.images
import (
43 ImageSerializationModel,
46 MaskedImageSerializationModel,
51from lsst.images.serialization
import ArchiveTree, InputArchive, MetadataValue, OutputArchive, Quantity
52from lsst.images.utils
import is_none
53from lsst.resources
import ResourcePathExpression
57 """Information about a star in an `ExtendedPsfCandidate`.
61 visit : `int`, optional
62 The visit during which the star was observed.
63 detector : `int`, optional
64 The detector on which the star was observed.
65 ref_id : `int`, optional
66 The reference catalog ID for the star.
67 ref_mag : `float`, optional
68 The reference magnitude for the star.
69 position_x : `float`, optional
70 The x-coordinate of the star in the focal plane.
71 position_y : `float`, optional
72 The y-coordinate of the star in the focal plane.
73 focal_plane_radius : `~lsst.images.utils.Quantity`, optional
74 The radius of the star from the center of the focal plane.
75 focal_plane_angle : `~lsst.images.utils.Quantity`, optional
76 The angle of the star in the focal plane, measured from the +x axis.
79 visit: int |
None =
None
80 detector: int |
None =
None
81 ref_id: int |
None =
None
82 ref_mag: float |
None =
None
83 position_x: float |
None =
None
84 position_y: float |
None =
None
85 focal_plane_radius: Quantity |
None =
None
86 focal_plane_angle: Quantity |
None =
None
89 attrs =
", ".join(f
"{k}={v!r}" for k, v
in self.__dict__.items())
90 return f
"ExtendedPsfCandidateInfo({attrs})"
96 """A Pydantic model to represent a serialized `ExtendedPsfCandidate`."""
98 psf_kernel_image: ImageSerializationModel[P] |
None = Field(
101 description=
"Kernel image of the PSF at the cutout center.",
103 star_info: ExtendedPsfCandidateInfo = Field(description=
"Information about the star in the cutout.")
107 """A Pydantic model to represent serialized `ExtendedPsfCandidates`."""
109 candidates: list[ExtendedPsfCandidateSerializationModel[P]] = Field(
110 default_factory=list,
111 description=
"The candidate cutouts in this collection.",
116 """A cutout centered on a star, with associated metadata.
120 image : `~lsst.images.Image`
121 The main data image for this star cutout.
122 mask : `~lsst.images.Mask`, optional
123 Bitmask that annotates the main image's pixels.
124 variance : `~lsst.images.Image`, optional
125 Per-pixel variance estimates for the image.
126 mask_schema : `~lsst.images.MaskSchema`, optional
127 Schema for the mask, required if a mask is provided.
128 projection : `~lsst.images.Projection`, optional
129 Projection to map pixels to the sky.
130 obs_info : `~astro_metadata_translator.ObservationInfo`, optional
131 Standardized description of visit metadata.
132 metadata : `dict` [`str`, `MetadataValue`], optional
133 Additional metadata to associate with this cutout.
134 psf_kernel_image : `~lsst.images.Image`, optional
135 Kernel image of the PSF at the cutout center.
136 star_info : `ExtendedPsfCandidateInfo`, optional
137 Information about the star in the cutout.
141 psf_kernel_image : `~lsst.images.Image`
142 Kernel image of the PSF at the cutout center.
143 star_info : `ExtendedPsfCandidateInfo`
144 Information about the star in this cutout.
151 mask: Mask |
None =
None,
152 variance: Image |
None =
None,
153 mask_schema: MaskSchema |
None =
None,
154 projection: Projection |
None =
None,
155 obs_info: ObservationInfo |
None =
None,
156 metadata: dict[str, MetadataValue] |
None =
None,
157 psf_kernel_image: Image |
None =
None,
158 star_info: ExtendedPsfCandidateInfo |
None =
None,
164 mask_schema=mask_schema,
165 projection=projection,
173 def __getitem__(self, bbox: Box | EllipsisType) -> ExtendedPsfCandidate:
177 return self._transfer_metadata(
181 mask=self.mask[bbox],
182 variance=self.variance[bbox],
190 return f
"ExtendedPsfCandidate({self.image!s}, {list(self.mask.schema.names)}, {self.star_info})"
194 f
"ExtendedPsfCandidate({self.image!r}, mask_schema={self.mask.schema!r}, "
195 f
"star_info={self.star_info!r})"
200 """Kernel image of the PSF at the cutout center."""
202 raise RuntimeError(
"No PSF kernel image is attached to this ExtendedPsfCandidate.")
207 """Return the ExtendedPsfCandidateInfo associated with this star."""
210 def copy(self) -> ExtendedPsfCandidate:
211 """Deep-copy the star cutout, metadata, and star info."""
212 return self._transfer_metadata(
214 image=self._image.
copy(),
215 mask=self._mask.
copy(),
216 variance=self._variance.
copy(),
223 def serialize(self, archive: OutputArchive[Any]) -> ExtendedPsfCandidateSerializationModel:
224 masked_image_model = super().
serialize(archive)
225 serialized_psf_kernel_image = (
226 archive.serialize_direct(
234 **masked_image_model.model_dump(),
235 psf_kernel_image=serialized_psf_kernel_image,
240 def _get_archive_tree_type[P: BaseModel](
241 pointer_type: type[P],
242 ) -> type[ExtendedPsfCandidateSerializationModel[P]]:
243 return ExtendedPsfCandidateSerializationModel[pointer_type]
247 model: ExtendedPsfCandidateSerializationModel[Any],
248 archive: InputArchive[Any],
250 bbox: Box |
None =
None,
251 ) -> ExtendedPsfCandidate:
252 masked_image = MaskedImage.deserialize(model, archive, bbox=bbox)
254 Image.deserialize(model.psf_kernel_image, archive)
if model.psf_kernel_image
is not None else None
258 mask=masked_image.mask,
259 variance=masked_image.variance,
260 psf_kernel_image=psf_kernel_image,
261 star_info=model.star_info,
262 )._finish_deserialize(model)
266 """A collection of star cutouts.
270 candidates : `Iterable` [`ExtendedPsfCandidate`]
271 Collection of `ExtendedPsfCandidate` instances.
272 metadata : `dict` [`str`, `MetadataValue`], optional
273 Global metadata associated with the collection.
277 metadata : `dict` [`str`, `MetadataValue`]
278 Global metadata associated with the collection.
279 ref_id_map : `dict` [`int`, `ExtendedPsfCandidate`]
280 A mapping from reference IDs to `ExtendedPsfCandidate` objects.
281 Only includes candidates with valid reference IDs.
286 candidates: Sequence[ExtendedPsfCandidate],
287 metadata: dict[str, MetadataValue] |
None =
None,
290 self.
_metadata = {}
if metadata
is None else dict(metadata)
292 candidate.star_info.ref_id: candidate
293 for candidate
in self
294 if candidate.star_info.ref_id
is not None
301 if isinstance(index, slice):
309 return f
"ExtendedPsfCandidates(length={len(self)})"
315 """Return the collection's global metadata as a dict."""
320 """Map reference IDs to `ExtendedPsfCandidate` objects."""
324 def read_fits(cls, url: ResourcePathExpression) -> ExtendedPsfCandidates:
325 """Read a collection from a FITS file.
330 URL of the file to read; may be any type supported by
331 `lsst.resources.ResourcePath`.
333 return fits.read(cls, url).deserialized
336 """Write the collection to a FITS file.
341 Name of the file to write to. Must not already exist.
343 fits.write(self, filename)
345 def serialize(self, archive: OutputArchive[Any]) -> ExtendedPsfCandidatesSerializationModel:
348 archive.serialize_direct(f
"candidate_{index}", candidate.serialize)
349 for index, candidate
in enumerate(self.
_candidates)
356 model: ExtendedPsfCandidatesSerializationModel[Any],
357 archive: InputArchive[Any],
358 ) -> ExtendedPsfCandidates:
361 ExtendedPsfCandidate.deserialize(candidate_model, archive)
362 for candidate_model
in model.candidates
364 metadata=model.metadata,
368 def _get_archive_tree_type[P: BaseModel](
369 pointer_type: type[P],
370 ) -> type[ExtendedPsfCandidatesSerializationModel[P]]:
371 return ExtendedPsfCandidatesSerializationModel[pointer_type]
ExtendedPsfCandidateInfo _star_info
__init__(self, Image image, *, Mask|None mask=None, Image|None variance=None, MaskSchema|None mask_schema=None, Projection|None projection=None, ObservationInfo|None obs_info=None, dict[str, MetadataValue]|None metadata=None, Image|None psf_kernel_image=None, ExtendedPsfCandidateInfo|None star_info=None)
ExtendedPsfCandidate deserialize(ExtendedPsfCandidateSerializationModel[Any] model, InputArchive[Any] archive, *, Box|None bbox=None)
ExtendedPsfCandidate copy(self)
ExtendedPsfCandidateSerializationModel serialize(self, OutputArchive[Any] archive)
Image psf_kernel_image(self)
ExtendedPsfCandidateInfo star_info(self)
ExtendedPsfCandidate __getitem__(self, Box|EllipsisType bbox)
ExtendedPsfCandidatesSerializationModel serialize(self, OutputArchive[Any] archive)
None write_fits(self, str filename)
ExtendedPsfCandidates deserialize(ExtendedPsfCandidatesSerializationModel[Any] model, InputArchive[Any] archive)
ExtendedPsfCandidates read_fits(cls, ResourcePathExpression url)
__init__(self, Sequence[ExtendedPsfCandidate] candidates, dict[str, MetadataValue]|None metadata=None)
ExtendedPsfCandidateInfo star_info
ImageSerializationModel psf_kernel_image