Coverage for tests/test_generalShapeletPsfApproxPlugins.py: 21%
160 statements
« prev ^ index » next coverage.py v6.4.4, created at 2022-09-15 03:27 -0700
« prev ^ index » next coverage.py v6.4.4, created at 2022-09-15 03:27 -0700
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 dataImage = self.exposure.getPsf().computeImage()
79 modelImage = dataImage.Factory(dataImage.getBBox())
80 modelImage.getArray()[:, :] *= -1
81 msf.evaluate().addToImage(modelImage)
82 self.assertFloatsAlmostEqual(dataImage.getArray(), modelImage.getArray(), atol=1E-6,
83 plotOnFailure=False)
85 def testSingleFrame(self):
86 self.exposure.setPsf(self.psf)
87 config = self.makeBlankConfig()
88 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"]
89 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["SingleGaussian"]
90 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema)
91 measCat = lsst.afw.table.SourceCatalog(self.schema)
92 measRecord = measCat.addNew()
93 measRecord.set(self.centroidKey, lsst.geom.Point2D(20.0, 20.0))
94 task.run(measCat, self.exposure)
95 keySingleGaussian = lsst.shapelet.MultiShapeletFunctionKey(
96 self.schema["modelfit"]["GeneralShapeletPsfApprox"]["SingleGaussian"]
97 )
98 msfSingleGaussian = measRecord.get(keySingleGaussian)
99 self.assertEqual(len(msfSingleGaussian.getComponents()), 1)
100 self.checkResult(msfSingleGaussian)
102 def testForced(self):
103 self.exposure.setPsf(self.psf)
104 config = lsst.meas.base.ForcedMeasurementTask.ConfigClass()
105 config.slots.centroid = "base_TransformedCentroid"
106 config.slots.shape = None
107 config.slots.psfFlux = None
108 config.slots.apFlux = None
109 config.slots.gaussianFlux = None
110 config.slots.modelFlux = None
111 config.doReplaceWithNoise = False
112 config.slots.centroid = "base_TransformedCentroid"
113 config.plugins.names = ["base_TransformedCentroid", "modelfit_GeneralShapeletPsfApprox"]
114 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["SingleGaussian"]
115 config.copyColumns = {"id": "objectId", "parent": "parentObjectId"}
116 refCat = lsst.afw.table.SourceCatalog(self.schema)
117 refRecord = refCat.addNew()
118 refRecord.set(self.centroidKey, lsst.geom.Point2D(20.0, 20.0))
119 refWcs = self.exposure.getWcs() # same as measurement Wcs
120 task = lsst.meas.base.ForcedMeasurementTask(config=config, refSchema=self.schema)
121 measCat = task.generateMeasCat(self.exposure, refCat, refWcs)
122 task.run(measCat, self.exposure, refCat, refWcs)
123 measRecord = measCat[0]
124 measSchema = measCat.schema
125 keySingleGaussian = lsst.shapelet.MultiShapeletFunctionKey(
126 measSchema["modelfit"]["GeneralShapeletPsfApprox"]["SingleGaussian"]
127 )
128 msfSingleGaussian = measRecord.get(keySingleGaussian)
129 self.assertEqual(len(msfSingleGaussian.getComponents()), 1)
130 self.checkResult(msfSingleGaussian)
132 def testNanFlag(self):
133 config = self.makeBlankConfig()
134 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"]
135 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"]
136 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema)
137 measCat = lsst.afw.table.SourceCatalog(self.schema)
138 measRecord = measCat.addNew()
139 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits"))
140 psfImage.getArray()[0, 0] = numpy.nan
141 psfImage.setXY0(lsst.geom.Point2I(0, 0))
142 kernel = lsst.afw.math.FixedKernel(psfImage)
143 psf = lsst.meas.algorithms.KernelPsf(kernel)
144 self.exposure.setPsf(psf)
145 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2)
146 measRecord.set(self.centroidKey, center)
147 task.run(measCat, self.exposure)
148 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag"))
149 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan"))
150 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations"))
151 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations"))
152 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception"))
154 def testInnerIterationsFlag(self):
155 config = self.makeBlankConfig()
156 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"]
157 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"]
158 config.plugins["modelfit_GeneralShapeletPsfApprox"].models["Full"].optimizer.maxInnerIterations = 1
159 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema)
160 measCat = lsst.afw.table.SourceCatalog(self.schema)
161 measRecord = measCat.addNew()
162 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits"))
163 psfImage.setXY0(lsst.geom.Point2I(0, 0))
164 kernel = lsst.afw.math.FixedKernel(psfImage)
165 psf = lsst.meas.algorithms.KernelPsf(kernel)
166 self.exposure.setPsf(psf)
167 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2)
168 measRecord.set(self.centroidKey, center)
169 task.run(measCat, self.exposure)
170 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag"))
171 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan"))
172 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations"))
173 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations"))
174 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception"))
176 def testOuterIterationsFlag(self):
177 config = self.makeBlankConfig()
178 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"]
179 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"]
180 config.plugins["modelfit_GeneralShapeletPsfApprox"].models["Full"].optimizer.maxOuterIterations = 1
181 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema)
182 measCat = lsst.afw.table.SourceCatalog(self.schema)
183 measRecord = measCat.addNew()
184 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits"))
185 psfImage.setXY0(lsst.geom.Point2I(0, 0))
186 kernel = lsst.afw.math.FixedKernel(psfImage)
187 psf = lsst.meas.algorithms.KernelPsf(kernel)
188 self.exposure.setPsf(psf)
189 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2)
190 measRecord.set(self.centroidKey, center)
191 task.run(measCat, self.exposure)
192 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag"))
193 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan"))
194 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations"))
195 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations"))
196 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception"))
199class TestMemory(lsst.utils.tests.MemoryTestCase):
200 pass
203def setup_module(module):
204 lsst.utils.tests.init()
207if __name__ == "__main__": 207 ↛ 208line 207 didn't jump to line 208, because the condition on line 207 was never true
208 lsst.utils.tests.init()
209 unittest.main()