lsst.afw g5dde539398+b655ba634f
Loading...
Searching...
No Matches
_exposureSummaryStats.py
Go to the documentation of this file.
1# This file is part of afw.
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# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21from __future__ import annotations
22
23import dataclasses
24from typing import TYPE_CHECKING
25import yaml
26import warnings
27
28from ..typehandling import Storable, StorableHelperFactory
29
30if TYPE_CHECKING:
31 from ..table import BaseRecord, Schema
32
33__all__ = ("ExposureSummaryStats", )
34
35
36def _default_corners():
37 return [float("nan")] * 4
38
39
40@dataclasses.dataclass
42 _persistence_name = 'ExposureSummaryStats'
43
44 _factory = StorableHelperFactory(__name__, _persistence_name)
45
46 version: int = 0
47
48 psfSigma: float = float('nan')
49 """PSF determinant radius (pixels)."""
50
51 psfArea: float = float('nan')
52 """PSF effective area (pixels**2)."""
53
54 psfIxx: float = float('nan')
55 """PSF shape Ixx (pixels**2)."""
56
57 psfIyy: float = float('nan')
58 """PSF shape Iyy (pixels**2)."""
59
60 psfIxy: float = float('nan')
61 """PSF shape Ixy (pixels**2)."""
62
63 ra: float = float('nan')
64 """Bounding box center Right Ascension (degrees)."""
65
66 dec: float = float('nan')
67 """Bounding box center Declination (degrees)."""
68
69 zenithDistance: float = float('nan')
70 """Bounding box center zenith distance (degrees)."""
71
72 zeroPoint: float = float('nan')
73 """Mean zeropoint in detector (mag)."""
74
75 skyBg: float = float('nan')
76 """Average sky background (ADU)."""
77
78 skyNoise: float = float('nan')
79 """Average sky noise (ADU)."""
80
81 meanVar: float = float('nan')
82 """Mean variance of the weight plane (ADU**2)."""
83
84 raCorners: list[float] = dataclasses.field(default_factory=_default_corners)
85 """Right Ascension of bounding box corners (degrees)."""
86
87 decCorners: list[float] = dataclasses.field(default_factory=_default_corners)
88 """Declination of bounding box corners (degrees)."""
89
90 astromOffsetMean: float = float('nan')
91 """Astrometry match offset mean."""
92
93 astromOffsetStd: float = float('nan')
94 """Astrometry match offset stddev."""
95
96 nPsfStar: int = 0
97 """Number of stars used for psf model."""
98
99 psfStarDeltaE1Median: float = float('nan')
100 """Psf stars median E1 residual (starE1 - psfE1)."""
101
102 psfStarDeltaE2Median: float = float('nan')
103 """Psf stars median E2 residual (starE2 - psfE2)."""
104
105 psfStarDeltaE1Scatter: float = float('nan')
106 """Psf stars MAD E1 scatter (starE1 - psfE1)."""
107
108 psfStarDeltaE2Scatter: float = float('nan')
109 """Psf stars MAD E2 scatter (starE2 - psfE2)."""
110
111 psfStarDeltaSizeMedian: float = float('nan')
112 """Psf stars median size residual (starSize - psfSize)."""
113
114 psfStarDeltaSizeScatter: float = float('nan')
115 """Psf stars MAD size scatter (starSize - psfSize)."""
116
117 psfStarScaledDeltaSizeScatter: float = float('nan')
118 """Psf stars MAD size scatter scaled by psfSize**2."""
119
120 psfTraceRadiusDelta: float = float('nan')
121 """Delta (max - min) of the model psf trace radius values evaluated on a
122 grid of unmasked pixels (pixels).
123 """
124
125 maxDistToNearestPsf: float = float('nan')
126 """Maximum distance of an unmasked pixel to its nearest model psf star
127 (pixels).
128 """
129
130 def __post_init__(self):
131 Storable.__init__(self)
132
133 def isPersistable(self):
134 return True
135
136 def _getPersistenceName(self):
137 return self._persistence_name
138
139 def _getPythonModule(self):
140 return __name__
141
142 def _write(self):
143 return yaml.dump(dataclasses.asdict(self), encoding='utf-8')
144
145 @staticmethod
146 def _read(bytes):
147 yamlDict = yaml.load(bytes, Loader=yaml.SafeLoader)
148 # For forwards compatibility, filter out any fields that are
149 # not defined in the dataclass.
150 droppedFields = []
151 for _field in list(yamlDict.keys()):
152 if _field not in ExposureSummaryStats.__dataclass_fields__:
153 droppedFields.append(_field)
154 yamlDict.pop(_field)
155 if len(droppedFields) > 0:
156 droppedFieldString = ", ".join([str(f) for f in droppedFields])
157 warnings.warn(
158 (
159 f"Could not read summary fields [{droppedFieldString}]. "
160 "Please use a newer stack."
161 ),
162 FutureWarning,
163 )
164 return ExposureSummaryStats(**yamlDict)
165
166 @classmethod
167 def update_schema(cls, schema: Schema) -> None:
168 """Update an schema to includes for all summary statistic fields.
169
170 Parameters
171 -------
172 schema : `lsst.afw.table.Schema`
173 Schema to add which fields will be added.
174 """
175 schema.addField(
176 "psfSigma",
177 type="F",
178 doc="PSF model second-moments determinant radius (center of chip) (pixel)",
179 )
180 schema.addField(
181 "psfArea",
182 type="F",
183 doc="PSF model effective area (center of chip) (pixel**2)",
184 )
185 schema.addField(
186 "psfIxx", type="F", doc="PSF model Ixx (center of chip) (pixel**2)"
187 )
188 schema.addField(
189 "psfIyy", type="F", doc="PSF model Iyy (center of chip) (pixel**2)"
190 )
191 schema.addField(
192 "psfIxy", type="F", doc="PSF model Ixy (center of chip) (pixel**2)"
193 )
194 schema.addField(
195 "raCorners",
196 type="ArrayD",
197 size=4,
198 doc="Right Ascension of bounding box corners (degrees)",
199 )
200 schema.addField(
201 "decCorners",
202 type="ArrayD",
203 size=4,
204 doc="Declination of bounding box corners (degrees)",
205 )
206 schema.addField(
207 "ra", type="D", doc="Right Ascension of bounding box center (degrees)"
208 )
209 schema.addField(
210 "dec", type="D", doc="Declination of bounding box center (degrees)"
211 )
212 schema.addField(
213 "zenithDistance",
214 type="F",
215 doc="Zenith distance of bounding box center (degrees)",
216 )
217 schema.addField("zeroPoint", type="F", doc="Mean zeropoint in detector (mag)")
218 schema.addField("skyBg", type="F", doc="Average sky background (ADU)")
219 schema.addField("skyNoise", type="F", doc="Average sky noise (ADU)")
220 schema.addField(
221 "meanVar", type="F", doc="Mean variance of the weight plane (ADU**2)"
222 )
223 schema.addField(
224 "astromOffsetMean",
225 type="F",
226 doc="Mean offset of astrometric calibration matches (arcsec)",
227 )
228 schema.addField(
229 "astromOffsetStd",
230 type="F",
231 doc="Standard deviation of offsets of astrometric calibration matches (arcsec)",
232 )
233 schema.addField("nPsfStar", type="I", doc="Number of stars used for PSF model")
234 schema.addField(
235 "psfStarDeltaE1Median",
236 type="F",
237 doc="Median E1 residual (starE1 - psfE1) for psf stars",
238 )
239 schema.addField(
240 "psfStarDeltaE2Median",
241 type="F",
242 doc="Median E2 residual (starE2 - psfE2) for psf stars",
243 )
244 schema.addField(
245 "psfStarDeltaE1Scatter",
246 type="F",
247 doc="Scatter (via MAD) of E1 residual (starE1 - psfE1) for psf stars",
248 )
249 schema.addField(
250 "psfStarDeltaE2Scatter",
251 type="F",
252 doc="Scatter (via MAD) of E2 residual (starE2 - psfE2) for psf stars",
253 )
254 schema.addField(
255 "psfStarDeltaSizeMedian",
256 type="F",
257 doc="Median size residual (starSize - psfSize) for psf stars (pixel)",
258 )
259 schema.addField(
260 "psfStarDeltaSizeScatter",
261 type="F",
262 doc="Scatter (via MAD) of size residual (starSize - psfSize) for psf stars (pixel)",
263 )
264 schema.addField(
265 "psfStarScaledDeltaSizeScatter",
266 type="F",
267 doc="Scatter (via MAD) of size residual scaled by median size squared",
268 )
269 schema.addField(
270 "psfTraceRadiusDelta",
271 type="F",
272 doc="Delta (max - min) of the model psf trace radius values evaluated on a grid of "
273 "unmasked pixels (pixel).",
274 )
275 schema.addField(
276 "maxDistToNearestPsf",
277 type="F",
278 doc="Maximum distance of an unmasked pixel to its nearest model psf star (pixel).",
279 )
280
281 def update_record(self, record: BaseRecord) -> None:
282 """Write summary-statistic columns into a record.
283
284 Parameters
285 ----------
287 Record to update. This is expected to frequently be an
288 `ExposureRecord` instance (with higher-level code adding other
289 columns and objects), but this method can work with any record
290 type.
291 """
292 for field in dataclasses.fields(self):
293 value = getattr(self, field.name)
294 if field.name == "version":
295 continue
296 elif field.type.startswith("list"):
297 record[field.name][:] = value
298 else:
299 record[field.name] = value
300
301 @classmethod
302 def from_record(cls, record: BaseRecord) -> ExposureSummaryStats:
303 """Read summary-statistic columns from a record into ``self``.
304
305 Parameters
306 ----------
308 Record to read from. This is expected to frequently be an
309 `ExposureRecord` instance (with higher-level code adding other
310 columns and objects), but this method can work with any record
311 type, ignoring any attributes or columns it doesn't recognize.
312
313 Returns
314 -------
315 summary : `ExposureSummaryStats`
316 Summary statistics object created from the given record.
317 """
318 return cls(
319 **{
320 field.name: (
321 record[field.name] if not field.type.startswith("list")
322 else [float(v) for v in record[field.name]]
323 )
324 for field in dataclasses.fields(cls)
325 if field.name != "version"
326 }
327 )
ExposureSummaryStats from_record(cls, BaseRecord record)
Base class for all records.
Definition: BaseRecord.h:31
Defines the fields and offsets for a table.
Definition: Schema.h:51
virtual bool isPersistable() const noexcept
Return true if this particular object can be persisted using afw::table::io.
Definition: Persistable.h:102
Interface supporting iteration over heterogenous containers.
Definition: Storable.h:58
daf::base::PropertyList * list
Definition: fits.cc:928