Coverage for python/lsst/ap/association/metrics.py : 44%

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#
23__all__ = ["NumberNewDiaObjectsMetricTask",
24 "NumberUnassociatedDiaObjectsMetricTask",
25 "FractionUpdatedDiaObjectsMetricTask",
26 "TotalUnassociatedDiaObjectsMetricTask",
27 ]
30import astropy.units as u
32from lsst.verify import Measurement
33from lsst.verify.gen2tasks import register
34from lsst.verify.tasks import MetadataMetricTask, MetadataMetricConfig, \
35 ApdbMetricTask, ApdbMetricConfig, MetricComputationError
38class NumberNewDiaObjectsMetricConfig(MetadataMetricConfig):
39 def setDefaults(self):
40 self.connections.package = "ap_association"
41 self.connections.metric = "numNewDiaObjects"
44@register("numNewDiaObjects")
45class NumberNewDiaObjectsMetricTask(MetadataMetricTask):
46 """Task that computes the number of DIASources that create new DIAObjects
47 in an image, visit, etc..
48 """
49 _DefaultName = "numNewDiaObjects"
50 ConfigClass = NumberNewDiaObjectsMetricConfig
52 def makeMeasurement(self, values):
53 """Compute the number of new DIAObjects.
55 Parameters
56 ----------
57 values : `dict` [`str`, `int` or `None`]
58 A `dict` representation of the metadata. Each `dict` has the
59 following key:
61 ``"newObjects"``
62 The number of new objects created for this image (`int`
63 or `None`). May be `None` if the image was not successfully
64 associated.
66 Returns
67 -------
68 measurement : `lsst.verify.Measurement` or `None`
69 The total number of new objects.
70 """
71 if values["newObjects"] is not None:
72 try:
73 nNew = int(values["newObjects"])
74 except (ValueError, TypeError) as e:
75 raise MetricComputationError("Corrupted value of numNewDiaObjects") from e
76 else:
77 return Measurement(self.config.metricName, nNew * u.count)
78 else:
79 self.log.info("Nothing to do: no association results found.")
80 return None
82 @classmethod
83 def getInputMetadataKeys(cls, config):
84 return {"newObjects": ".numNewDiaObjects"}
87class NumberUnassociatedDiaObjectsMetricConfig(MetadataMetricConfig):
88 def setDefaults(self):
89 self.connections.package = "ap_association"
90 self.connections.metric = "numUnassociatedDiaObjects"
93@register("numUnassociatedDiaObjects")
94class NumberUnassociatedDiaObjectsMetricTask(MetadataMetricTask):
95 """Task that computes the number of previously-known DIAObjects that do
96 not have detected DIASources in an image, visit, etc..
97 """
98 _DefaultName = "numUnassociatedDiaObjects"
99 ConfigClass = NumberUnassociatedDiaObjectsMetricConfig
101 def makeMeasurement(self, values):
102 """Compute the number of non-updated DIAObjects.
104 Parameters
105 ----------
106 values : `dict` [`str`, `int` or `None`]
107 A `dict` representation of the metadata. Each `dict` has the
108 following key:
110 ``"unassociatedObjects"``
111 The number of DIAObjects not associated with a DiaSource in
112 this image (`int` or `None`). May be `None` if the image was
113 not successfully associated.
115 Returns
116 -------
117 measurement : `lsst.verify.Measurement` or `None`
118 The total number of unassociated objects.
119 """
120 if values["unassociatedObjects"] is not None:
121 try:
122 nNew = int(values["unassociatedObjects"])
123 except (ValueError, TypeError) as e:
124 raise MetricComputationError("Corrupted value of numUnassociatedDiaObjects") from e
125 else:
126 return Measurement(self.config.metricName, nNew * u.count)
127 else:
128 self.log.info("Nothing to do: no association results found.")
129 return None
131 @classmethod
132 def getInputMetadataKeys(cls, config):
133 return {"unassociatedObjects": ".numUnassociatedDiaObjects"}
136class FractionUpdatedDiaObjectsMetricConfig(MetadataMetricConfig):
137 def setDefaults(self):
138 self.connections.package = "ap_association"
139 self.connections.metric = "fracUpdatedDiaObjects"
142@register("fracUpdatedDiaObjects")
143class FractionUpdatedDiaObjectsMetricTask(MetadataMetricTask):
144 """Task that computes the fraction of previously created DIAObjects that
145 have a new association in this image, visit, etc..
146 """
147 _DefaultName = "fracUpdatedDiaObjects"
148 ConfigClass = FractionUpdatedDiaObjectsMetricConfig
150 def makeMeasurement(self, values):
151 """Compute the number of non-updated DIAObjects.
153 AssociationTask reports each pre-existing DIAObject as either updated
154 (associated with a new DIASource) or unassociated.
156 Parameters
157 ----------
158 values : `dict` [`str`, `int` or `None`]
159 A `dict` representation of the metadata. Each `dict` has the
160 following keys:
162 ``"updatedObjects"``
163 The number of DIAObjects updated for this image (`int` or
164 `None`). May be `None` if the image was not
165 successfully associated.
166 ``"unassociatedObjects"``
167 The number of DIAObjects not associated with a DiaSource in
168 this image (`int` or `None`). May be `None` if the image was
169 not successfully associated.
171 Returns
172 -------
173 measurement : `lsst.verify.Measurement` or `None`
174 The total number of unassociated objects.
175 """
176 if values["updatedObjects"] is not None \
177 and values["unassociatedObjects"] is not None:
178 try:
179 nUpdated = int(values["updatedObjects"])
180 nUnassociated = int(values["unassociatedObjects"])
181 except (ValueError, TypeError) as e:
182 raise MetricComputationError("Corrupted value of numUpdatedDiaObjects "
183 "or numUnassociatedDiaObjects") from e
184 else:
185 if nUpdated <= 0 and nUnassociated <= 0:
186 return None # No pre-existing DIAObjects; no fraction to compute
187 else:
188 fraction = nUpdated / (nUpdated + nUnassociated)
189 return Measurement(self.config.metricName, fraction * u.dimensionless_unscaled)
190 else:
191 self.log.info("Nothing to do: no association results found.")
192 return None
194 @classmethod
195 def getInputMetadataKeys(cls, config):
196 return {"updatedObjects": ".numUpdatedDiaObjects",
197 "unassociatedObjects": ".numUnassociatedDiaObjects"}
200class TotalUnassociatedDiaObjectsMetricConfig(ApdbMetricConfig):
201 def setDefaults(self):
202 self.connections.package = "ap_association"
203 self.connections.metric = "totalUnassociatedDiaObjects"
206@register("totalUnassociatedDiaObjects")
207class TotalUnassociatedDiaObjectsMetricTask(ApdbMetricTask):
208 """Task that computes the number of DIAObjects with only one
209 associated DIASource.
210 """
211 _DefaultName = "totalUnassociatedDiaObjects"
212 ConfigClass = TotalUnassociatedDiaObjectsMetricConfig
214 def makeMeasurement(self, dbHandle, outputDataId):
215 """Compute the number of unassociated DIAObjects.
217 Parameters
218 ----------
219 dbHandle : `lsst.dax.apdb.Apdb`
220 A database instance.
221 outputDataId : any data ID type
222 The subset of the database to which this measurement applies.
223 Must be empty, as the number of unassociated sources is
224 ill-defined for subsets of the dataset.
226 Returns
227 -------
228 measurement : `lsst.verify.Measurement`
229 The total number of unassociated objects.
231 Raises
232 ------
233 MetricComputationError
234 Raised on any failure to query the database.
235 ValueError
236 Raised if outputDataId is not empty
237 """
238 # All data ID types define keys()
239 if outputDataId.keys() - {'instrument'}:
240 raise ValueError("%s must not be associated with specific data IDs (gave %s)."
241 % (self.config.metricName, outputDataId))
243 try:
244 nUnassociatedDiaObjects = dbHandle.countUnassociatedObjects()
245 except Exception as e:
246 raise MetricComputationError("Could not get unassociated objects from database") from e
248 meas = Measurement(self.config.metricName, nUnassociatedDiaObjects * u.count)
249 return meas