Coverage for python/lsst/pipe/tasks/fit_coadd_psf.py: 58%

51 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-04-15 10:48 +0000

1# This file is part of pipe_tasks. 

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/>. 

21 

22__all__ = [ 

23 "CoaddPsfFitConfig", "CoaddPsfFitSubConfig", "CoaddPsfFitSubTask", "CoaddPsfFitTask", 

24] 

25 

26from .fit_multiband import CatalogExposure, CatalogExposureConfig 

27from lsst.obs.base import ExposureIdInfo 

28import lsst.pex.config as pexConfig 

29import lsst.pipe.base as pipeBase 

30import lsst.pipe.base.connectionTypes as cT 

31 

32from abc import ABC, abstractmethod 

33from pydantic.dataclasses import dataclass 

34 

35 

36@dataclass(frozen=True, kw_only=True, config=CatalogExposureConfig) 

37class CatalogExposurePsf(CatalogExposure): 

38 def get_catalog(self): 

39 return self.catalog 

40 

41 def get_psf_image(self, source): 

42 bbox = source.getFootprint().getBBox() 

43 center = bbox.getCenter() 

44 return self.exposure.getPsf().computeKernelImage(center).array 

45 

46 

47CoaddPsfFitBaseTemplates = { 

48 "name_coadd": "deep", 

49 "name_output_method": "multiprofit", 

50} 

51 

52 

53class CoaddPsfFitConnections( 

54 pipeBase.PipelineTaskConnections, 

55 dimensions=("tract", "patch", "skymap"), 

56 defaultTemplates=CoaddPsfFitBaseTemplates, 

57): 

58 coadd = cT.Input( 

59 doc="Coadd image to fit a PSF model to", 

60 name="{name_coadd}Coadd_calexp", 

61 storageClass="ExposureF", 

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

63 ) 

64 cat_meas = cT.Input( 

65 doc="Deblended single-band source catalog", 

66 name="{name_coadd}Coadd_meas", 

67 storageClass="SourceCatalog", 

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

69 ) 

70 cat_output = cT.Output( 

71 doc="Output PSF fit parameter catalog", 

72 name="{name_coadd}Coadd_psfs_{name_output_method}", 

73 storageClass="ArrowTable", 

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

75 ) 

76 

77 

78class CoaddPsfFitSubConfig(pexConfig.Config): 

79 """Base config class for the CoaddPsfFitTask. 

80 

81 Implementing classes may add any necessary attributes. 

82 """ 

83 

84 

85class CoaddPsfFitSubTask(pipeBase.Task, ABC): 

86 """Interface for CoaddPsfFitTask subtasks to fit PSFs. 

87 

88 Parameters 

89 ---------- 

90 **kwargs 

91 Additional arguments to be passed to the `lsst.pipe.base.Task` 

92 constructor. 

93 """ 

94 ConfigClass = CoaddPsfFitSubConfig 

95 

96 def __init__(self, **kwargs): 

97 super().__init__(**kwargs) 

98 

99 @abstractmethod 

100 def run( 

101 self, catexp: CatalogExposurePsf 

102 ) -> pipeBase.Struct: 

103 """Fit PSF images at locations of sources in a single exposure. 

104 

105 Parameters 

106 ---------- 

107 catexp : `CatalogExposurePsf` 

108 An exposure to fit a model PSF at the position of all 

109 sources in the corresponding catalog. 

110 

111 Returns 

112 ------- 

113 retStruct : `lsst.pipe.base.Struct` 

114 A struct with a cat_output attribute containing the output 

115 measurement catalog. 

116 

117 Notes 

118 ----- 

119 Subclasses may have further requirements on the input parameters, 

120 including: 

121 - Passing only one catexp per band; 

122 - Catalogs containing HeavyFootprints with deblended images; 

123 - Fitting only a subset of the sources. 

124 If any requirements are not met, the subtask should fail as soon as 

125 possible. 

126 """ 

127 raise NotImplementedError() 

128 

129 

130class CoaddPsfFitConfig( 

131 pipeBase.PipelineTaskConfig, 

132 pipelineConnections=CoaddPsfFitConnections, 

133): 

134 """Configure a CoaddPsfFitTask, including a configurable fitting subtask. 

135 """ 

136 fit_coadd_psf = pexConfig.ConfigurableField( 

137 target=CoaddPsfFitSubTask, 

138 doc="Task to fit PSF models for a single coadd", 

139 ) 

140 

141 

142class CoaddPsfFitTask(pipeBase.PipelineTask): 

143 """Fit a PSF model at the location of sources in a coadd. 

144 

145 This task is intended to fit only a single PSF model at the 

146 centroid of all of the sources in a single coadd exposure. 

147 Subtasks may choose to filter which sources they fit, 

148 and may output whatever columns they desire in addition to 

149 the minimum of 'id'. 

150 """ 

151 ConfigClass = CoaddPsfFitConfig 

152 _DefaultName = "CoaddPsfFit" 

153 

154 def __init__(self, initInputs, **kwargs): 

155 super().__init__(initInputs=initInputs, **kwargs) 

156 self.makeSubtask("fit_coadd_psf") 

157 

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

159 inputs = butlerQC.get(inputRefs) 

160 id_tp = ExposureIdInfo.fromDataId(butlerQC.quantum.dataId, "tract_patch").expId 

161 dataId = inputRefs.cat_meas.dataId 

162 for dataRef in (inputRefs.coadd,): 

163 if dataRef.dataId != dataId: 

164 raise RuntimeError(f'{dataRef=}.dataId != {inputRefs.cat_meas.dataId=}') 

165 

166 catexp = CatalogExposurePsf( 

167 catalog=inputs['cat_meas'], exposure=inputs['coadd'], dataId=dataId, id_tract_patch=id_tp, 

168 ) 

169 outputs = self.run(catexp=catexp) 

170 butlerQC.put(outputs, outputRefs) 

171 

172 def run(self, catexp: CatalogExposurePsf) -> pipeBase.Struct: 

173 """Fit a PSF model at the location of sources in a coadd. 

174 

175 Parameters 

176 ---------- 

177 catexp : `typing.List [CatalogExposurePsf]` 

178 A list of catalog-exposure pairs in a given band. 

179 

180 Returns 

181 ------- 

182 retStruct : `lsst.pipe.base.Struct` 

183 A struct with a cat_output attribute containing the output 

184 measurement catalog. 

185 

186 Notes 

187 ----- 

188 Subtasks may have further requirements; see `CoaddPsfFitSubTask.run`. 

189 """ 

190 cat_output = self.fit_coadd_psf.run(catexp).output 

191 retStruct = pipeBase.Struct(cat_output=cat_output) 

192 return retStruct