Coverage for tests/test_metrics.py: 35%
Shortcuts 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
Shortcuts 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
32import lsst.pipe.base.testUtils
33from lsst.verify import Name
34from lsst.verify.gen2tasks.testUtils import MetricTaskTestCase
35from lsst.verify.tasks import MetricComputationError
36from lsst.verify.tasks.testUtils import MetadataMetricTestCase, ApdbMetricTestCase
38from lsst.ap.association.metrics import \
39 NumberNewDiaObjectsMetricTask, \
40 NumberUnassociatedDiaObjectsMetricTask, \
41 FractionUpdatedDiaObjectsMetricTask, \
42 TotalUnassociatedDiaObjectsMetricTask
45def _makeAssociationMetadata(numUpdated=27, numNew=4, numUnassociated=15):
46 metadata = PropertySet()
47 metadata.add("association.numUpdatedDiaObjects", numUpdated)
48 metadata.add("association.numNewDiaObjects", numNew)
49 metadata.add("association.numUnassociatedDiaObjects", numUnassociated)
50 return metadata
53class TestNewDiaObjects(MetadataMetricTestCase):
55 @classmethod
56 def makeTask(cls):
57 return NumberNewDiaObjectsMetricTask()
59 def testValid(self):
60 metadata = _makeAssociationMetadata()
61 result = self.task.run(metadata)
62 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
63 meas = result.measurement
65 self.assertEqual(meas.metric_name, Name(metric="ap_association.numNewDiaObjects"))
66 self.assertEqual(meas.quantity, metadata.getAsDouble("association.numNewDiaObjects") * u.count)
68 def testNoNew(self):
69 metadata = _makeAssociationMetadata(numNew=0)
70 result = self.task.run(metadata)
71 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
72 meas = result.measurement
74 self.assertEqual(meas.metric_name, Name(metric="ap_association.numNewDiaObjects"))
75 self.assertEqual(meas.quantity, 0.0 * u.count)
77 def testMissingData(self):
78 result = self.task.run(None)
79 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
80 meas = result.measurement
81 self.assertIsNone(meas)
83 def testAssociationFailed(self):
84 result = self.task.run(PropertySet())
85 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
86 meas = result.measurement
87 self.assertIsNone(meas)
89 def testBadlyTypedKeys(self):
90 metadata = _makeAssociationMetadata()
91 metadata.set("association.numNewDiaObjects", "Ultimate Answer")
93 with self.assertRaises(MetricComputationError):
94 self.task.run(metadata)
97class TestUnassociatedDiaObjects(MetadataMetricTestCase):
99 @classmethod
100 def makeTask(cls):
101 return NumberUnassociatedDiaObjectsMetricTask()
103 def testValid(self):
104 metadata = _makeAssociationMetadata()
105 result = self.task.run(metadata)
106 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
107 meas = result.measurement
109 self.assertEqual(meas.metric_name, Name(metric="ap_association.numUnassociatedDiaObjects"))
110 self.assertEqual(meas.quantity,
111 metadata.getAsDouble("association.numUnassociatedDiaObjects") * u.count)
113 def testAllUpdated(self):
114 metadata = _makeAssociationMetadata(numUnassociated=0)
115 result = self.task.run(metadata)
116 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
117 meas = result.measurement
119 self.assertEqual(meas.metric_name, Name(metric="ap_association.numUnassociatedDiaObjects"))
120 self.assertEqual(meas.quantity, 0.0 * u.count)
122 def testMissingData(self):
123 result = self.task.run(None)
124 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
125 meas = result.measurement
126 self.assertIsNone(meas)
128 def testAssociationFailed(self):
129 result = self.task.run(PropertySet())
130 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
131 meas = result.measurement
132 self.assertIsNone(meas)
134 def testBadlyTypedKeys(self):
135 metadata = _makeAssociationMetadata()
136 metadata.set("association.numUnassociatedDiaObjects", "Ultimate Answer")
138 with self.assertRaises(MetricComputationError):
139 self.task.run(metadata)
142class TestFracUpdatedDiaObjects(MetadataMetricTestCase):
144 @classmethod
145 def makeTask(cls):
146 return FractionUpdatedDiaObjectsMetricTask()
148 def testValid(self):
149 metadata = _makeAssociationMetadata()
150 result = self.task.run(metadata)
151 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
152 meas = result.measurement
154 self.assertEqual(meas.metric_name, Name(metric="ap_association.fracUpdatedDiaObjects"))
155 nUpdated = metadata.getAsDouble("association.numUpdatedDiaObjects")
156 nTotal = metadata.getAsDouble("association.numUnassociatedDiaObjects") + nUpdated
157 self.assertEqual(meas.quantity, nUpdated / nTotal * u.dimensionless_unscaled)
159 def testNoUpdated(self):
160 metadata = _makeAssociationMetadata(numUpdated=0)
161 result = self.task.run(metadata)
162 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
163 meas = result.measurement
165 self.assertEqual(meas.metric_name, Name(metric="ap_association.fracUpdatedDiaObjects"))
166 self.assertEqual(meas.quantity, 0.0 * u.dimensionless_unscaled)
168 def testAllUpdated(self):
169 metadata = _makeAssociationMetadata(numUnassociated=0)
170 result = self.task.run(metadata)
171 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
172 meas = result.measurement
174 self.assertEqual(meas.metric_name, Name(metric="ap_association.fracUpdatedDiaObjects"))
175 self.assertEqual(meas.quantity, 1.0 * u.dimensionless_unscaled)
177 def testNoObjects(self):
178 metadata = _makeAssociationMetadata(numUpdated=0, numUnassociated=0)
179 result = self.task.run(metadata)
180 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
181 meas = result.measurement
183 self.assertIsNone(meas)
185 def testMissingData(self):
186 result = self.task.run(None)
187 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
188 meas = result.measurement
189 self.assertIsNone(meas)
191 def testAssociationFailed(self):
192 result = self.task.run(PropertySet())
193 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
194 meas = result.measurement
195 self.assertIsNone(meas)
197 def testBadlyTypedKeys(self):
198 metadata = _makeAssociationMetadata()
199 metadata.set("association.numUnassociatedDiaObjects", "Ultimate Answer")
201 with self.assertRaises(MetricComputationError):
202 self.task.run(metadata)
205class TestTotalUnassociatedObjects(ApdbMetricTestCase):
207 @staticmethod
208 def _makeApdb(dummy_dbInfo):
209 """Create a dummy apdb.
211 We don't have access to the apdb in the task directly so mocking
212 return values is difficult. We thus make use of the dummy dbInfo
213 that is passed to the init task to pass values to the apdb object
214 instantiated.
215 """
216 apdb = unittest.mock.Mock(Apdb)
217 test_value = dummy_dbInfo["test_value"]
218 apdb.countUnassociatedObjects = unittest.mock.MagicMock(
219 return_value=test_value)
220 return apdb
222 @classmethod
223 def makeTask(cls):
224 class SimpleDbLoader(Task):
225 ConfigClass = Config
227 def run(self, dummy):
228 if dummy is not None:
229 return Struct(apdb=cls._makeApdb(dummy))
230 else:
231 return Struct(apdb=None)
233 config = TotalUnassociatedDiaObjectsMetricTask.ConfigClass()
234 config.dbLoader.retarget(SimpleDbLoader)
235 return TotalUnassociatedDiaObjectsMetricTask(config=config)
237 @classmethod
238 def makeDbInfo(cls):
239 return {"test_value": "whatever"}
241 def setUp(self):
242 super().setUp()
244 def testValid(self):
245 result = self.task.run([{"test_value": 42}])
246 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
247 meas = result.measurement
249 self.assertEqual(meas.metric_name, Name(metric="ap_association.totalUnassociatedDiaObjects"))
250 self.assertEqual(meas.quantity, 42 * u.count)
252 def testAllAssociated(self):
253 result = self.task.run([{"test_value": 0}])
254 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
255 meas = result.measurement
257 self.assertEqual(meas.metric_name, Name(metric="ap_association.totalUnassociatedDiaObjects"))
258 self.assertEqual(meas.quantity, 0.0 * u.count)
260 def testMissingData(self):
261 result = self.task.run(None)
262 lsst.pipe.base.testUtils.assertValidOutput(self.task, result)
263 meas = result.measurement
264 self.assertIsNone(meas)
266 def testFineGrainedMetric(self):
267 with self.assertRaises(ValueError):
268 self.task.run([self.makeDbInfo()], outputDataId={"visit": 42})
271# Hack around unittest's hacky test setup system
272del MetricTaskTestCase
273del MetadataMetricTestCase
274del ApdbMetricTestCase
277class MemoryTester(lsst.utils.tests.MemoryTestCase):
278 pass
281def setup_module(module):
282 lsst.utils.tests.init()
285if __name__ == "__main__": 285 ↛ 286line 285 didn't jump to line 286, because the condition on line 285 was never true
286 lsst.utils.tests.init()
287 unittest.main()