LSST Applications 30.0.7,g0e76e35be5+e8e946ae08,g19811a7679+138f7293ba,g199a45376c+5e234f8357,g1fd858c14a+2f48dbc4c4,g262e1987ae+fb36cac54d,g29ae962dfc+d9108a0941,g2c21b0017a+4f59a27f16,g31e44d4a5c+b0138be388,g33ac35c1f1+28b9f72785,g35bb328faa+b0138be388,g40c9b15c53+823ad735c1,g47891489e3+bcc48a0b46,g53246c7159+b0138be388,g64539dfbff+e8e946ae08,g67b6fd64d1+bcc48a0b46,g74acd417e5+422380537a,g76965917b2+a5ca99c4d9,g786e29fd12+796b79145d,g7aefaa3e3d+dc0c200193,g86b635cae8+734fe384f0,g87389fa792+d8b5378923,g89139ef638+bcc48a0b46,g8bbb235e95+3f4f7f9447,g8ea07a8fe4+78a4c88802,g9290983e33+ffdc83c6f7,g92c671f44c+e8e946ae08,gaa753fd333+03f406da14,gbf99507273+b0138be388,gc49b57b85e+8df26ee1f0,gca7fc764a6+bcc48a0b46,gd7ef33dd92+bcc48a0b46,gdab6d2f7ff+422380537a,ge1c02a5578+b0138be388,ge410e46f29+bcc48a0b46,ge80df9fc40+e6db5413d1,geaed405ab2+1de65a85c6,gf5dcc679e7+35a0ce2edd,gf5f1c85443+e8e946ae08
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 starEMedian: float = float('nan')
147 """Median ellipticity (sqrt(starE1**2.0 + starE2**2.0)) of the stars used
148 in the PSF model.
149 """
150
151 starUnNormalizedEMedian: float = float('nan')
152 """Median un-normalized ellipticity
153 (sqrt((starXX - starYY)**2.0 + (2.0*starXY)**2.0))
154 of the stars used in the PSF model.
155 """
156
157 effTime: float = float('nan')
158 """Effective exposure time calculated from psfSigma, skyBg, and
159 zeroPoint (seconds).
160 """
161
162 effTimePsfSigmaScale: float = float('nan')
163 """PSF scaling of the effective exposure time."""
164
165 effTimeSkyBgScale: float = float('nan')
166 """Sky background scaling of the effective exposure time."""
167
168 effTimeZeroPointScale: float = float('nan')
169 """Zeropoint scaling of the effective exposure time."""
170
171 magLim: float = float('nan')
172 """Magnitude limit at fixed SNR (default SNR=5) calculated from psfSigma, skyBg,
173 zeroPoint, and readNoise.
174 """
175
176 def __post_init__(self):
177 Storable.__init__(self)
178
179 def isPersistable(self):
180 return True
181
183 return self._persistence_name
184
186 return __name__
187
188 def _write(self):
189 return yaml.dump(dataclasses.asdict(self), encoding='utf-8')
190
191 @staticmethod
192 def _read(bytes):
193 yamlDict = yaml.load(bytes, Loader=yaml.SafeLoader)
194
195 # Special list of fields to forward to new names.
196 forwardFieldDict = {"decl": "dec"}
197
198 # For forwards compatibility, filter out any fields that are
199 # not defined in the dataclass.
200 droppedFields = []
201 for _field in list(yamlDict.keys()):
202 if _field not in ExposureSummaryStats.__dataclass_fields__:
203 if _field in forwardFieldDict and forwardFieldDict[_field] not in yamlDict:
204 yamlDict[forwardFieldDict[_field]] = yamlDict[_field]
205 else:
206 droppedFields.append(_field)
207 yamlDict.pop(_field)
208 if len(droppedFields) > 0:
209 droppedFieldString = ", ".join([str(f) for f in droppedFields])
210 plural = "s" if len(droppedFields) != 1 else ""
211 them = "them" if len(droppedFields) > 1 else "it"
212 warnings.warn(
213 f"Summary field{plural} [{droppedFieldString}] not recognized by this software version;"
214 f" ignoring {them}.",
215 FutureWarning,
216 stacklevel=2,
217 )
218 return ExposureSummaryStats(**yamlDict)
219
220 @classmethod
221 def update_schema(cls, schema: Schema) -> None:
222 """Update an schema to includes for all summary statistic fields.
223
224 Parameters
225 -------
226 schema : `lsst.afw.table.Schema`
227 Schema to add which fields will be added.
228 """
229 schema.addField(
230 "psfSigma",
231 type="F",
232 doc="PSF model second-moments determinant radius (center of chip) (pixel)",
233 units="pixel",
234 )
235 schema.addField(
236 "psfArea",
237 type="F",
238 doc="PSF model effective area (center of chip) (pixel**2)",
239 units='pixel**2',
240 )
241 schema.addField(
242 "psfIxx",
243 type="F",
244 doc="PSF model Ixx (center of chip) (pixel**2)",
245 units='pixel**2',
246 )
247 schema.addField(
248 "psfIyy",
249 type="F",
250 doc="PSF model Iyy (center of chip) (pixel**2)",
251 units='pixel**2',
252 )
253 schema.addField(
254 "psfIxy",
255 type="F",
256 doc="PSF model Ixy (center of chip) (pixel**2)",
257 units='pixel**2',
258 )
259 schema.addField(
260 "raCorners",
261 type="ArrayD",
262 size=4,
263 doc="Right Ascension of bounding box corners (degrees)",
264 units="degree",
265 )
266 schema.addField(
267 "decCorners",
268 type="ArrayD",
269 size=4,
270 doc="Declination of bounding box corners (degrees)",
271 units="degree",
272 )
273 schema.addField(
274 "ra",
275 type="D",
276 doc="Right Ascension of bounding box center (degrees)",
277 units="degree",
278 )
279 schema.addField(
280 "dec",
281 type="D",
282 doc="Declination of bounding box center (degrees)",
283 units="degree",
284 )
285 schema.addField(
286 "zenithDistance",
287 type="F",
288 doc="Zenith distance of bounding box center (degrees)",
289 units="degree",
290 )
291 schema.addField(
292 "pixelScale",
293 type="F",
294 doc="Measured detector pixel scale (arcsec/pixel)",
295 units="arcsec/pixel",
296 )
297 schema.addField(
298 "expTime",
299 type="F",
300 doc="Exposure time of the exposure (seconds)",
301 units="second",
302 )
303 schema.addField(
304 "zeroPoint",
305 type="F",
306 doc="Mean zeropoint in detector (mag)",
307 units="mag",
308 )
309 schema.addField(
310 "skyBg",
311 type="F",
312 doc="Average sky background (ADU)",
313 units="adu",
314 )
315 schema.addField(
316 "skyNoise",
317 type="F",
318 doc="Average sky noise (ADU)",
319 units="adu",
320 )
321 schema.addField(
322 "meanVar",
323 type="F",
324 doc="Mean variance of the weight plane (ADU**2)",
325 units="adu**2"
326 )
327 schema.addField(
328 "astromOffsetMean",
329 type="F",
330 doc="Mean offset of astrometric calibration matches (arcsec)",
331 units="arcsec",
332 )
333 schema.addField(
334 "astromOffsetStd",
335 type="F",
336 doc="Standard deviation of offsets of astrometric calibration matches (arcsec)",
337 units="arcsec",
338 )
339 schema.addField("nPsfStar", type="I", doc="Number of stars used for PSF model")
340 schema.addField(
341 "psfStarDeltaE1Median",
342 type="F",
343 doc="Median E1 residual (starE1 - psfE1) for psf stars",
344 )
345 schema.addField(
346 "psfStarDeltaE2Median",
347 type="F",
348 doc="Median E2 residual (starE2 - psfE2) for psf stars",
349 )
350 schema.addField(
351 "psfStarDeltaE1Scatter",
352 type="F",
353 doc="Scatter (via MAD) of E1 residual (starE1 - psfE1) for psf stars",
354 )
355 schema.addField(
356 "psfStarDeltaE2Scatter",
357 type="F",
358 doc="Scatter (via MAD) of E2 residual (starE2 - psfE2) for psf stars",
359 )
360 schema.addField(
361 "psfStarDeltaSizeMedian",
362 type="F",
363 doc="Median size residual (starSize - psfSize) for psf stars (pixel)",
364 units="pixel",
365 )
366 schema.addField(
367 "psfStarDeltaSizeScatter",
368 type="F",
369 doc="Scatter (via MAD) of size residual (starSize - psfSize) for psf stars (pixel)",
370 units="pixel",
371 )
372 schema.addField(
373 "psfStarScaledDeltaSizeScatter",
374 type="F",
375 doc="Scatter (via MAD) of size residual scaled by median size squared",
376 )
377 schema.addField(
378 "psfTraceRadiusDelta",
379 type="F",
380 doc="Delta (max - min) of the model psf trace radius values evaluated on a grid of "
381 "unmasked pixels (pixel).",
382 units="pixel",
383 )
384 schema.addField(
385 "psfApFluxDelta",
386 type="F",
387 doc="Delta (max - min) of the model psf aperture flux (with aperture radius of "
388 "max(2, 3*psfSigma)) values evaluated on a grid of unmasked pixels.",
389 )
390 schema.addField(
391 "psfApCorrSigmaScaledDelta",
392 type="F",
393 doc="Delta (max - min) of the model psf aperture correction factors scaled (divided) "
394 "by the psfSigma evaluated on a grid of unmasked pixels.",
395 )
396 schema.addField(
397 "maxDistToNearestPsf",
398 type="F",
399 doc="Maximum distance of an unmasked pixel to its nearest model psf star (pixel).",
400 units="pixel",
401 )
402 schema.addField(
403 "starEMedian",
404 type="F",
405 doc="Median ellipticity (sqrt(starE1**2.0 + starE2**2.0)) of the stars used in "
406 "the PSF model.",
407 )
408 schema.addField(
409 "starUnNormalizedEMedian",
410 type="F",
411 doc="Median un-normalized ellipticity (sqrt((starXX - starYY)**2.0 + (2.0*starXY)**2.0)) "
412 "of the stars used in the PSF model.",
413 )
414 schema.addField(
415 "effTime",
416 type="F",
417 doc="Effective exposure time calculated from psfSigma, skyBg, and "
418 "zeroPoint (seconds).",
419 units="second",
420 )
421 schema.addField(
422 "effTimePsfSigmaScale",
423 type="F",
424 doc="PSF scaling of the effective exposure time."
425 )
426 schema.addField(
427 "effTimeSkyBgScale",
428 type="F",
429 doc="Sky background scaling of the effective exposure time."
430 )
431 schema.addField(
432 "effTimeZeroPointScale",
433 type="F",
434 doc="Zeropoint scaling of the effective exposure time."
435 )
436 schema.addField(
437 "magLim",
438 type="F",
439 doc="Magnitude limit at SNR=5 (M5) calculated from psfSigma, "
440 "skyBg, zeroPoint, and readNoise.",
441 units="mag",
442 )
443
444 def update_record(self, record: BaseRecord) -> None:
445 """Write summary-statistic columns into a record.
446
447 Parameters
448 ----------
449 record : `lsst.afw.table.BaseRecord`
450 Record to update. This is expected to frequently be an
451 `ExposureRecord` instance (with higher-level code adding other
452 columns and objects), but this method can work with any record
453 type.
454 """
455 for field in dataclasses.fields(self):
456 value = getattr(self, field.name)
457 if field.name == "version":
458 continue
459 elif field.type.startswith("list"):
460 record[field.name][:] = value
461 else:
462 record[field.name] = value
463
464 @classmethod
465 def from_record(cls, record: BaseRecord) -> ExposureSummaryStats:
466 """Read summary-statistic columns from a record into ``self``.
467
468 Parameters
469 ----------
470 record : `lsst.afw.table.BaseRecord`
471 Record to read from. This is expected to frequently be an
472 `ExposureRecord` instance (with higher-level code adding other
473 columns and objects), but this method can work with any record
474 type, ignoring any attributes or columns it doesn't recognize.
475
476 Returns
477 -------
478 summary : `ExposureSummaryStats`
479 Summary statistics object created from the given record.
480 """
481 return cls(
482 **{
483 field.name: (
484 record[field.name] if not field.type.startswith("list")
485 else [float(v) for v in record[field.name]]
486 )
487 for field in dataclasses.fields(cls)
488 if field.name != "version"
489 }
490 )
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