40
40
41
41
class ComputeExposureSummaryStatsConfig (pexConfig .Config ):
42
42
"""Config for ComputeExposureSummaryTask"""
43
+ doUpdatePsfModelStats = pexConfig .Field (
44
+ dtype = bool ,
45
+ default = True ,
46
+ doc = "Update the grid-based PSF model fidelity statistics (psfTraceRadiusDelta & psfApFluxDelta)?"
47
+ "Set to False if speed is of the essence." ,
48
+ )
49
+ doUpdateApCorrModelStats = pexConfig .Field (
50
+ dtype = bool ,
51
+ default = True ,
52
+ doc = "Update the grid-based apCorr model fidelity statistic (psfApCorrSigmaScaledDelta)? "
53
+ "Set to False if speed is of the essence." ,
54
+ )
55
+ doUpdateMaxDistToNearestPsfStats = pexConfig .Field (
56
+ dtype = bool ,
57
+ default = True ,
58
+ doc = "Update the grid-based maximun distance to the nearest PSF star fidelity statistic "
59
+ "(maxDistToNearestPsf)? Set to False if speed is of the essence." ,
60
+ )
61
+ doUpdateWcsStats = pexConfig .Field (
62
+ dtype = bool ,
63
+ default = True ,
64
+ doc = "Update the wcs statistics? Set to False if speed is of the essence." ,
65
+ )
66
+ doUpdatePhotoCalibStats = pexConfig .Field (
67
+ dtype = bool ,
68
+ default = True ,
69
+ doc = "Update the photoCalib statistics? Set to False if speed is of the essence." ,
70
+ )
71
+ doUpdateBackgroundStats = pexConfig .Field (
72
+ dtype = bool ,
73
+ default = True ,
74
+ doc = "Update the background statistics? Set to False if speed is of the essence." ,
75
+ )
76
+ doUpdateMaskedImageStats = pexConfig .Field (
77
+ dtype = bool ,
78
+ default = True ,
79
+ doc = "Update the masked image (i.e. skyNoise & meanVar) statistics? Set to False "
80
+ "if speed is of the essence." ,
81
+ )
82
+ doUpdateEffectiveTimeStats = pexConfig .Field (
83
+ dtype = bool ,
84
+ default = True ,
85
+ doc = "Update the effective time statistics? Set to False if speed is of the essence." ,
86
+ )
43
87
sigmaClip = pexConfig .Field (
44
88
dtype = float ,
45
89
doc = "Sigma for outlier rejection for sky noise." ,
@@ -158,13 +202,26 @@ class ComputeExposureSummaryStatsTask(pipeBase.Task):
158
202
"""Task to compute exposure summary statistics.
159
203
160
204
This task computes various quantities suitable for DPDD and other
161
- downstream processing at the detector centers, including:
205
+ downstream processing at the detector centers. The non-optionally
206
+ computed quantities are:
162
207
- expTime
163
208
- psfSigma
164
209
- psfArea
165
210
- psfIxx
166
211
- psfIyy
167
212
- psfIxy
213
+
214
+ And these quantities which are computed from the stars in the detector:
215
+ - psfStarDeltaE1Median
216
+ - psfStarDeltaE2Median
217
+ - psfStarDeltaE1Scatter
218
+ - psfStarDeltaE2Scatter
219
+ - psfStarDeltaSizeMedian
220
+ - psfStarDeltaSizeScatter
221
+ - psfStarScaledDeltaSizeScatter
222
+
223
+ The subsequently listed quatities are optionally computed via the
224
+ "doUpdateX" config parameters (which all default to True):
168
225
- ra
169
226
- dec
170
227
- pixelScale (arcsec/pixel)
@@ -178,15 +235,6 @@ class ComputeExposureSummaryStatsTask(pipeBase.Task):
178
235
- astromOffsetMean
179
236
- astromOffsetStd
180
237
181
- These additional quantities are computed from the stars in the detector:
182
- - psfStarDeltaE1Median
183
- - psfStarDeltaE2Median
184
- - psfStarDeltaE1Scatter
185
- - psfStarDeltaE2Scatter
186
- - psfStarDeltaSizeMedian
187
- - psfStarDeltaSizeScatter
188
- - psfStarScaledDeltaSizeScatter
189
-
190
238
These quantities are computed based on the PSF model and image mask
191
239
to assess the robustness of the PSF model across a given detector
192
240
(against, e.g., extrapolation instability):
@@ -243,18 +291,23 @@ def run(self, exposure, sources, background):
243
291
summary , psf , bbox , sources , image_mask = exposure .mask , image_ap_corr_map = exposure .apCorrMap
244
292
)
245
293
246
- wcs = exposure .getWcs ()
247
- visitInfo = exposure .getInfo ().getVisitInfo ()
248
- self .update_wcs_stats (summary , wcs , bbox , visitInfo )
294
+ if self .config .doUpdateWcsStats :
295
+ wcs = exposure .getWcs ()
296
+ visitInfo = exposure .getInfo ().getVisitInfo ()
297
+ self .update_wcs_stats (summary , wcs , bbox , visitInfo )
249
298
250
- photoCalib = exposure .getPhotoCalib ()
251
- self .update_photo_calib_stats (summary , photoCalib )
299
+ if self .config .doUpdatePhotoCalibStats :
300
+ photoCalib = exposure .getPhotoCalib ()
301
+ self .update_photo_calib_stats (summary , photoCalib )
252
302
253
- self .update_background_stats (summary , background )
303
+ if self .config .doUpdateBackgroundStats :
304
+ self .update_background_stats (summary , background )
254
305
255
- self .update_masked_image_stats (summary , exposure .getMaskedImage ())
306
+ if self .config .doUpdateMaskedImageStats :
307
+ self .update_masked_image_stats (summary , exposure .getMaskedImage ())
256
308
257
- self .update_effective_time_stats (summary , exposure )
309
+ if self .config .doUpdateEffectiveTimeStats :
310
+ self .update_effective_time_stats (summary , exposure )
258
311
259
312
md = exposure .getMetadata ()
260
313
if 'SFM_ASTROM_OFFSET_MEAN' in md :
@@ -331,33 +384,49 @@ def update_psf_stats(
331
384
# 750bffe6620e565bda731add1509507f5c40c8bb/src/PsfFlux.cc#L112
332
385
summary .psfArea = float (np .sum (im .array )/ np .sum (im .array ** 2. ))
333
386
334
- if image_mask is not None :
335
- psfApRadius = max (self .config .minPsfApRadiusPix , 3.0 * summary .psfSigma )
336
- self .log .debug ("Using radius of %.3f (pixels) for psfApFluxDelta metric" , psfApRadius )
337
- psfTraceRadiusDelta , psfApFluxDelta = compute_psf_image_deltas (
338
- image_mask ,
339
- psf ,
340
- sampling = self .config .psfGridSampling ,
341
- ap_radius_pix = psfApRadius ,
342
- bad_mask_bits = self .config .psfBadMaskPlanes
343
- )
344
- summary .psfTraceRadiusDelta = float (psfTraceRadiusDelta )
345
- summary .psfApFluxDelta = float (psfApFluxDelta )
346
- if image_ap_corr_map is not None :
347
- if self .config .psfApCorrFieldName not in image_ap_corr_map .keys ():
348
- self .log .warn (f"{ self .config .psfApCorrFieldName } not found in "
349
- "image_ap_corr_map. Setting psfApCorrSigmaScaledDelta to NaN." )
350
- psfApCorrSigmaScaledDelta = nan
351
- else :
352
- image_ap_corr_field = image_ap_corr_map [self .config .psfApCorrFieldName ]
353
- psfApCorrSigmaScaledDelta = compute_ap_corr_sigma_scaled_delta (
354
- image_mask ,
355
- image_ap_corr_field ,
356
- summary .psfSigma ,
357
- sampling = self .config .psfGridSampling ,
358
- bad_mask_bits = self .config .psfBadMaskPlanes ,
359
- )
360
- summary .psfApCorrSigmaScaledDelta = float (psfApCorrSigmaScaledDelta )
387
+ if not self .config .doUpdatePsfModelStats :
388
+ self .log .info ("Note: not computing grid-based PSF model fidelity metrics "
389
+ "psfTraceRadiusDelta & psfApFluxDelta." )
390
+ else :
391
+ if image_mask is None :
392
+ self .log .info ("Note: computation of grid-based PSF model fidelity metrics was requested, "
393
+ "but required image_mask parameter was not provided." )
394
+ else :
395
+ psfApRadius = max (self .config .minPsfApRadiusPix , 3.0 * summary .psfSigma )
396
+ self .log .debug ("Using radius of %.3f (pixels) for psfApFluxDelta metric." , psfApRadius )
397
+
398
+ psfTraceRadiusDelta , psfApFluxDelta = compute_psf_image_deltas (
399
+ image_mask ,
400
+ psf ,
401
+ sampling = self .config .psfGridSampling ,
402
+ ap_radius_pix = psfApRadius ,
403
+ bad_mask_bits = self .config .psfBadMaskPlanes
404
+ )
405
+ summary .psfTraceRadiusDelta = float (psfTraceRadiusDelta )
406
+ summary .psfApFluxDelta = float (psfApFluxDelta )
407
+ if not self .config .doUpdateApCorrModelStats :
408
+ self .log .info ("Note: not computing grid-based apCorr model fidelity metric "
409
+ "psfApCorrSigmaScaledDelta." )
410
+ else :
411
+ if image_mask is None :
412
+ self .log .info ("Note: computation of grid-based apCorr model fidelity metric was requested, "
413
+ "but required image_mask parameter was not provided." )
414
+ else :
415
+ if image_ap_corr_map is not None :
416
+ if self .config .psfApCorrFieldName not in image_ap_corr_map .keys ():
417
+ self .log .warn (f"{ self .config .psfApCorrFieldName } not found in "
418
+ "image_ap_corr_map. Setting psfApCorrSigmaScaledDelta to NaN." )
419
+ psfApCorrSigmaScaledDelta = nan
420
+ else :
421
+ image_ap_corr_field = image_ap_corr_map [self .config .psfApCorrFieldName ]
422
+ psfApCorrSigmaScaledDelta = compute_ap_corr_sigma_scaled_delta (
423
+ image_mask ,
424
+ image_ap_corr_field ,
425
+ summary .psfSigma ,
426
+ sampling = self .config .psfGridSampling ,
427
+ bad_mask_bits = self .config .psfBadMaskPlanes ,
428
+ )
429
+ summary .psfApCorrSigmaScaledDelta = float (psfApCorrSigmaScaledDelta )
361
430
362
431
if sources is None :
363
432
# No sources are available (as in some tests and rare cases where
@@ -418,14 +487,20 @@ def update_psf_stats(
418
487
summary .psfStarDeltaSizeScatter = float (psfStarDeltaSizeScatter )
419
488
summary .psfStarScaledDeltaSizeScatter = float (psfStarScaledDeltaSizeScatter )
420
489
421
- if image_mask is not None :
422
- maxDistToNearestPsf = maximum_nearest_psf_distance (
423
- image_mask ,
424
- psf_cat ,
425
- sampling = self .config .psfSampling ,
426
- bad_mask_bits = self .config .psfBadMaskPlanes
427
- )
428
- summary .maxDistToNearestPsf = float (maxDistToNearestPsf )
490
+ if not self .config .doUpdateMaxDistToNearestPsfStats :
491
+ self .log .info ("Note: not computing grid-based maxDistToNearestPsf model fidelity metric." )
492
+ else :
493
+ if image_mask is None :
494
+ self .log .info ("Note: computation of maxDistToNearestPsf PSF model fidelity metric was "
495
+ "requested, but required image_mask parameter was not provided." )
496
+ else :
497
+ maxDistToNearestPsf = maximum_nearest_psf_distance (
498
+ image_mask ,
499
+ psf_cat ,
500
+ sampling = self .config .psfSampling ,
501
+ bad_mask_bits = self .config .psfBadMaskPlanes
502
+ )
503
+ summary .maxDistToNearestPsf = float (maxDistToNearestPsf )
429
504
430
505
def update_wcs_stats (self , summary , wcs , bbox , visitInfo ):
431
506
"""Compute all summary-statistic fields that depend on the WCS model.
0 commit comments