22 """Read preprocessed bright stars and stack them to build an extended
26 from dataclasses
import dataclass
27 from typing
import List
29 from lsst.afw import image
as afwImage
36 """Single extended PSF over a focal plane region.
38 The focal plane region is defined through a list
43 extended_psf_image : `lsst.afw.image.MaskedImageF`
44 Image of the extended PSF model.
45 detector_list : `list` [`int`]
46 List of detector IDs that define the focal plane region over which this
47 extended PSF model has been built (and can be used).
49 extended_psf_image: afwImage.MaskedImageF
50 detector_list: List[int]
54 """Extended PSF model.
56 Each instance may contain a default extended PSF, a set of extended PSFs
57 that correspond to different focal plane regions, or both. At this time,
58 focal plane regions are always defined as a subset of detectors.
62 default_extended_psf : `lsst.afw.image.MaskedImageF`
63 Extended PSF model to be used as default (or only) extended PSF model.
71 """Add a new focal plane region, along wit hits extended PSF, to the
76 extended_psf_image : `lsst.afw.image.MaskedImageF`
77 Extended PSF model for the region.
79 Name of the focal plane region. Will be converted to all-uppercase.
80 detector_list : `list` [`int`]
81 List of IDs for the detectors that define the focal plane region.
83 region_name = region_name.upper()
85 raise ValueError(f
"Region name {region_name} is already used by this ExtendedPsf instance.")
87 extended_psf_image=extended_psf_image, detector_list=detector_list)
88 for det
in detector_list:
92 """Return the appropriate extended PSF.
94 If the instance contains no extended PSF defined over focal plane
95 regions, the default extended PSF will be returned regardless of
96 whether a detector ID was passed as argument.
100 detector : `int`, optional
101 Detector ID. If focal plane region PSFs are defined, is used to
102 determine which model to return.
106 extendedPsfImage : `lsst.afw.image.MaskedImageF`
107 The extended PSF model. If this instance contains extended PSFs
108 defined over focal plane regions, the extended PSF model for the
109 region that contains ``detector`` is returned. If not, the default
110 extended PSF is returned.
114 raise ValueError(
"No default extended PSF available; please provide detector number.")
121 """Returns the number of extended PSF models present in the instance.
123 Note that if the instance contains both a default model and a set of
124 focal plane region models, the length of the instance will be the
125 number of regional models, plus one (the default). This is true even
126 in the case where the default model is one of the focal plane
127 region-specific models.
135 """Returns the extended PSF for a focal plane region.
137 The region can be identified either by name, or through a detector ID.
141 region_name : `str` or `None`, optional
142 Name of the region for which the extended PSF should be retrieved.
143 Ignored if ``detector`` is provided. Must be provided if
144 ``detector`` is None.
145 detector : `int` or `None`, optional
146 If provided, returns the extended PSF for the focal plane region
147 that includes this detector.
152 Raised if neither ``detector`` nor ``regionName`` is provided.
155 if region_name
is None:
156 raise ValueError(
"One of either a regionName or a detector number must be provided.")
161 """Write this object to a file.
166 Name of file to write.
172 metadata[
"HAS_REGIONS"] =
True
175 metadata[region] = e_psf_region.detector_list
177 metadata[
"HAS_REGIONS"] =
False
178 fits_primary = afwFits.Fits(filename,
"w")
179 fits_primary.createEmpty()
180 fits_primary.writeMetadata(metadata)
181 fits_primary.closeFile()
185 default_hdu_metadata.update({
"REGION":
"DEFAULT",
"EXTNAME":
"IMAGE"})
186 self.
default_extended_psfdefault_extended_psf.image.writeFits(filename, metadata=default_hdu_metadata, mode=
"a")
187 default_hdu_metadata.update({
"REGION":
"DEFAULT",
"EXTNAME":
"MASK"})
188 self.
default_extended_psfdefault_extended_psf.mask.writeFits(filename, metadata=default_hdu_metadata, mode=
"a")
190 for j, (region, e_psf_region)
in enumerate(self.
focal_plane_regionsfocal_plane_regions.items()):
192 metadata.update({
"REGION": region,
"EXTNAME":
"IMAGE"})
193 e_psf_region.extended_psf_image.image.writeFits(filename, metadata=metadata, mode=
"a")
194 metadata.update({
"REGION": region,
"EXTNAME":
"MASK"})
195 e_psf_region.extended_psf_image.mask.writeFits(filename, metadata=metadata, mode=
"a")
198 """Alias for ``write_fits``; exists for compatibility with the Butler.
204 """Build an instance of this class from a file.
209 Name of the file to read.
212 global_metadata = afwFits.readMetadata(filename, hdu=0)
213 has_default = global_metadata.getBool(
"HAS_DEFAULT")
214 if global_metadata.getBool(
"HAS_REGIONS"):
215 focal_plane_region_names = global_metadata.getArray(
"REGION_NAMES")
217 focal_plane_region_names = []
218 f = afwFits.Fits(filename,
"r")
219 n_extensions = f.countHdus()
220 extended_psf_parts = {}
221 for j
in range(1, n_extensions):
222 md = afwFits.readMetadata(filename, hdu=j)
223 if has_default
and md[
"REGION"] ==
"DEFAULT":
224 if md[
"EXTNAME"] ==
"IMAGE":
225 default_image = afwImage.ImageF(filename, hdu=j)
226 elif md[
"EXTNAME"] ==
"MASK":
227 default_mask = afwImage.MaskX(filename, hdu=j)
229 if md[
"EXTNAME"] ==
"IMAGE":
230 extended_psf_part = afwImage.ImageF(filename, hdu=j)
231 elif md[
"EXTNAME"] ==
"MASK":
232 extended_psf_part = afwImage.MaskX(filename, hdu=j)
233 extended_psf_parts.setdefault(md[
"REGION"], {})[md[
"EXTNAME"].lower()] = extended_psf_part
236 extended_psf = cls(afwImage.MaskedImageF(default_image, default_mask))
240 if len(extended_psf_parts) != len(focal_plane_region_names):
241 raise ValueError(f
"Number of per-region extended PSFs read ({len(extended_psf_parts)}) does not "
242 "match with the number of regions recorded in the metadata "
243 f
"({len(focal_plane_region_names)}).")
245 for r_name
in focal_plane_region_names:
246 extended_psf_image = afwImage.MaskedImageF(**extended_psf_parts[r_name])
247 detector_list = global_metadata.getArray(r_name)
248 extended_psf.add_regional_extended_psf(extended_psf_image, r_name, detector_list)
254 """Alias for ``readFits``; exists for compatibility with the Butler.
def writeFits(self, filename)
def readFits(cls, filename)
detectors_focal_plane_regions
def __call__(self, detector=None)
def get_regional_extended_psf(self, region_name=None, detector=None)
def add_regional_extended_psf(self, extended_psf_image, region_name, detector_list)
def read_fits(cls, filename)
def write_fits(self, filename)
def __init__(self, default_extended_psf=None)