Coverage for tests/test_CatalogCalculation.py: 44%
95 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-08 02:11 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-08 02:11 -0700
1# This file is part of meas_base.
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 lsst.utils.tests
25import lsst.meas.base.catalogCalculation as catCalc
26import lsst.afw.table as afwTable
27from lsst.meas.base.pluginRegistry import register
28from lsst.meas.base import MeasurementError
31@register("FailcatalogCalculation")
32class FailCC(catCalc.CatalogCalculationPlugin):
33 """Plugin which is guaranteed to fail, testing the failure framework.
34 """
35 @classmethod
36 def getExecutionOrder(cls):
37 return cls.DEFAULT_CATALOGCALCULATION
39 def __init__(self, config, name, schema, metadata):
40 catCalc.CatalogCalculationPlugin.__init__(self, config, name, schema, metadata)
41 self.failKey = schema.addField(name + "_fail", type="Flag", doc="Failure test")
43 def calculate(self, measRecord):
44 # note: flagbit doesn't matter, since a FlagHandler isn't used
45 raise MeasurementError("Supposed to fail", 0)
47 def fail(self, measRecord, error=None):
48 measRecord.set(self.failKey, True)
51@register("singleRecordCatalogCalculation")
52class SingleRecordCC(catCalc.CatalogCalculationPlugin):
53 """Test plugin which operates on single records.
55 Takes a single record, reads a value, squares it, and writes out the
56 results to the record.
57 """
58 @classmethod
59 def getExecutionOrder(cls):
60 return cls.DEFAULT_CATALOGCALCULATION
62 def __init__(self, config, name, schema, metadata):
63 catCalc.CatalogCalculationPlugin.__init__(self, config, name, schema, metadata)
64 self.failKey = schema.addField(name + "_fail", type="Flag", doc="Failure flag")
65 self.squareKey = schema.addField(name + "_square", type="D", doc="Square of input catalog")
67 def calculate(self, measRecord):
68 value = measRecord.get("start")
69 measRecord.set(self.squareKey, value**2)
71 def fail(self, measRecord, error=None):
72 measRecord.set(self.failKey, True)
75@register("multiRecordCatalogCalculation")
76class MultiRecordAb(catCalc.CatalogCalculationPlugin):
77 """Test plugin which operates on multiple records.
79 This plugin takes the whole source catalog at once, and loops over the
80 catalog internally. The algorithm simply reads a value, cubes it, and
81 writes the results out to the table.
82 """
83 plugType = 'multi'
85 @classmethod
86 def getExecutionOrder(cls):
87 return cls.DEFAULT_CATALOGCALCULATION
89 def __init__(self, config, name, schema, metadata):
90 catCalc.CatalogCalculationPlugin.__init__(self, config, name, schema, metadata)
91 self.failKey = schema.addField(name + "_fail", type="Flag", doc="Failure flag")
92 self.cubeKey = schema.addField(name + "_cube", type="D", doc="Cube of input catalog")
94 def calculate(self, catalog):
95 for rec in catalog:
96 value = rec.get("start")
97 rec.set(self.cubeKey, value**3)
99 def fail(self, catalog, error=None):
100 for rec in catalog:
101 rec.set(self.failKey, True)
104@register("dependentCatalogCalulation")
105class DependentAb(catCalc.CatalogCalculationPlugin):
106 """Test plugin which depends on a previous plugin execution.
108 Used to test runlevel resolution. This plugin takes in single records,
109 reads a value calculated by a previous plugin, computes a square root, and
110 writes the results to the table.
111 """
112 @classmethod
113 def getExecutionOrder(cls):
114 return cls.DEFAULT_CATALOGCALCULATION + 1
116 def __init__(self, config, name, schema, metadata):
117 catCalc.CatalogCalculationPlugin.__init__(self, config, name, schema, metadata)
118 self.failKey = schema.addField(name + "_fail", type="Flag", doc="Failure flag")
119 self.sqrtKey = schema.addField(name + "_sqrt", type="D",
120 doc="Square root of singleRecord catalogCalculation")
122 def calculate(self, measRecord):
123 value = measRecord.get("singleRecordCatalogCalculation_square")
124 measRecord.set(self.sqrtKey, value**0.5)
126 def fail(self, measRecord, error=None):
127 measRecord.set(self.failKey, True)
130class CatalogCalculationTest(unittest.TestCase):
131 """Test the catalogCalculation framework using plugins defined above.
132 """
133 def setUp(self):
134 # Create a schema object, and populate it with a field to simulate
135 # results from measurements on an image
136 schema = afwTable.SourceTable.makeMinimalSchema()
137 schema.addField("start", type="D")
138 # Instantiate a config object adding each of the above plugins, and
139 # use it to create a task
140 catCalcConfig = catCalc.CatalogCalculationConfig()
141 catCalcConfig.plugins.names = ["FailcatalogCalculation", "singleRecordCatalogCalculation",
142 "multiRecordCatalogCalculation", "dependentCatalogCalulation"]
143 catCalcTask = catCalc.CatalogCalculationTask(schema=schema, config=catCalcConfig)
144 # Create a catalog with five sources as input to the task
145 self.catalog = afwTable.SourceCatalog(schema)
146 self.numObjects = 5
147 for i in range(self.numObjects):
148 rec = self.catalog.addNew()
149 rec.set("start", float(i + 1))
151 # Run the catalogCalculation task, outputs will be checked in test
152 # methods
153 catCalcTask.run(self.catalog)
155 def testCatalogCalculation(self):
156 # Verify the failure flag got set for the plugin expected to fail
157 self.assertEqual(len(self.catalog), self.numObjects)
158 for src in self.catalog:
159 self.assertTrue(src.get("FailcatalogCalculation_fail"))
161 # Verify the single record plugin ran successfully
162 for rec in self.catalog:
163 self.assertAlmostEqual(rec.get("start")**2, rec.get("singleRecordCatalogCalculation_square"), 4)
165 # Verify that the system correctly handled a plugin which expects a
166 # full catalog to be passed
167 for rec in self.catalog:
168 self.assertAlmostEqual(rec.get("start")**3, rec.get("multiRecordCatalogCalculation_cube"), 4)
170 # Verify that the system runs plugins in the correct run order
171 for rec in self.catalog:
172 self.assertAlmostEqual(rec.get("start"), rec.get("dependentCatalogCalulation_sqrt"), 4)
174 def tearDown(self):
175 del self.catalog, self.numObjects,
178class TestMemory(lsst.utils.tests.MemoryTestCase):
179 pass
182def setup_module(module):
183 lsst.utils.tests.init()
186if __name__ == "__main__": 186 ↛ 187line 186 didn't jump to line 187, because the condition on line 186 was never true
187 lsst.utils.tests.init()
188 unittest.main()