44 _persistence_name =
'ExposureSummaryStats'
46 _factory = StorableHelperFactory(__name__, _persistence_name)
50 psfSigma: float = float(
'nan')
51 """PSF determinant radius (pixels)."""
53 psfArea: float = float(
'nan')
54 """PSF effective area (pixels**2)."""
56 psfIxx: float = float(
'nan')
57 """PSF shape Ixx (pixels**2)."""
59 psfIyy: float = float(
'nan')
60 """PSF shape Iyy (pixels**2)."""
62 psfIxy: float = float(
'nan')
63 """PSF shape Ixy (pixels**2)."""
65 ra: float = float(
'nan')
66 """Bounding box center Right Ascension (degrees)."""
68 dec: float = float(
'nan')
69 """Bounding box center Declination (degrees)."""
71 pixelScale: float = float(
'nan')
72 """Measured detector pixel scale (arcsec/pixel)."""
74 zenithDistance: float = float(
'nan')
75 """Bounding box center zenith distance (degrees)."""
77 expTime: float = float(
'nan')
78 """Exposure time of the exposure (seconds)."""
80 zeroPoint: float = float(
'nan')
81 """Mean zeropoint in detector (mag)."""
83 skyBg: float = float(
'nan')
84 """Average sky background (ADU)."""
86 skyNoise: float = float(
'nan')
87 """Average sky noise (ADU)."""
89 meanVar: float = float(
'nan')
90 """Mean variance of the weight plane (ADU**2)."""
92 raCorners: list[float] = dataclasses.field(default_factory=_default_corners)
93 """Right Ascension of bounding box corners (degrees)."""
95 decCorners: list[float] = dataclasses.field(default_factory=_default_corners)
96 """Declination of bounding box corners (degrees)."""
98 psfAdaptiveThresholdValue: float = float(
'nan')
99 """Threshold value used in the adaptive threshold detection pass for PSF modelling."""
101 psfAdaptiveIncludeThresholdMultiplier: float = float(
'nan')
102 """Threshold multiplier used in the adaptive threshold detection pass for PSF modelling."""
104 nShapeletsStar: int = 0
105 """Number of sources used in the shapelet decomposition."""
107 shapeletsOnlyIqScore: float = float(
'nan')
108 """The dimensionless image quality score as determined from the shapelets decomposition
109 that includes power only from the non-atmospheric decomposition coefficients. The
110 score spans the range [0.0, 1.0] with lower values indicating better image quality.
113 shapeletsIqScore: float = float(
'nan')
114 """The dimensionless image quality score as determined from the shapelets decomposition
115 that includes power from the median centroid offset between those used in the decomposition
116 and those of the centroid slot in addition to non-atmospheric decomposition coefficients.
117 The score spans the range [0.0, 1.0] with lower values indicating better image quality.
120 shapeletsCoeffs: list[float] = dataclasses.field(default_factory=list)
121 """List of coefficients from the PSF star shapelet decomposition."""
123 centroidDiffShapeletsVsSlotMedian: float = float(
'nan')
124 """Median centroid difference (sqrt((slot_x - shapelet_x)**2 + (slot_y - shapelet_y)**2)) for
125 sources used in the shapelet decomposition (pixels).
128 shapeletsStarEMedian: float = float(
'nan')
129 """Median ellipticity (sqrt(starE1**2.0 + starE2**2.0)) of the sources used in the
130 shapelet decomposition.
133 shapeletsStarUnNormalizedEMedian: float = float(
'nan')
134 """Median un-normalized ellipticity (sqrt((starXX - starYY)**2.0 + (2.0*starXY)**2.0))
135 of the sources used in the shapelet decomposition (pixels**2).
138 refCatSourceDensity: float = float(
'nan')
139 """Source density for the detector region as computed from the loaded reference catalog
140 (number per degrees**2).
143 astromOffsetMean: float = float(
'nan')
144 """Astrometry match offset mean."""
146 astromOffsetStd: float = float(
'nan')
147 """Astrometry match offset stddev."""
150 """Number of stars used for psf model."""
152 psfStarDeltaE1Median: float = float(
'nan')
153 """Psf stars median E1 residual (starE1 - psfE1)."""
155 psfStarDeltaE2Median: float = float(
'nan')
156 """Psf stars median E2 residual (starE2 - psfE2)."""
158 psfStarDeltaE1Scatter: float = float(
'nan')
159 """Psf stars MAD E1 scatter (starE1 - psfE1)."""
161 psfStarDeltaE2Scatter: float = float(
'nan')
162 """Psf stars MAD E2 scatter (starE2 - psfE2)."""
164 psfStarDeltaSizeMedian: float = float(
'nan')
165 """Psf stars median size residual (starSize - psfSize)."""
167 psfStarDeltaSizeScatter: float = float(
'nan')
168 """Psf stars MAD size scatter (starSize - psfSize)."""
170 psfStarScaledDeltaSizeScatter: float = float(
'nan')
171 """Psf stars MAD size scatter scaled by psfSize**2."""
173 psfTraceRadiusDelta: float = float(
'nan')
174 """Delta (max - min) of the model psf trace radius values evaluated on a
175 grid of unmasked pixels (pixels).
178 psfApFluxDelta: float = float(
'nan')
179 """Delta (max - min) of the model psf aperture flux (with aperture radius of
180 max(2, 3*psfSigma)) values evaluated on a grid of unmasked pixels.
183 psfApCorrSigmaScaledDelta: float = float(
'nan')
184 """Delta (max - min) of the psf flux aperture correction factors scaled (divided)
185 by the psfSigma evaluated on a grid of unmasked pixels.
188 maxDistToNearestPsf: float = float(
'nan')
189 """Maximum distance of an unmasked pixel to its nearest model psf star
193 starEMedian: float = float(
'nan')
194 """Median ellipticity (sqrt(starE1**2.0 + starE2**2.0)) of the stars used
198 starUnNormalizedEMedian: float = float(
'nan')
199 """Median un-normalized ellipticity (sqrt((starXX - starYY)**2.0 + (2.0*starXY)**2.0))
200 of the stars used in the PSF model (pixel**2).
203 starComa1Median: float = float(
'nan')
204 """Coma-like higher-order moment combination: median M30 + M12
205 of the stars used in the PSF model.
208 starComa2Median: float = float(
'nan')
209 """Coma-like higher-order moment combination: median M21 + M03
210 of the stars used in the PSF model.
213 starTrefoil1Median: float = float(
'nan')
214 """Trefoil-like higher-order moment combination: median M30 - 3*M12
215 of the stars used in the PSF model.
218 starTrefoil2Median: float = float(
'nan')
219 """Trefoil-like higher-order moment combination: median 3*M21 - M03
220 of the stars used in the PSF model.
223 starKurtosisMedian: float = float(
'nan')
224 """Kurtosis-like higher-order moment combination: median M40 + 2*M22 + M04
225 of the stars used in the PSF model.
228 starE41Median: float = float(
'nan')
229 """Fourth-order ellipticity-like higher-order moment combination: median M40 - M04
230 of the stars used in the PSF model.
233 starE42Median: float = float(
'nan')
234 """Fourth-order ellipticity-like higher-order moment combination: median 2*(M31 + M13)
235 of the stars used in the PSF model.
238 effTime: float = float(
'nan')
239 """Effective exposure time calculated from psfSigma, skyBg, and
243 effTimePsfSigmaScale: float = float(
'nan')
244 """PSF scaling of the effective exposure time."""
246 effTimeSkyBgScale: float = float(
'nan')
247 """Sky background scaling of the effective exposure time."""
249 effTimeZeroPointScale: float = float(
'nan')
250 """Zeropoint scaling of the effective exposure time."""
252 magLim: float = float(
'nan')
253 """Magnitude limit at fixed SNR (default SNR=5) calculated from psfSigma, skyBg,
254 zeroPoint, and readNoise.
257 psfTE1e1: float = float(
'nan')
258 """Per-exposure TE1e1 ~ <de1 de1> of PSF residual ellipticity, averaged over
259 theta [0,1] arcmin via treecorr KK correlation. Dimensionless; used to form the
260 full-survey TE1 metric.
263 psfTE1e2: float = float(
'nan')
264 """Per-exposure TE1e2 ~ <de2 de2> of PSF residual ellipticity, averaged over
265 theta [0,1] arcmin via treecorr KK correlation. Dimensionless; used to form the
266 full-survey TE1 metric.
269 psfTE1ex: float = float(
'nan')
270 """Per-exposure TE1ex ~ <de1 de2> of PSF residual ellipticity, averaged over
271 theta [0,1] arcmin via treecorr KK correlation. Dimensionless; used to form the
272 full-survey TE1 metric.
275 psfTE2e1: float = float(
'nan')
276 """Per-exposure TE2e1 ~ <de1 de1> of PSF residual ellipticity, averaged over
277 theta [5,100] arcmin via treecorr KK correlation. Dimensionless; used to form the
278 full-survey TE2 metric.
281 psfTE2e2: float = float(
'nan')
282 """Per-exposure TE2e2 ~ <de2 de2> of PSF residual ellipticity, averaged over
283 theta [5,100] arcmin via treecorr KK correlation. Dimensionless; used to form the
284 full-survey TE2 metric.
287 psfTE2ex: float = float(
'nan')
288 """Per-exposure TE2ex ~ <de1 de2> of PSF residual ellipticity, averaged over
289 theta [5,100] arcmin via treecorr KK correlation. Dimensionless; used to form the
290 full-survey TE2 metric.
293 psfTE3e1: float = float(
'nan')
294 """Per-exposure median-over-CCDs of TE3e1 ~ <de1 de1> of PSF residual
295 ellipticity, where each CCD uses theta within [0,5] arcmin bins. Dimensionless;
296 downstream pipelines take the 85th percentile over
297 images to evaluate TE3.
300 psfTE3e2: float = float(
'nan')
301 """Per-exposure median-over-CCDs of TE3e2 ~ <de2 de2> of PSF residual
302 ellipticity, where each CCD uses theta within [0,5] arcmin bins. Dimensionless;
303 downstream pipelines take the 85th percentile over
304 images to evaluate TE3.
307 psfTE3ex: float = float(
'nan')
308 """Per-exposure median-over-CCDs of TE3ex ~ <de1 de2> of PSF residual
309 ellipticity, where each CCD uses theta within [0,5] arcmin bins. Dimensionless;
310 downstream pipelines take the 85th percentile over
311 images to evaluate TE3.
314 psfTE4e1: float = float(
'nan')
315 """Per-exposure median-over-CCDs of TE4e1 ~ <de1 de1> of PSF residual
316 ellipticity, where each CCD uses theta within [5,20] arcmin bins. Dimensionless;
317 downstream pipelines take the 85th percentile over
318 images to evaluate TE4.
321 psfTE4e2: float = float(
'nan')
322 """Per-exposure median-over-CCDs of TE4e2 ~ <de2 de2> of PSF residual
323 ellipticity, where each CCD uses theta within [5,20] arcmin bins. Dimensionless;
324 downstream pipelines take the 85th percentile over
325 images to evaluate TE4.
328 psfTE4ex: float = float(
'nan')
329 """Per-exposure median-over-CCDs of TE4ex ~ <de1 de2> of PSF residual
330 ellipticity, where each CCD uses theta within [5,20] arcmin bins. Dimensionless;
331 downstream pipelines take the 85th percentile over
332 images to evaluate TE4.
336 Storable.__init__(self)
348 return yaml.dump(dataclasses.asdict(self), encoding=
'utf-8')
352 yamlDict = yaml.load(bytes, Loader=yaml.SafeLoader)
355 forwardFieldDict = {
"decl":
"dec"}
360 for _field
in list(yamlDict.keys()):
361 if _field
not in ExposureSummaryStats.__dataclass_fields__:
362 if _field
in forwardFieldDict
and forwardFieldDict[_field]
not in yamlDict:
363 yamlDict[forwardFieldDict[_field]] = yamlDict[_field]
365 droppedFields.append(_field)
367 if len(droppedFields) > 0:
368 droppedFieldString =
", ".join([str(f)
for f
in droppedFields])
369 plural =
"s" if len(droppedFields) != 1
else ""
370 them =
"them" if len(droppedFields) > 1
else "it"
372 f
"Summary field{plural} [{droppedFieldString}] not recognized by this software version;"
373 f
" ignoring {them}.",
381 """Update an schema to includes for all summary statistic fields.
385 schema : `lsst.afw.table.Schema`
386 Schema to add which fields will be added.
391 doc=
"PSF model second-moments determinant radius (center of chip) (pixel)",
397 doc=
"PSF model effective area (center of chip) (pixel**2)",
403 doc=
"PSF model Ixx (center of chip) (pixel**2)",
409 doc=
"PSF model Iyy (center of chip) (pixel**2)",
415 doc=
"PSF model Ixy (center of chip) (pixel**2)",
422 doc=
"Right Ascension of bounding box corners (degrees)",
429 doc=
"Declination of bounding box corners (degrees)",
435 doc=
"Right Ascension of bounding box center (degrees)",
441 doc=
"Declination of bounding box center (degrees)",
447 doc=
"Zenith distance of bounding box center (degrees)",
453 doc=
"Measured detector pixel scale (arcsec/pixel)",
454 units=
"arcsec/pixel",
459 doc=
"Exposure time of the exposure (seconds)",
465 doc=
"Mean zeropoint in detector (mag)",
471 doc=
"Average sky background (ADU)",
477 doc=
"Average sky noise (ADU)",
483 doc=
"Mean variance of the weight plane (ADU**2)",
487 "psfAdaptiveThresholdValue",
489 doc=
"Threshold value used in the adaptive threshold detection pass for PSF modelling.",
493 "psfAdaptiveIncludeThresholdMultiplier",
495 doc=
"Threshold multiplier used in the adaptive threshold detection pass for PSF modelling.",
501 doc=
"Number of sources used in the shapelet decomposition.",
505 "shapeletsOnlyIqScore",
507 doc=
"The dimensionless image quality score as determined from the shapelets "
508 "decomposition that includes power only from the non-atmospheric decomposition "
509 "coefficients. The score spans the range [0.0, 1.0] with lower values indicating "
510 "better image quality.",
516 doc=
"The dimensionless image quality score as determined from the shapelets "
517 "decomposition that includes power from the median centroid offset between those "
518 "used in the decomposition and those of the centroid slot in addition to "
519 "non-atmospheric decomposition coefficients. The score spans the range [0.0, 1.0] "
520 "with lower values indicating better image quality.",
527 doc=
"List of coefficients from the PSF star shapelet decomposition.",
531 "centroidDiffShapeletsVsSlotMedian",
533 doc=
"Median centroid difference (sqrt((slot_x - shapelet_x)**2 + (slot_y - shapelet_y)**2)) "
534 "for sources used in the shapelet decomposition.",
538 "shapeletsStarEMedian",
540 doc=
"Median ellipticity (sqrt(starE1**2.0 + starE2**2.0)) of the stars used in the "
541 "shapelet decomposition.",
545 "shapeletsStarUnNormalizedEMedian",
547 doc=
"Median un-normalized ellipticity (sqrt((starXX - starYY)**2.0 + (2.0*starXY)**2.0)) "
548 "of the stars used in the shapelet decomposition.",
552 "refCatSourceDensity",
554 doc=
"Source density for the detector region as computed from the loaded reference catalog "
555 "(number per degrees**2)",
561 doc=
"Mean offset of astrometric calibration matches (arcsec)",
567 doc=
"Standard deviation of offsets of astrometric calibration matches (arcsec)",
570 schema.addField(
"nPsfStar", type=
"I", doc=
"Number of stars used for PSF model")
572 "psfStarDeltaE1Median",
574 doc=
"Median E1 residual (starE1 - psfE1) for psf stars",
577 "psfStarDeltaE2Median",
579 doc=
"Median E2 residual (starE2 - psfE2) for psf stars",
582 "psfStarDeltaE1Scatter",
584 doc=
"Scatter (via MAD) of E1 residual (starE1 - psfE1) for psf stars",
587 "psfStarDeltaE2Scatter",
589 doc=
"Scatter (via MAD) of E2 residual (starE2 - psfE2) for psf stars",
592 "psfStarDeltaSizeMedian",
594 doc=
"Median size residual (starSize - psfSize) for psf stars (pixel)",
598 "psfStarDeltaSizeScatter",
600 doc=
"Scatter (via MAD) of size residual (starSize - psfSize) for psf stars (pixel)",
604 "psfStarScaledDeltaSizeScatter",
606 doc=
"Scatter (via MAD) of size residual scaled by median size squared",
609 "psfTraceRadiusDelta",
611 doc=
"Delta (max - min) of the model psf trace radius values evaluated on a grid of "
612 "unmasked pixels (pixel).",
618 doc=
"Delta (max - min) of the model psf aperture flux (with aperture radius of "
619 "max(2, 3*psfSigma)) values evaluated on a grid of unmasked pixels.",
622 "psfApCorrSigmaScaledDelta",
624 doc=
"Delta (max - min) of the model psf aperture correction factors scaled (divided) "
625 "by the psfSigma evaluated on a grid of unmasked pixels.",
628 "maxDistToNearestPsf",
630 doc=
"Maximum distance of an unmasked pixel to its nearest model psf star (pixel).",
636 doc=
"Median ellipticity (sqrt(starE1**2.0 + starE2**2.0)) of the stars used in "
640 "starUnNormalizedEMedian",
642 doc=
"Median un-normalized ellipticity (sqrt((starXX - starYY)**2.0 + (2.0*starXY)**2.0)) "
643 "of the stars used in the PSF model.",
648 doc=
"Coma-like higher-order moment combination: median M30 + M12 "
649 "of the stars used in the PSF model.",
654 doc=
"Coma-like higher-order moment combination: median M21 + M03 "
655 "of the stars used in the PSF model.",
658 "starTrefoil1Median",
660 doc=
"Trefoil-like higher-order moment combination: median M30 - 3*M12 "
661 "of the stars used in the PSF model.",
664 "starTrefoil2Median",
666 doc=
"Trefoil-like higher-order moment combination: median 3*M21 - M03 "
667 "of the stars used in the PSF model.",
670 "starKurtosisMedian",
672 doc=
"Kurtosis-like higher-order moment combination: median M40 + 2*M22 + M04 "
673 "of the stars used in the PSF model.",
678 doc=
"Fourth-order ellipticity-like higher-order moment combination: median M40 - M04 "
679 "of the stars used in the PSF model.",
684 doc=
"Fourth-order ellipticity-like higher-order moment combination: median 2*(M31 + M13) "
685 "of the stars used in the PSF model.",
690 doc=
"Effective exposure time calculated from psfSigma, skyBg, and "
691 "zeroPoint (seconds).",
695 "effTimePsfSigmaScale",
697 doc=
"PSF scaling of the effective exposure time."
702 doc=
"Sky background scaling of the effective exposure time."
705 "effTimeZeroPointScale",
707 doc=
"Zeropoint scaling of the effective exposure time."
712 doc=
"Magnitude limit at SNR=5 (M5) calculated from psfSigma, "
713 "skyBg, zeroPoint, and readNoise.",
719 doc=
"Per-exposure E1e1 ~ <de1 de1> of PSF residual ellipticity "
720 "over theta within [0,1] arcmin. Dimensionless; contributes to TE1.",
725 doc=
"Per-exposure E1e2 ~ <de2 de2> of PSF residual ellipticity "
726 "over theta within [0,1] arcmin. Dimensionless; contributes to TE1.",
731 doc=
"Per-exposure E1ex ~ <de1 de2> of PSF residual ellipticity "
732 "over theta within [0,1] arcmin. Dimensionless; contributes to TE1.",
737 doc=
"Per-exposure E2e1 ~ <de1 de1> of PSF residual ellipticity "
738 "over theta within [5, 100] arcmin. Dimensionless; contributes to TE2.",
743 doc=
"Per-exposure E2e2 ~ <de2 de2> of PSF residual ellipticity "
744 "over theta within [5, 100] arcmin. Dimensionless; contributes to TE2.",
749 doc=
"Per-exposure E2ex ~ <de1 de2> of PSF residual ellipticity "
750 "over theta within [5, 100] arcmin. Dimensionless; contributes to TE2.",
755 doc=
"Per-exposure median-over-CCDs of TE3e1 ~ <de1 de1> with "
756 "per-CCD theta within [0,5] arcmin. Dimensionless; used for TE3.",
761 doc=
"Per-exposure median-over-CCDs of TE3e2 ~ <de2 de2> with "
762 "per-CCD theta within [0,5] arcmin. Dimensionless; used for TE3.",
767 doc=
"Per-exposure median-over-CCDs of TE3ex ~ <de1 de2> with "
768 "per-CCD theta within [0,5] arcmin. Dimensionless; used for TE3.",
773 doc=
"Per-exposure median-over-CCDs of TE4e1 ~ <de1 de1> with "
774 "per-CCD theta within [5, 20] arcmin. Dimensionless; used for TE4.",
779 doc=
"Per-exposure median-over-CCDs of TE4e2 ~ <de2 de2> with "
780 "per-CCD theta within [5, 20] arcmin. Dimensionless; used for TE4.",
785 doc=
"Per-exposure median-over-CCDs of TE4ex ~ <de1 de2> with "
786 "per-CCD theta within [5, 20] arcmin. Dimensionless; used for TE4.",
790 """Write summary-statistic columns into a record.
794 record : `lsst.afw.table.BaseRecord`
795 Record to update. This is expected to frequently be an
796 `ExposureRecord` instance (with higher-level code adding other
797 columns and objects), but this method can work with any record
800 for field
in dataclasses.fields(self):
801 value = getattr(self, field.name)
802 if field.name ==
"version":
804 elif field.type.startswith(
"list"):
805 record[field.name] = np.array(value, dtype=record[field.name].dtype)
807 record[field.name] = value
811 """Read summary-statistic columns from a record into ``self``.
815 record : `lsst.afw.table.BaseRecord`
816 Record to read from. This is expected to frequently be an
817 `ExposureRecord` instance (with higher-level code adding other
818 columns and objects), but this method can work with any record
819 type, ignoring any attributes or columns it doesn't recognize.
823 summary : `ExposureSummaryStats`
824 Summary statistics object created from the given record.
829 record[field.name]
if not field.type.startswith(
"list")
830 else [float(v)
for v
in record[field.name]]
832 for field
in dataclasses.fields(cls)
833 if field.name !=
"version"