LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
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
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 pixelScale: float = float('nan')
70 """Measured detector pixel scale (arcsec/pixel)."""
71
72 zenithDistance: float = float('nan')
73 """Bounding box center zenith distance (degrees)."""
74
75 expTime: float = float('nan')
76 """Exposure time of the exposure (seconds)."""
77
78 zeroPoint: float = float('nan')
79 """Mean zeropoint in detector (mag)."""
80
81 skyBg: float = float('nan')
82 """Average sky background (ADU)."""
83
84 skyNoise: float = float('nan')
85 """Average sky noise (ADU)."""
86
87 meanVar: float = float('nan')
88 """Mean variance of the weight plane (ADU**2)."""
89
90 raCorners: list[float] = dataclasses.field(default_factory=_default_corners)
91 """Right Ascension of bounding box corners (degrees)."""
92
93 decCorners: list[float] = dataclasses.field(default_factory=_default_corners)
94 """Declination of bounding box corners (degrees)."""
95
96 astromOffsetMean: float = float('nan')
97 """Astrometry match offset mean."""
98
99 astromOffsetStd: float = float('nan')
100 """Astrometry match offset stddev."""
101
102 nPsfStar: int = 0
103 """Number of stars used for psf model."""
104
105 psfStarDeltaE1Median: float = float('nan')
106 """Psf stars median E1 residual (starE1 - psfE1)."""
107
108 psfStarDeltaE2Median: float = float('nan')
109 """Psf stars median E2 residual (starE2 - psfE2)."""
110
111 psfStarDeltaE1Scatter: float = float('nan')
112 """Psf stars MAD E1 scatter (starE1 - psfE1)."""
113
114 psfStarDeltaE2Scatter: float = float('nan')
115 """Psf stars MAD E2 scatter (starE2 - psfE2)."""
116
117 psfStarDeltaSizeMedian: float = float('nan')
118 """Psf stars median size residual (starSize - psfSize)."""
119
120 psfStarDeltaSizeScatter: float = float('nan')
121 """Psf stars MAD size scatter (starSize - psfSize)."""
122
123 psfStarScaledDeltaSizeScatter: float = float('nan')
124 """Psf stars MAD size scatter scaled by psfSize**2."""
125
126 psfTraceRadiusDelta: float = float('nan')
127 """Delta (max - min) of the model psf trace radius values evaluated on a
128 grid of unmasked pixels (pixels).
129 """
130
131 psfApFluxDelta: float = float('nan')
132 """Delta (max - min) of the model psf aperture flux (with aperture radius of
133 max(2, 3*psfSigma)) values evaluated on a grid of unmasked pixels.
134 """
135
136 psfApCorrSigmaScaledDelta: float = float('nan')
137 """Delta (max - min) of the psf flux aperture correction factors scaled (divided)
138 by the psfSigma evaluated on a grid of unmasked pixels.
139 """
140
141 maxDistToNearestPsf: float = float('nan')
142 """Maximum distance of an unmasked pixel to its nearest model psf star
143 (pixels).
144 """
145
146 effTime: float = float('nan')
147 """Effective exposure time calculated from psfSigma, skyBg, and
148 zeroPoint (seconds).
149 """
150
151 effTimePsfSigmaScale: float = float('nan')
152 """PSF scaling of the effective exposure time."""
153
154 effTimeSkyBgScale: float = float('nan')
155 """Sky background scaling of the effective exposure time."""
156
157 effTimeZeroPointScale: float = float('nan')
158 """Zeropoint scaling of the effective exposure time."""
159
160 magLim: float = float('nan')
161 """Magnitude limit at fixed SNR (default SNR=5) calculated from psfSigma, skyBg,
162 zeroPoint, and readNoise.
163 """
164
165 def __post_init__(self):
166 Storable.__init__(self)
167
168 def isPersistable(self):
169 return True
170
172 return self._persistence_name
173
175 return __name__
176
177 def _write(self):
178 return yaml.dump(dataclasses.asdict(self), encoding='utf-8')
179
180 @staticmethod
181 def _read(bytes):
182 yamlDict = yaml.load(bytes, Loader=yaml.SafeLoader)
183
184 # Special list of fields to forward to new names.
185 forwardFieldDict = {"decl": "dec"}
186
187 # For forwards compatibility, filter out any fields that are
188 # not defined in the dataclass.
189 droppedFields = []
190 for _field in list(yamlDict.keys()):
191 if _field not in ExposureSummaryStats.__dataclass_fields__:
192 if _field in forwardFieldDict and forwardFieldDict[_field] not in yamlDict:
193 yamlDict[forwardFieldDict[_field]] = yamlDict[_field]
194 else:
195 droppedFields.append(_field)
196 yamlDict.pop(_field)
197 if len(droppedFields) > 0:
198 droppedFieldString = ", ".join([str(f) for f in droppedFields])
199 plural = "s" if len(droppedFields) != 1 else ""
200 them = "them" if len(droppedFields) > 1 else "it"
201 warnings.warn(
202 f"Summary field{plural} [{droppedFieldString}] not recognized by this software version;"
203 f" ignoring {them}.",
204 FutureWarning,
205 stacklevel=2,
206 )
207 return ExposureSummaryStats(**yamlDict)
208
209 @classmethod
210 def update_schema(cls, schema: Schema) -> None:
211 """Update an schema to includes for all summary statistic fields.
212
213 Parameters
214 -------
215 schema : `lsst.afw.table.Schema`
216 Schema to add which fields will be added.
217 """
218 schema.addField(
219 "psfSigma",
220 type="F",
221 doc="PSF model second-moments determinant radius (center of chip) (pixel)",
222 units="pixel",
223 )
224 schema.addField(
225 "psfArea",
226 type="F",
227 doc="PSF model effective area (center of chip) (pixel**2)",
228 units='pixel**2',
229 )
230 schema.addField(
231 "psfIxx",
232 type="F",
233 doc="PSF model Ixx (center of chip) (pixel**2)",
234 units='pixel**2',
235 )
236 schema.addField(
237 "psfIyy",
238 type="F",
239 doc="PSF model Iyy (center of chip) (pixel**2)",
240 units='pixel**2',
241 )
242 schema.addField(
243 "psfIxy",
244 type="F",
245 doc="PSF model Ixy (center of chip) (pixel**2)",
246 units='pixel**2',
247 )
248 schema.addField(
249 "raCorners",
250 type="ArrayD",
251 size=4,
252 doc="Right Ascension of bounding box corners (degrees)",
253 units="degree",
254 )
255 schema.addField(
256 "decCorners",
257 type="ArrayD",
258 size=4,
259 doc="Declination of bounding box corners (degrees)",
260 units="degree",
261 )
262 schema.addField(
263 "ra",
264 type="D",
265 doc="Right Ascension of bounding box center (degrees)",
266 units="degree",
267 )
268 schema.addField(
269 "dec",
270 type="D",
271 doc="Declination of bounding box center (degrees)",
272 units="degree",
273 )
274 schema.addField(
275 "zenithDistance",
276 type="F",
277 doc="Zenith distance of bounding box center (degrees)",
278 units="degree",
279 )
280 schema.addField(
281 "pixelScale",
282 type="F",
283 doc="Measured detector pixel scale (arcsec/pixel)",
284 units="arcsec/pixel",
285 )
286 schema.addField(
287 "expTime",
288 type="F",
289 doc="Exposure time of the exposure (seconds)",
290 units="second",
291 )
292 schema.addField(
293 "zeroPoint",
294 type="F",
295 doc="Mean zeropoint in detector (mag)",
296 units="mag",
297 )
298 schema.addField(
299 "skyBg",
300 type="F",
301 doc="Average sky background (ADU)",
302 units="adu",
303 )
304 schema.addField(
305 "skyNoise",
306 type="F",
307 doc="Average sky noise (ADU)",
308 units="adu",
309 )
310 schema.addField(
311 "meanVar",
312 type="F",
313 doc="Mean variance of the weight plane (ADU**2)",
314 units="adu**2"
315 )
316 schema.addField(
317 "astromOffsetMean",
318 type="F",
319 doc="Mean offset of astrometric calibration matches (arcsec)",
320 units="arcsec",
321 )
322 schema.addField(
323 "astromOffsetStd",
324 type="F",
325 doc="Standard deviation of offsets of astrometric calibration matches (arcsec)",
326 units="arcsec",
327 )
328 schema.addField("nPsfStar", type="I", doc="Number of stars used for PSF model")
329 schema.addField(
330 "psfStarDeltaE1Median",
331 type="F",
332 doc="Median E1 residual (starE1 - psfE1) for psf stars",
333 )
334 schema.addField(
335 "psfStarDeltaE2Median",
336 type="F",
337 doc="Median E2 residual (starE2 - psfE2) for psf stars",
338 )
339 schema.addField(
340 "psfStarDeltaE1Scatter",
341 type="F",
342 doc="Scatter (via MAD) of E1 residual (starE1 - psfE1) for psf stars",
343 )
344 schema.addField(
345 "psfStarDeltaE2Scatter",
346 type="F",
347 doc="Scatter (via MAD) of E2 residual (starE2 - psfE2) for psf stars",
348 )
349 schema.addField(
350 "psfStarDeltaSizeMedian",
351 type="F",
352 doc="Median size residual (starSize - psfSize) for psf stars (pixel)",
353 units="pixel",
354 )
355 schema.addField(
356 "psfStarDeltaSizeScatter",
357 type="F",
358 doc="Scatter (via MAD) of size residual (starSize - psfSize) for psf stars (pixel)",
359 units="pixel",
360 )
361 schema.addField(
362 "psfStarScaledDeltaSizeScatter",
363 type="F",
364 doc="Scatter (via MAD) of size residual scaled by median size squared",
365 )
366 schema.addField(
367 "psfTraceRadiusDelta",
368 type="F",
369 doc="Delta (max - min) of the model psf trace radius values evaluated on a grid of "
370 "unmasked pixels (pixel).",
371 units="pixel",
372 )
373 schema.addField(
374 "psfApFluxDelta",
375 type="F",
376 doc="Delta (max - min) of the model psf aperture flux (with aperture radius of "
377 "max(2, 3*psfSigma)) values evaluated on a grid of unmasked pixels.",
378 )
379 schema.addField(
380 "psfApCorrSigmaScaledDelta",
381 type="F",
382 doc="Delta (max - min) of the model psf aperture correction factors scaled (divided) "
383 "by the psfSigma evaluated on a grid of unmasked pixels.",
384 )
385 schema.addField(
386 "maxDistToNearestPsf",
387 type="F",
388 doc="Maximum distance of an unmasked pixel to its nearest model psf star (pixel).",
389 units="pixel",
390 )
391 schema.addField(
392 "effTime",
393 type="F",
394 doc="Effective exposure time calculated from psfSigma, skyBg, and "
395 "zeroPoint (seconds).",
396 units="second",
397 )
398 schema.addField(
399 "effTimePsfSigmaScale",
400 type="F",
401 doc="PSF scaling of the effective exposure time."
402 )
403 schema.addField(
404 "effTimeSkyBgScale",
405 type="F",
406 doc="Sky background scaling of the effective exposure time."
407 )
408 schema.addField(
409 "effTimeZeroPointScale",
410 type="F",
411 doc="Zeropoint scaling of the effective exposure time."
412 )
413 schema.addField(
414 "magLim",
415 type="F",
416 doc="Magnitude limit at SNR=5 (M5) calculated from psfSigma, "
417 "skyBg, zeroPoint, and readNoise.",
418 units="mag",
419 )
420
421 def update_record(self, record: BaseRecord) -> None:
422 """Write summary-statistic columns into a record.
423
424 Parameters
425 ----------
426 record : `lsst.afw.table.BaseRecord`
427 Record to update. This is expected to frequently be an
428 `ExposureRecord` instance (with higher-level code adding other
429 columns and objects), but this method can work with any record
430 type.
431 """
432 for field in dataclasses.fields(self):
433 value = getattr(self, field.name)
434 if field.name == "version":
435 continue
436 elif field.type.startswith("list"):
437 record[field.name][:] = value
438 else:
439 record[field.name] = value
440
441 @classmethod
442 def from_record(cls, record: BaseRecord) -> ExposureSummaryStats:
443 """Read summary-statistic columns from a record into ``self``.
444
445 Parameters
446 ----------
447 record : `lsst.afw.table.BaseRecord`
448 Record to read from. This is expected to frequently be an
449 `ExposureRecord` instance (with higher-level code adding other
450 columns and objects), but this method can work with any record
451 type, ignoring any attributes or columns it doesn't recognize.
452
453 Returns
454 -------
455 summary : `ExposureSummaryStats`
456 Summary statistics object created from the given record.
457 """
458 return cls(
459 **{
460 field.name: (
461 record[field.name] if not field.type.startswith("list")
462 else [float(v) for v in record[field.name]]
463 )
464 for field in dataclasses.fields(cls)
465 if field.name != "version"
466 }
467 )
ExposureSummaryStats from_record(cls, BaseRecord record)
virtual bool isPersistable() const noexcept
Return true if this particular object can be persisted using afw::table::io.
Interface supporting iteration over heterogenous containers.
Definition Storable.h:58