Coverage for tests/test_metrics.py : 32%

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# (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/>.
22import unittest
23import unittest.mock
25import astropy.units as u
27import lsst.utils.tests
28from lsst.pex.config import Config
29from lsst.daf.base import PropertySet
30from lsst.dax.apdb import Apdb
31from lsst.pipe.base import Task, Struct
32from lsst.verify import Name
33from lsst.verify.gen2tasks.testUtils import MetricTaskTestCase
34from lsst.verify.tasks import MetricComputationError
35from lsst.verify.tasks.testUtils import MetadataMetricTestCase, ApdbMetricTestCase
37from lsst.ap.association.metrics import \
38 NumberNewDiaObjectsMetricTask, \
39 NumberUnassociatedDiaObjectsMetricTask, \
40 FractionUpdatedDiaObjectsMetricTask, \
41 TotalUnassociatedDiaObjectsMetricTask
44def _makeAssociationMetadata(numUpdated=27, numNew=4, numUnassociated=15):
45 metadata = PropertySet()
46 metadata.add("association.numUpdatedDiaObjects", numUpdated)
47 metadata.add("association.numNewDiaObjects", numNew)
48 metadata.add("association.numUnassociatedDiaObjects", numUnassociated)
49 return metadata
52class TestNewDiaObjects(MetadataMetricTestCase):
54 @classmethod
55 def makeTask(cls):
56 return NumberNewDiaObjectsMetricTask()
58 def testValid(self):
59 metadata = _makeAssociationMetadata()
60 result = self.task.run(metadata)
61 meas = result.measurement
63 self.assertEqual(meas.metric_name, Name(metric="ap_association.numNewDiaObjects"))
64 self.assertEqual(meas.quantity, metadata.getAsDouble("association.numNewDiaObjects") * u.count)
66 def testNoNew(self):
67 metadata = _makeAssociationMetadata(numNew=0)
68 result = self.task.run(metadata)
69 meas = result.measurement
71 self.assertEqual(meas.metric_name, Name(metric="ap_association.numNewDiaObjects"))
72 self.assertEqual(meas.quantity, 0.0 * u.count)
74 def testMissingData(self):
75 result = self.task.run(None)
76 meas = result.measurement
77 self.assertIsNone(meas)
79 def testAssociationFailed(self):
80 result = self.task.run(PropertySet())
81 meas = result.measurement
82 self.assertIsNone(meas)
84 def testBadlyTypedKeys(self):
85 metadata = _makeAssociationMetadata()
86 metadata.set("association.numNewDiaObjects", "Ultimate Answer")
88 with self.assertRaises(MetricComputationError):
89 self.task.run(metadata)
92class TestUnassociatedDiaObjects(MetadataMetricTestCase):
94 @classmethod
95 def makeTask(cls):
96 return NumberUnassociatedDiaObjectsMetricTask()
98 def testValid(self):
99 metadata = _makeAssociationMetadata()
100 result = self.task.run(metadata)
101 meas = result.measurement
103 self.assertEqual(meas.metric_name, Name(metric="ap_association.numUnassociatedDiaObjects"))
104 self.assertEqual(meas.quantity,
105 metadata.getAsDouble("association.numUnassociatedDiaObjects") * u.count)
107 def testAllUpdated(self):
108 metadata = _makeAssociationMetadata(numUnassociated=0)
109 result = self.task.run(metadata)
110 meas = result.measurement
112 self.assertEqual(meas.metric_name, Name(metric="ap_association.numUnassociatedDiaObjects"))
113 self.assertEqual(meas.quantity, 0.0 * u.count)
115 def testMissingData(self):
116 result = self.task.run(None)
117 meas = result.measurement
118 self.assertIsNone(meas)
120 def testAssociationFailed(self):
121 result = self.task.run(PropertySet())
122 meas = result.measurement
123 self.assertIsNone(meas)
125 def testBadlyTypedKeys(self):
126 metadata = _makeAssociationMetadata()
127 metadata.set("association.numUnassociatedDiaObjects", "Ultimate Answer")
129 with self.assertRaises(MetricComputationError):
130 self.task.run(metadata)
133class TestFracUpdatedDiaObjects(MetadataMetricTestCase):
135 @classmethod
136 def makeTask(cls):
137 return FractionUpdatedDiaObjectsMetricTask()
139 def testValid(self):
140 metadata = _makeAssociationMetadata()
141 result = self.task.run(metadata)
142 meas = result.measurement
144 self.assertEqual(meas.metric_name, Name(metric="ap_association.fracUpdatedDiaObjects"))
145 nUpdated = metadata.getAsDouble("association.numUpdatedDiaObjects")
146 nTotal = metadata.getAsDouble("association.numUnassociatedDiaObjects") + nUpdated
147 self.assertEqual(meas.quantity, nUpdated / nTotal * u.dimensionless_unscaled)
149 def testNoUpdated(self):
150 metadata = _makeAssociationMetadata(numUpdated=0)
151 result = self.task.run(metadata)
152 meas = result.measurement
154 self.assertEqual(meas.metric_name, Name(metric="ap_association.fracUpdatedDiaObjects"))
155 self.assertEqual(meas.quantity, 0.0 * u.dimensionless_unscaled)
157 def testAllUpdated(self):
158 metadata = _makeAssociationMetadata(numUnassociated=0)
159 result = self.task.run(metadata)
160 meas = result.measurement
162 self.assertEqual(meas.metric_name, Name(metric="ap_association.fracUpdatedDiaObjects"))
163 self.assertEqual(meas.quantity, 1.0 * u.dimensionless_unscaled)
165 def testNoObjects(self):
166 metadata = _makeAssociationMetadata(numUpdated=0, numUnassociated=0)
167 result = self.task.run(metadata)
168 meas = result.measurement
170 self.assertIsNone(meas)
172 def testMissingData(self):
173 result = self.task.run(None)
174 meas = result.measurement
175 self.assertIsNone(meas)
177 def testAssociationFailed(self):
178 result = self.task.run(PropertySet())
179 meas = result.measurement
180 self.assertIsNone(meas)
182 def testBadlyTypedKeys(self):
183 metadata = _makeAssociationMetadata()
184 metadata.set("association.numUnassociatedDiaObjects", "Ultimate Answer")
186 with self.assertRaises(MetricComputationError):
187 self.task.run(metadata)
190class TestTotalUnassociatedObjects(ApdbMetricTestCase):
192 @staticmethod
193 def _makeApdb(dummy_dbInfo):
194 """Create a dummy apdb.
196 We don't have access to the apdb in the task directly so mocking
197 return values is difficult. We thus make use of the dummy dbInfo
198 that is passed to the init task to pass values to the apdb object
199 instantiated.
200 """
201 apdb = unittest.mock.Mock(Apdb)
202 test_value = dummy_dbInfo["test_value"]
203 apdb.countUnassociatedObjects = unittest.mock.MagicMock(
204 return_value=test_value)
205 return apdb
207 @classmethod
208 def makeTask(cls):
209 class SimpleDbLoader(Task):
210 ConfigClass = Config
212 def run(self, dummy):
213 if dummy is not None:
214 return Struct(apdb=cls._makeApdb(dummy))
215 else:
216 return Struct(apdb=None)
218 config = TotalUnassociatedDiaObjectsMetricTask.ConfigClass()
219 config.dbLoader.retarget(SimpleDbLoader)
220 return TotalUnassociatedDiaObjectsMetricTask(config=config)
222 @classmethod
223 def makeDbInfo(cls):
224 return {"test_value": "whatever"}
226 def setUp(self):
227 super().setUp()
229 def testValid(self):
230 result = self.task.run([{"test_value": 42}])
231 meas = result.measurement
233 self.assertEqual(meas.metric_name, Name(metric="ap_association.totalUnassociatedDiaObjects"))
234 self.assertEqual(meas.quantity, 42 * u.count)
236 def testAllAssociated(self):
237 result = self.task.run([{"test_value": 0}])
238 meas = result.measurement
240 self.assertEqual(meas.metric_name, Name(metric="ap_association.totalUnassociatedDiaObjects"))
241 self.assertEqual(meas.quantity, 0.0 * u.count)
243 def testMissingData(self):
244 result = self.task.run(None)
245 meas = result.measurement
246 self.assertIsNone(meas)
248 def testFineGrainedMetric(self):
249 with self.assertRaises(ValueError):
250 self.task.run([self.makeDbInfo()], outputDataId={"visit": 42})
253# Hack around unittest's hacky test setup system
254del MetricTaskTestCase
255del MetadataMetricTestCase
256del ApdbMetricTestCase
259class MemoryTester(lsst.utils.tests.MemoryTestCase):
260 pass
263def setup_module(module):
264 lsst.utils.tests.init()
267if __name__ == "__main__": 267 ↛ 268line 267 didn't jump to line 268, because the condition on line 267 was never true
268 lsst.utils.tests.init()
269 unittest.main()