Coverage for python / lsst / analysis / tools / tasks / coaddDepthSummary.py: 32%

53 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-05 18:53 +0000

1# This file is part of analysis_tools. 

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 

23__all__ = ( 

24 "CoaddDepthSummaryConfig", 

25 "CoaddDepthSummaryTask", 

26) 

27 

28 

29import numpy as np 

30from astropy.table import Table 

31from lsst.pex.config import ListField 

32from lsst.pipe.base import PipelineTask, PipelineTaskConfig, PipelineTaskConnections, Struct 

33from lsst.pipe.base import connectionTypes as cT 

34 

35 

36class CoaddDepthSummaryConnections( 

37 PipelineTaskConnections, 

38 dimensions=("tract", "skymap"), 

39 defaultTemplates={"coaddName": ""}, # set as either deep or template in the pipeline 

40): 

41 data = cT.Input( 

42 doc="Coadd n_image to load from the butler (pixel values are the number of input images).", 

43 name="{coaddName}_coadd_n_image", 

44 storageClass="ImageU", 

45 multiple=True, 

46 dimensions=("tract", "patch", "band", "skymap"), 

47 deferLoad=True, 

48 ) 

49 

50 statTable = cT.Output( 

51 doc="Table with resulting n_image based depth statistics.", 

52 name="{coaddName}_coadd_depth_table", 

53 storageClass="ArrowAstropy", 

54 dimensions=("tract", "skymap"), 

55 ) 

56 

57 

58class CoaddDepthSummaryConfig(PipelineTaskConfig, pipelineConnections=CoaddDepthSummaryConnections): 

59 threshold_list = ListField( 

60 default=[1, 3, 5, 12], 

61 dtype=int, 

62 doc="The n_image pixel value thresholds, in ascending order.", 

63 ) 

64 

65 quantile_list = ListField( 

66 default=[5, 10, 25, 50, 75, 90, 95], 

67 dtype=int, 

68 doc="The percentiles at which to compute n_image values, in ascending order.", 

69 ) 

70 

71 

72class CoaddDepthSummaryTask(PipelineTask): 

73 ConfigClass = CoaddDepthSummaryConfig 

74 _DefaultName = "coaddDepthSummary" 

75 

76 def runQuantum(self, butlerQC, inputRefs, outputRefs): 

77 inputs = butlerQC.get(inputRefs) 

78 outputs = self.run(inputs) 

79 butlerQC.put(outputs, outputRefs) 

80 

81 def run(self, inputs): 

82 t = Table() 

83 bands = [] 

84 patches = [] 

85 medians = [] 

86 stdevs = [] 

87 stats = [] 

88 quantiles = [] 

89 

90 for n_image_handle in inputs["data"]: 

91 n_image = n_image_handle.get() 

92 data_id = n_image_handle.dataId 

93 band = str(data_id.band.name) 

94 patch = int(data_id.patch.id) 

95 median = np.nanmedian(n_image.array) 

96 stdev = np.nanstd(n_image.array) 

97 

98 bands.append(band) 

99 patches.append(patch) 

100 medians.append(median) 

101 stdevs.append(stdev) 

102 

103 band_patch_stats = [] 

104 for threshold in self.config.threshold_list: 

105 # Calculate the percentage of the image with an image depth 

106 # above the given threshold. 

107 stat = np.sum(n_image.array > threshold) * 100 / (n_image.getHeight() * n_image.getWidth()) 

108 band_patch_stats.append(stat) 

109 

110 stats.append(band_patch_stats) 

111 

112 # Calculate the quantiles for image depth 

113 # across the whole n_image array. 

114 quantile = list(np.percentile(n_image.array, q=self.config.quantile_list)) 

115 quantiles.append(quantile) 

116 

117 threshold_col_names = [ 

118 f"depth_above_threshold_{threshold}" for threshold in self.config.threshold_list 

119 ] 

120 quantile_col_names = [f"depth_{q}_percentile" for q in self.config.quantile_list] 

121 

122 # Construct the Astropy table 

123 data = [patches, bands, medians, stdevs] + list(zip(*stats)) + list(zip(*quantiles)) 

124 names = ["patch", "band", "medians", "stdevs"] + threshold_col_names + quantile_col_names 

125 dtype = ( 

126 ["int", "str", "float", "float"] 

127 + ["float" for x in range(len(list(zip(*stats))))] 

128 + ["int" for y in range(len(list(zip(*quantiles))))] 

129 ) 

130 t = Table(data=data, names=names, dtype=dtype) 

131 return Struct(statTable=t)