Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of ap_association. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://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 <http://www.gnu.org/licenses/>. 

21# 

22 

23__all__ = ["NumberNewDiaObjectsMetricTask", 

24 "NumberUnassociatedDiaObjectsMetricTask", 

25 "FractionUpdatedDiaObjectsMetricTask", 

26 "NumberSolarSystemObjectsMetricTask", 

27 "NumberAssociatedSolarSystemObjectsMetricTask", 

28 "TotalUnassociatedDiaObjectsMetricTask", 

29 ] 

30 

31 

32import astropy.units as u 

33 

34from lsst.verify import Measurement 

35from lsst.verify.gen2tasks import register 

36from lsst.verify.tasks import MetadataMetricTask, MetadataMetricConfig, \ 

37 ApdbMetricTask, ApdbMetricConfig, MetricComputationError 

38 

39 

40class NumberNewDiaObjectsMetricConfig(MetadataMetricConfig): 

41 def setDefaults(self): 

42 self.connections.package = "ap_association" 

43 self.connections.metric = "numNewDiaObjects" 

44 

45 

46@register("numNewDiaObjects") 

47class NumberNewDiaObjectsMetricTask(MetadataMetricTask): 

48 """Task that computes the number of DIASources that create new DIAObjects 

49 in an image, visit, etc.. 

50 """ 

51 _DefaultName = "numNewDiaObjects" 

52 ConfigClass = NumberNewDiaObjectsMetricConfig 

53 

54 def makeMeasurement(self, values): 

55 """Compute the number of new DIAObjects. 

56 

57 Parameters 

58 ---------- 

59 values : `dict` [`str`, `int` or `None`] 

60 A `dict` representation of the metadata. Each `dict` has the 

61 following key: 

62 

63 ``"newObjects"`` 

64 The number of new objects created for this image (`int` 

65 or `None`). May be `None` if the image was not successfully 

66 associated. 

67 

68 Returns 

69 ------- 

70 measurement : `lsst.verify.Measurement` or `None` 

71 The total number of new objects. 

72 """ 

73 if values["newObjects"] is not None: 

74 try: 

75 nNew = int(values["newObjects"]) 

76 except (ValueError, TypeError) as e: 

77 raise MetricComputationError("Corrupted value of numNewDiaObjects") from e 

78 else: 

79 return Measurement(self.config.metricName, nNew * u.count) 

80 else: 

81 self.log.info("Nothing to do: no association results found.") 

82 return None 

83 

84 @classmethod 

85 def getInputMetadataKeys(cls, config): 

86 return {"newObjects": ".numNewDiaObjects"} 

87 

88 

89class NumberUnassociatedDiaObjectsMetricConfig(MetadataMetricConfig): 

90 def setDefaults(self): 

91 self.connections.package = "ap_association" 

92 self.connections.metric = "numUnassociatedDiaObjects" 

93 

94 

95@register("numUnassociatedDiaObjects") 

96class NumberUnassociatedDiaObjectsMetricTask(MetadataMetricTask): 

97 """Task that computes the number of previously-known DIAObjects that do 

98 not have detected DIASources in an image, visit, etc.. 

99 """ 

100 _DefaultName = "numUnassociatedDiaObjects" 

101 ConfigClass = NumberUnassociatedDiaObjectsMetricConfig 

102 

103 def makeMeasurement(self, values): 

104 """Compute the number of non-updated DIAObjects. 

105 

106 Parameters 

107 ---------- 

108 values : `dict` [`str`, `int` or `None`] 

109 A `dict` representation of the metadata. Each `dict` has the 

110 following key: 

111 

112 ``"unassociatedObjects"`` 

113 The number of DIAObjects not associated with a DiaSource in 

114 this image (`int` or `None`). May be `None` if the image was 

115 not successfully associated. 

116 

117 Returns 

118 ------- 

119 measurement : `lsst.verify.Measurement` or `None` 

120 The total number of unassociated objects. 

121 """ 

122 if values["unassociatedObjects"] is not None: 

123 try: 

124 nNew = int(values["unassociatedObjects"]) 

125 except (ValueError, TypeError) as e: 

126 raise MetricComputationError("Corrupted value of numUnassociatedDiaObjects") from e 

127 else: 

128 return Measurement(self.config.metricName, nNew * u.count) 

129 else: 

130 self.log.info("Nothing to do: no association results found.") 

131 return None 

132 

133 @classmethod 

134 def getInputMetadataKeys(cls, config): 

135 return {"unassociatedObjects": ".numUnassociatedDiaObjects"} 

136 

137 

138class FractionUpdatedDiaObjectsMetricConfig(MetadataMetricConfig): 

139 def setDefaults(self): 

140 self.connections.package = "ap_association" 

141 self.connections.metric = "fracUpdatedDiaObjects" 

142 

143 

144@register("fracUpdatedDiaObjects") 

145class FractionUpdatedDiaObjectsMetricTask(MetadataMetricTask): 

146 """Task that computes the fraction of previously created DIAObjects that 

147 have a new association in this image, visit, etc.. 

148 """ 

149 _DefaultName = "fracUpdatedDiaObjects" 

150 ConfigClass = FractionUpdatedDiaObjectsMetricConfig 

151 

152 def makeMeasurement(self, values): 

153 """Compute the number of non-updated DIAObjects. 

154 

155 AssociationTask reports each pre-existing DIAObject as either updated 

156 (associated with a new DIASource) or unassociated. 

157 

158 Parameters 

159 ---------- 

160 values : `dict` [`str`, `int` or `None`] 

161 A `dict` representation of the metadata. Each `dict` has the 

162 following keys: 

163 

164 ``"updatedObjects"`` 

165 The number of DIAObjects updated for this image (`int` or 

166 `None`). May be `None` if the image was not 

167 successfully associated. 

168 ``"unassociatedObjects"`` 

169 The number of DIAObjects not associated with a DiaSource in 

170 this image (`int` or `None`). May be `None` if the image was 

171 not successfully associated. 

172 

173 Returns 

174 ------- 

175 measurement : `lsst.verify.Measurement` or `None` 

176 The total number of unassociated objects. 

177 """ 

178 if values["updatedObjects"] is not None \ 

179 and values["unassociatedObjects"] is not None: 

180 try: 

181 nUpdated = int(values["updatedObjects"]) 

182 nUnassociated = int(values["unassociatedObjects"]) 

183 except (ValueError, TypeError) as e: 

184 raise MetricComputationError("Corrupted value of numUpdatedDiaObjects " 

185 "or numUnassociatedDiaObjects") from e 

186 else: 

187 if nUpdated <= 0 and nUnassociated <= 0: 

188 return None # No pre-existing DIAObjects; no fraction to compute 

189 else: 

190 fraction = nUpdated / (nUpdated + nUnassociated) 

191 return Measurement(self.config.metricName, fraction * u.dimensionless_unscaled) 

192 else: 

193 self.log.info("Nothing to do: no association results found.") 

194 return None 

195 

196 @classmethod 

197 def getInputMetadataKeys(cls, config): 

198 return {"updatedObjects": ".numUpdatedDiaObjects", 

199 "unassociatedObjects": ".numUnassociatedDiaObjects"} 

200 

201 

202class NumberSolarSystemObjectsMetricConfig(MetadataMetricConfig): 

203 def setDefaults(self): 

204 self.connections.package = "ap_association" 

205 self.connections.metric = "numTotalSolarSystemObjects" 

206 

207 

208@register("numTotalSolarSystemObjects") 

209class NumberSolarSystemObjectsMetricTask(MetadataMetricTask): 

210 """Task that computes the number of SolarSystemObjects that are 

211 observable within this detectorVisit. 

212 """ 

213 _DefaultName = "numTotalSolarSystemObjects" 

214 ConfigClass = NumberSolarSystemObjectsMetricConfig 

215 

216 def makeMeasurement(self, values): 

217 """Compute the total number of SolarSystemObjects within a 

218 detectorVisit. 

219 

220 Parameters 

221 ---------- 

222 values : `dict` [`str`, `int` or `None`] 

223 A `dict` representation of the metadata. Each `dict` has the 

224 following key: 

225 

226 ``"unassociatedObjects"`` 

227 The number of DIAObjects not associated with a DiaSource in 

228 this image (`int` or `None`). May be `None` if the image was 

229 not successfully associated. 

230 

231 Returns 

232 ------- 

233 measurement : `lsst.verify.Measurement` or `None` 

234 The total number of Solar System objects. 

235 """ 

236 if values["numTotalSolarSystemObjects"] is not None: 

237 try: 

238 nNew = int(values["numTotalSolarSystemObjects"]) 

239 except (ValueError, TypeError) as e: 

240 raise MetricComputationError("Corrupted value of numTotalSolarSystemObjects") from e 

241 else: 

242 return Measurement(self.config.metricName, nNew * u.count) 

243 else: 

244 self.log.info("Nothing to do: no solar system results found.") 

245 return None 

246 

247 @classmethod 

248 def getInputMetadataKeys(cls, config): 

249 return {"numTotalSolarSystemObjects": ".numTotalSolarSystemObjects"} 

250 

251 

252class NumberAssociatedSolarSystemObjectsMetricConfig(MetadataMetricConfig): 

253 def setDefaults(self): 

254 self.connections.package = "ap_association" 

255 self.connections.metric = "numAssociatedSsObjects" 

256 

257 

258@register("numAssociatedSsObjects") 

259class NumberAssociatedSolarSystemObjectsMetricTask(MetadataMetricTask): 

260 """Number of SolarSystemObjects that were associated with new DiaSources 

261 for this detectorVisit. 

262 """ 

263 _DefaultName = "numAssociatedSsObjects" 

264 ConfigClass = NumberAssociatedSolarSystemObjectsMetricConfig 

265 

266 def makeMeasurement(self, values): 

267 """Compute the number of associated SolarSystemObjects. 

268 

269 Parameters 

270 ---------- 

271 values : `dict` [`str`, `int` or `None`] 

272 A `dict` representation of the metadata. Each `dict` has the 

273 following key: 

274 

275 ``"unassociatedObjects"`` 

276 The number of DIAObjects not associated with a DiaSource in 

277 this image (`int` or `None`). May be `None` if the image was 

278 not successfully associated. 

279 

280 Returns 

281 ------- 

282 measurement : `lsst.verify.Measurement` or `None` 

283 The total number of associated SolarSystemObjects. 

284 """ 

285 if values["numAssociatedSsObjects"] is not None: 

286 try: 

287 nNew = int(values["numAssociatedSsObjects"]) 

288 except (ValueError, TypeError) as e: 

289 raise MetricComputationError("Corrupted value of numAssociatedSsObjects") from e 

290 else: 

291 return Measurement(self.config.metricName, nNew * u.count) 

292 else: 

293 self.log.info("Nothing to do: no solar system results found.") 

294 return None 

295 

296 @classmethod 

297 def getInputMetadataKeys(cls, config): 

298 return {"numAssociatedSsObjects": ".numAssociatedSsObjects"} 

299 

300 

301class TotalUnassociatedDiaObjectsMetricConfig(ApdbMetricConfig): 

302 def setDefaults(self): 

303 self.connections.package = "ap_association" 

304 self.connections.metric = "totalUnassociatedDiaObjects" 

305 

306 

307@register("totalUnassociatedDiaObjects") 

308class TotalUnassociatedDiaObjectsMetricTask(ApdbMetricTask): 

309 """Task that computes the number of DIAObjects with only one 

310 associated DIASource. 

311 """ 

312 _DefaultName = "totalUnassociatedDiaObjects" 

313 ConfigClass = TotalUnassociatedDiaObjectsMetricConfig 

314 

315 def makeMeasurement(self, dbHandle, outputDataId): 

316 """Compute the number of unassociated DIAObjects. 

317 

318 Parameters 

319 ---------- 

320 dbHandle : `lsst.dax.apdb.Apdb` 

321 A database instance. 

322 outputDataId : any data ID type 

323 The subset of the database to which this measurement applies. 

324 Must be empty, as the number of unassociated sources is 

325 ill-defined for subsets of the dataset. 

326 

327 Returns 

328 ------- 

329 measurement : `lsst.verify.Measurement` 

330 The total number of unassociated objects. 

331 

332 Raises 

333 ------ 

334 MetricComputationError 

335 Raised on any failure to query the database. 

336 ValueError 

337 Raised if outputDataId is not empty 

338 """ 

339 # All data ID types define keys() 

340 if outputDataId.keys() - {'instrument'}: 

341 raise ValueError("%s must not be associated with specific data IDs (gave %s)." 

342 % (self.config.metricName, outputDataId)) 

343 

344 try: 

345 nUnassociatedDiaObjects = dbHandle.countUnassociatedObjects() 

346 except Exception as e: 

347 raise MetricComputationError("Could not get unassociated objects from database") from e 

348 

349 meas = Measurement(self.config.metricName, nUnassociatedDiaObjects * u.count) 

350 return meas