Coverage for python/lsst/faro/base/CatalogMeasurementBase.py: 33%

61 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-10-01 02:40 -0700

1# This file is part of faro. 

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 astropy.table import Table, hstack 

22import astropy.units as u 

23 

24import lsst.pipe.base as pipeBase 

25import lsst.pex.config as pexConfig 

26from lsst.verify.tasks import MetricTask, MetricConfig, MetricConnections 

27from lsst.pipe.tasks.loadReferenceCatalog import LoadReferenceCatalogTask 

28import lsst.geom 

29from .BaseSubTasks import NumSourcesTask 

30 

31__all__ = ( 

32 "CatalogMeasurementBaseConnections", 

33 "CatalogMeasurementBaseConfig", 

34 "CatalogMeasurementBaseTask", 

35) 

36 

37 

38class CatalogMeasurementBaseConnections( 

39 MetricConnections, defaultTemplates={"refDataset": ""} 

40): 

41 

42 refCat = pipeBase.connectionTypes.PrerequisiteInput( 

43 doc="Reference catalog", 

44 name="{refDataset}", 

45 storageClass="SimpleCatalog", 

46 dimensions=("skypix",), 

47 deferLoad=True, 

48 multiple=True, 

49 ) 

50 

51 def __init__(self, *, config=None): 

52 super().__init__(config=config) 

53 if config.connections.refDataset == "": 

54 self.prerequisiteInputs.remove("refCat") 

55 

56 

57class CatalogMeasurementBaseConfig( 

58 MetricConfig, pipelineConnections=CatalogMeasurementBaseConnections 

59): 

60 """Configuration for CatalogMeasurementBaseTask.""" 

61 

62 measure = pexConfig.ConfigurableField( 

63 # This task is meant to make measurements of various types. 

64 # The default task is, therefore, a bit of a place holder. 

65 # It is expected that this will be overridden in the pipeline 

66 # definition in most cases. 

67 target=NumSourcesTask, 

68 doc="Measure task", 

69 ) 

70 

71 referenceCatalogLoader = pexConfig.ConfigurableField( 

72 target=LoadReferenceCatalogTask, doc="Reference catalog loader", 

73 ) 

74 

75 requireAstrometry = pexConfig.Field( 

76 doc=("Require that a given catalog have a valid WCS in order to be included in metric " 

77 "measurements?"), 

78 dtype=bool, 

79 default=True, 

80 ) 

81 requirePhotometry = pexConfig.Field( 

82 doc=("Require that a given catalog have a valid photoCalib in order to be included in metric " 

83 "measurements?"), 

84 dtype=bool, 

85 default=True, 

86 ) 

87 

88 def setDefaults(self): 

89 self.referenceCatalogLoader.doApplyColorTerms = False 

90 

91 

92class CatalogMeasurementBaseTask(MetricTask): 

93 """Base class for science performance metrics measured from source/object catalogs.""" 

94 

95 ConfigClass = CatalogMeasurementBaseConfig 

96 _DefaultName = "catalogMeasurementBaseTask" 

97 

98 def __init__(self, config, *args, **kwargs): 

99 super().__init__(*args, config=config, **kwargs) 

100 self.makeSubtask("measure") 

101 

102 def run(self, **kwargs): 

103 if 'shelveName' in self.measure.config.keys(): 

104 if self.measure.config.shelveName: 

105 # Persist in-memory objects for development and testing 

106 self._persistMeasurementInputs(self.measure.config, self.measure.config.shelveName, **kwargs) 

107 return self.measure.run(self.config.connections.metric, **kwargs) 

108 

109 def _getTableColumnsSelectors(self, columns, currentBands=None): 

110 """given a list of selectors return columns required to apply these 

111 selectors. 

112 Parameters 

113 ---------- 

114 columns: `list` [`str`] 

115 a list of columns required to calculate a metric. This list 

116 is appended with any addditional columns required for the selectorActions. 

117 

118 currentBands: `list` [`str`] 

119 The filter band(s) associated with the observations. 

120 

121 Returns 

122 ------- 

123 columnNames: `list` [`str`] the set of columns required to compute a 

124 metric with any addditional columns required for the selectorActions 

125 appended to the set. 

126 

127 """ 

128 columnNames = set(columns) 

129 for actionStruct in [self.config.measure.selectorActions]: 

130 for action in actionStruct: 

131 for col in action.columns(currentBands): 

132 columnNames.add(col) 

133 

134 return columnNames 

135 

136 def _getReferenceCatalog(self, butlerQC, dataIds, refCats, filterList, epoch=None): 

137 """Load reference catalog in sky region of interest and optionally applies proper 

138 motion correction and color terms. 

139 

140 Loads the `lsst.afw.table.SimpleCatalog` reference catalog, computes ra and dec 

141 (optionally) applying a proper motion correction. Also, color terms 

142 are (optionally) applied to the reference magnitudes in order to transform 

143 them to the data's photometric system. 

144 

145 returns a refCat with both the original loaded reference catalog and 

146 the coorected coordinates (ra,dec) and transformed reference magnitudes 

147 (refMag-/refMagErr-) 

148 

149 Parameters 

150 ---------- 

151 butlerQC : `lsst.pipe.base.butlerQuantumContext.ButlerQuantumContext` 

152 Butler quantum context for a Gen3 repository. 

153 dataIds: interable of `lsst.daf.butler.dataId` 

154 An iterable object of dataIds that point to reference catalogs 

155 in a Gen3 repository. 

156 refCats : iterable of `lsst.daf.butler.DeferredDatasetHandle` 

157 An iterable object of dataset refs for reference catalogs in 

158 a Gen3 repository. 

159 filterList : `list` [`str`] 

160 List of camera physicalFilter names to apply color terms. 

161 epoch : `astropy.time.Time`, optional 

162 Epoch to which to correct proper motion and parallax 

163 (if available), or `None` to not apply such corrections. 

164 

165 Returns 

166 ------- 

167 refCat: pandas.dataframe 

168 a reference catalog with original columns and corrected 

169 coordinates (ra,dec) and reference magnitudes (refMag-/refMagErr-) 

170 """ 

171 center = lsst.geom.SpherePoint( 

172 butlerQC.quantum.dataId.region.getBoundingCircle().getCenter() 

173 ) 

174 radius = butlerQC.quantum.dataId.region.getBoundingCircle().getOpeningAngle() 

175 

176 loaderTask = LoadReferenceCatalogTask( 

177 config=self.config.referenceCatalogLoader, dataIds=dataIds, refCats=refCats, 

178 name=self.config.connections.refCat 

179 ) 

180 

181 # Get catalog with proper motion and color terms applied 

182 refCatCorrected = loaderTask.getSkyCircleCatalog( 

183 center, radius, filterList, epoch=epoch 

184 ) 

185 

186 # Get unformatted catalog w/ all columns 

187 skyCircle = loaderTask.refObjLoader.loadSkyCircle( 

188 center, radius, loaderTask._referenceFilter, epoch=epoch 

189 ) 

190 refCat = skyCircle.refCat 

191 

192 refCatTable = Table() 

193 refCatTable['ra'] = refCatCorrected['ra']*u.deg 

194 refCatTable['dec'] = refCatCorrected['dec']*u.deg 

195 for n, filterName in enumerate(filterList): 

196 refCatTable['refMag-' + filterName] = refCatCorrected["refMag"][:, n]*u.ABmag 

197 refCatTable['refMagErr-' + filterName] = refCatCorrected["refMagErr"][:, n]*u.ABmag 

198 refCatFrame = hstack([refCatTable, refCat.asAstropy()]).to_pandas() 

199 

200 return refCatFrame 

201 

202 def _persistMeasurementInputs(self, config, shelveName, **kwargs): 

203 """Persist in-memory objects sent as inputs to metric measurement run method. 

204 

205 This function is intended to be used for development and testing purposes 

206 as a debug tool and is NOT to be used in routine operation. 

207 

208 Parameters 

209 ---------- 

210 config : `lsst.pex.config.Config` 

211 Config to be saved. 

212 shelveName : `str` 

213 Filename for output shelve. 

214 """ 

215 

216 import shelve 

217 

218 with shelve.open(shelveName, 'n') as shelf: 

219 shelf['config'] = config 

220 for key in kwargs.keys(): 

221 shelf[key] = kwargs[key]