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

52 statements  

« prev     ^ index     » next       coverage.py v7.4.3, created at 2024-02-27 14:09 +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.meas.base import SkyMapIdGeneratorConfig 

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", "band", "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 idGenerator = SkyMapIdGeneratorConfig.make_field() 

141 

142 

143class CoaddPsfFitTask(pipeBase.PipelineTask): 

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

145 

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

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

148 Subtasks may choose to filter which sources they fit, 

149 and may output whatever columns they desire in addition to 

150 the minimum of 'id'. 

151 """ 

152 ConfigClass = CoaddPsfFitConfig 

153 _DefaultName = "CoaddPsfFit" 

154 

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

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

157 self.makeSubtask("fit_coadd_psf") 

158 

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

160 inputs = butlerQC.get(inputRefs) 

161 id_tp = self.config.idGenerator.apply(butlerQC.quantum.dataId).catalog_id 

162 dataId = inputRefs.cat_meas.dataId 

163 for dataRef in (inputRefs.coadd,): 

164 if dataRef.dataId != dataId: 

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

166 

167 catexp = CatalogExposurePsf( 

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

169 ) 

170 outputs = self.run(catexp=catexp) 

171 butlerQC.put(outputs, outputRefs) 

172 

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

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

175 

176 Parameters 

177 ---------- 

178 catexp : `typing.List [CatalogExposurePsf]` 

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

180 

181 Returns 

182 ------- 

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

184 A struct with a cat_output attribute containing the output 

185 measurement catalog. 

186 

187 Notes 

188 ----- 

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

190 """ 

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

192 retStruct = pipeBase.Struct(cat_output=cat_output) 

193 return retStruct