Coverage for python / lsst / images / _observation_summary_stats.py: 94%
51 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-24 08:34 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-24 08:34 +0000
1# This file is part of lsst-images.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# Use of this source code is governed by a 3-clause BSD-style
10# license that can be found in the LICENSE file.
11from __future__ import annotations
13__all__ = ("ObservationSummaryStats",)
15import dataclasses
16import math
17from typing import Any, Self
19import pydantic
22def _default_corners() -> tuple[float, float, float, float]:
23 return (math.nan, math.nan, math.nan, math.nan)
26class ObservationSummaryStats(pydantic.BaseModel, ser_json_inf_nan="constants"):
27 version: int = pydantic.Field(0, description="Version of the model.")
29 psfSigma: float = pydantic.Field(math.nan, description="PSF determinant radius (pixels).")
31 psfArea: float = pydantic.Field(math.nan, description="PSF effective area (pixels**2).")
33 psfIxx: float = pydantic.Field(math.nan, description="PSF shape Ixx (pixels**2).")
35 psfIyy: float = pydantic.Field(math.nan, description="PSF shape Iyy (pixels**2).")
37 psfIxy: float = pydantic.Field(math.nan, description="PSF shape Ixy (pixels**2).")
39 ra: float = pydantic.Field(math.nan, description="Bounding box center Right Ascension (degrees).")
41 dec: float = pydantic.Field(math.nan, description="Bounding box center Declination (degrees).")
43 pixelScale: float = pydantic.Field(math.nan, description="Measured detector pixel scale (arcsec/pixel).")
45 zenithDistance: float = pydantic.Field(
46 math.nan, description="Bounding box center zenith distance (degrees)."
47 )
49 expTime: float = pydantic.Field(math.nan, description="Exposure time of the exposure (seconds).")
51 zeroPoint: float = pydantic.Field(math.nan, description="Mean zeropoint in detector (mag).")
53 skyBg: float = pydantic.Field(math.nan, description="Average sky background (ADU).")
55 skyNoise: float = pydantic.Field(math.nan, description="Average sky noise (ADU).")
57 meanVar: float = pydantic.Field(math.nan, description="Mean variance of the weight plane (ADU**2).")
59 raCorners: tuple[float, float, float, float] = pydantic.Field(
60 default_factory=_default_corners, description="Right Ascension of bounding box corners (degrees)."
61 )
63 decCorners: tuple[float, float, float, float] = pydantic.Field(
64 default_factory=_default_corners, description="Declination of bounding box corners (degrees)."
65 )
67 astromOffsetMean: float = pydantic.Field(math.nan, description="Astrometry match offset mean.")
69 astromOffsetStd: float = pydantic.Field(math.nan, description="Astrometry match offset stddev.")
71 nPsfStar: int = pydantic.Field(0, description="Number of stars used for psf model.")
73 psfStarDeltaE1Median: float = pydantic.Field(
74 math.nan, description="Psf stars median E1 residual (starE1 - psfE1)."
75 )
77 psfStarDeltaE2Median: float = pydantic.Field(
78 math.nan, description="Psf stars median E2 residual (starE2 - psfE2)."
79 )
81 psfStarDeltaE1Scatter: float = pydantic.Field(
82 math.nan, description="Psf stars MAD E1 scatter (starE1 - psfE1)."
83 )
85 psfStarDeltaE2Scatter: float = pydantic.Field(
86 math.nan, description="Psf stars MAD E2 scatter (starE2 - psfE2)."
87 )
89 psfStarDeltaSizeMedian: float = pydantic.Field(
90 math.nan, description="Psf stars median size residual (starSize - psfSize)."
91 )
93 psfStarDeltaSizeScatter: float = pydantic.Field(
94 math.nan, description="Psf stars MAD size scatter (starSize - psfSize)."
95 )
97 psfStarScaledDeltaSizeScatter: float = pydantic.Field(
98 math.nan, description="Psf stars MAD size scatter scaled by psfSize**2."
99 )
101 psfTraceRadiusDelta: float = pydantic.Field(
102 math.nan,
103 description=(
104 "Delta (max - min) of the model psf trace radius values evaluated on a grid of "
105 "unmasked pixels (pixels)."
106 ),
107 )
109 psfApFluxDelta: float = pydantic.Field(
110 math.nan,
111 description=(
112 "Delta (max - min) of the model psf aperture flux (with aperture radius of max(2, 3*psfSigma)) "
113 "values evaluated on a grid of unmasked pixels."
114 ),
115 )
117 psfApCorrSigmaScaledDelta: float = pydantic.Field(
118 math.nan,
119 description=(
120 "Delta (max - min) of the psf flux aperture correction factors scaled (divided) by the "
121 "psfSigma evaluated on a grid of unmasked pixels."
122 ),
123 )
125 maxDistToNearestPsf: float = pydantic.Field(
126 math.nan,
127 description="Maximum distance of an unmasked pixel to its nearest model psf star (pixels).",
128 )
130 starEMedian: float = pydantic.Field(
131 math.nan,
132 description=(
133 "Median ellipticity (sqrt(starE1**2.0 + starE2**2.0)) of the stars used in the PSF model."
134 ),
135 )
137 starUnNormalizedEMedian: float = pydantic.Field(
138 math.nan,
139 description=(
140 "Median un-normalized ellipticity (sqrt((starXX - starYY)**2.0 + "
141 "(2.0*starXY)**2.0)) of the stars used in the PSF model."
142 ),
143 )
145 effTime: float = pydantic.Field(
146 math.nan,
147 description="Effective exposure time calculated from psfSigma, skyBg, and zeroPoint (seconds).",
148 )
150 effTimePsfSigmaScale: float = pydantic.Field(
151 math.nan, description="PSF scaling of the effective exposure time."
152 )
154 effTimeSkyBgScale: float = pydantic.Field(
155 math.nan, description="Sky background scaling of the effective exposure time."
156 )
158 effTimeZeroPointScale: float = pydantic.Field(
159 math.nan, description="Zeropoint scaling of the effective exposure time."
160 )
162 magLim: float = pydantic.Field(
163 math.nan,
164 description=(
165 "Magnitude limit at fixed SNR (default SNR=5) calculated from psfSigma, skyBg,"
166 " zeroPoint, and readNoise."
167 ),
168 )
170 @classmethod
171 def from_legacy(cls, exposure_summary_stats: Any) -> Self:
172 """Return an `ObservationSummaryStats` from a legacy
173 `lsst.afw.image.ExposureSummaryStats`.
174 """
175 # Assume that all the fields in an ExposureSummaryStats dataclass
176 # are compatible with an ObservationSummaryStats.
177 summary_stats = dataclasses.asdict(exposure_summary_stats)
178 return cls.model_validate(summary_stats)