Coverage for tests/test_generalShapeletPsfApproxPlugins.py: 19%
161 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-12 11:12 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-12 11:12 +0000
1#
2# LSST Data Management System
3#
4# Copyright 2008-2016 AURA/LSST.
5#
6# This product includes software developed by the
7# LSST Project (http://www.lsst.org/).
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 LSST License Statement and
20# the GNU General Public License along with this program. If not,
21# see <https://www.lsstcorp.org/LegalNotices/>.
22#
23import unittest
24import numpy
25import os
27import lsst.utils.tests
28import lsst.shapelet
29import lsst.geom
30import lsst.afw.geom.ellipses
31import lsst.afw.table
32import lsst.afw.detection
33import lsst.log
34import lsst.utils.logging
35import lsst.meas.modelfit
36import lsst.meas.base
37import lsst.meas.algorithms
39# Set trace to 0-5 to view debug messages. Level 5 enables all traces.
40lsst.utils.logging.trace_set_at("lsst.meas.modelfit.optimizer.Optimizer", -1)
41lsst.utils.logging.trace_set_at("lsst.meas.modelfit.optimizer.solveTrustRegion", -1)
44class GeneralShapeletPsfApproxPluginsTestCase(lsst.utils.tests.TestCase):
46 def makeBlankConfig(self):
47 config = lsst.meas.base.SingleFrameMeasurementTask.ConfigClass()
48 config.slots.centroid = None
49 config.slots.shape = None
50 config.slots.psfFlux = None
51 config.slots.apFlux = None
52 config.slots.gaussianFlux = None
53 config.slots.modelFlux = None
54 config.slots.calibFlux = None
55 config.doReplaceWithNoise = False
56 return config
58 def setUp(self):
59 numpy.random.seed(500)
60 self.psfSigma = 2.0
61 self.exposure = lsst.afw.image.ExposureF(41, 41)
62 self.psf = lsst.afw.detection.GaussianPsf(19, 19, self.psfSigma)
63 self.schema = lsst.afw.table.SourceTable.makeMinimalSchema()
64 self.centroidKey = lsst.afw.table.Point2DKey.addFields(self.schema, "centroid", "centroid", "pixel")
65 self.schema.getAliasMap().set("slot_Centroid", "centroid")
66 self.psfDir = os.path.join(os.environ["MEAS_MODELFIT_DIR"], "tests", "data", "psfs")
68 def tearDown(self):
69 del self.exposure
70 del self.psf
71 del self.schema
72 del self.centroidKey
73 del self.psfDir
75 def checkResult(self, msf):
76 # Because we're fitting multiple shapelets to a single Gaussian (a single 0th-order shapelet)
77 # we should be able to fit with zero residuals, aside from (single-precision) round-off error.
78 pos = self.exposure.getPsf().getAveragePosition()
79 dataImage = self.exposure.getPsf().computeImage(pos)
80 modelImage = dataImage.Factory(dataImage.getBBox())
81 modelImage.getArray()[:, :] *= -1
82 msf.evaluate().addToImage(modelImage)
83 self.assertFloatsAlmostEqual(dataImage.getArray(), modelImage.getArray(), atol=1E-6,
84 plotOnFailure=False)
86 def testSingleFrame(self):
87 self.exposure.setPsf(self.psf)
88 config = self.makeBlankConfig()
89 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"]
90 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["SingleGaussian"]
91 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema)
92 measCat = lsst.afw.table.SourceCatalog(self.schema)
93 measRecord = measCat.addNew()
94 measRecord.set(self.centroidKey, lsst.geom.Point2D(20.0, 20.0))
95 task.run(measCat, self.exposure)
96 keySingleGaussian = lsst.shapelet.MultiShapeletFunctionKey(
97 self.schema["modelfit"]["GeneralShapeletPsfApprox"]["SingleGaussian"]
98 )
99 msfSingleGaussian = measRecord.get(keySingleGaussian)
100 self.assertEqual(len(msfSingleGaussian.getComponents()), 1)
101 self.checkResult(msfSingleGaussian)
103 def testForced(self):
104 self.exposure.setPsf(self.psf)
105 config = lsst.meas.base.ForcedMeasurementTask.ConfigClass()
106 config.slots.centroid = "base_TransformedCentroid"
107 config.slots.shape = None
108 config.slots.psfFlux = None
109 config.slots.apFlux = None
110 config.slots.gaussianFlux = None
111 config.slots.modelFlux = None
112 config.doReplaceWithNoise = False
113 config.slots.centroid = "base_TransformedCentroid"
114 config.plugins.names = ["base_TransformedCentroid", "modelfit_GeneralShapeletPsfApprox"]
115 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["SingleGaussian"]
116 config.copyColumns = {"id": "objectId", "parent": "parentObjectId"}
117 refCat = lsst.afw.table.SourceCatalog(self.schema)
118 refRecord = refCat.addNew()
119 refRecord.set(self.centroidKey, lsst.geom.Point2D(20.0, 20.0))
120 refWcs = self.exposure.getWcs() # same as measurement Wcs
121 task = lsst.meas.base.ForcedMeasurementTask(config=config, refSchema=self.schema)
122 measCat = task.generateMeasCat(self.exposure, refCat, refWcs)
123 task.run(measCat, self.exposure, refCat, refWcs)
124 measRecord = measCat[0]
125 measSchema = measCat.schema
126 keySingleGaussian = lsst.shapelet.MultiShapeletFunctionKey(
127 measSchema["modelfit"]["GeneralShapeletPsfApprox"]["SingleGaussian"]
128 )
129 msfSingleGaussian = measRecord.get(keySingleGaussian)
130 self.assertEqual(len(msfSingleGaussian.getComponents()), 1)
131 self.checkResult(msfSingleGaussian)
133 def testNanFlag(self):
134 config = self.makeBlankConfig()
135 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"]
136 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"]
137 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema)
138 measCat = lsst.afw.table.SourceCatalog(self.schema)
139 measRecord = measCat.addNew()
140 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits"))
141 psfImage.getArray()[0, 0] = numpy.nan
142 psfImage.setXY0(lsst.geom.Point2I(0, 0))
143 kernel = lsst.afw.math.FixedKernel(psfImage)
144 psf = lsst.meas.algorithms.KernelPsf(kernel)
145 self.exposure.setPsf(psf)
146 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2)
147 measRecord.set(self.centroidKey, center)
148 task.run(measCat, self.exposure)
149 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag"))
150 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan"))
151 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations"))
152 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations"))
153 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception"))
155 def testInnerIterationsFlag(self):
156 config = self.makeBlankConfig()
157 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"]
158 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"]
159 config.plugins["modelfit_GeneralShapeletPsfApprox"].models["Full"].optimizer.maxInnerIterations = 1
160 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema)
161 measCat = lsst.afw.table.SourceCatalog(self.schema)
162 measRecord = measCat.addNew()
163 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits"))
164 psfImage.setXY0(lsst.geom.Point2I(0, 0))
165 kernel = lsst.afw.math.FixedKernel(psfImage)
166 psf = lsst.meas.algorithms.KernelPsf(kernel)
167 self.exposure.setPsf(psf)
168 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2)
169 measRecord.set(self.centroidKey, center)
170 task.run(measCat, self.exposure)
171 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag"))
172 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan"))
173 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations"))
174 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations"))
175 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception"))
177 def testOuterIterationsFlag(self):
178 config = self.makeBlankConfig()
179 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"]
180 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"]
181 config.plugins["modelfit_GeneralShapeletPsfApprox"].models["Full"].optimizer.maxOuterIterations = 1
182 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema)
183 measCat = lsst.afw.table.SourceCatalog(self.schema)
184 measRecord = measCat.addNew()
185 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits"))
186 psfImage.setXY0(lsst.geom.Point2I(0, 0))
187 kernel = lsst.afw.math.FixedKernel(psfImage)
188 psf = lsst.meas.algorithms.KernelPsf(kernel)
189 self.exposure.setPsf(psf)
190 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2)
191 measRecord.set(self.centroidKey, center)
192 task.run(measCat, self.exposure)
193 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag"))
194 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan"))
195 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations"))
196 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations"))
197 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception"))
200class TestMemory(lsst.utils.tests.MemoryTestCase):
201 pass
204def setup_module(module):
205 lsst.utils.tests.init()
208if __name__ == "__main__": 208 ↛ 209line 208 didn't jump to line 209, because the condition on line 208 was never true
209 lsst.utils.tests.init()
210 unittest.main()