Coverage for tests/test_cModel.py: 24%
102 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-27 02:35 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-27 02:35 -0800
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
26import lsst.utils.tests
27import lsst.shapelet
28import lsst.afw.geom
29import lsst.geom
30import lsst.afw.image
31import lsst.log
32import lsst.utils.logging
33import lsst.meas.modelfit
34import lsst.meas.base
36# Set trace to 0-5 to view debug messages. Level 5 enables all traces.
37lsst.utils.logging.trace_set_at("lsst.meas.modelfit.optimizer.Optimizer", -1)
38lsst.utils.logging.trace_set_at("lsst.meas.modelfit.optimizer.solveTrustRegion", -1)
41def makeMultiShapeletCircularGaussian(sigma):
42 s = lsst.shapelet.ShapeletFunction(0, lsst.shapelet.HERMITE, sigma)
43 s.getCoefficients()[0] = 1.0 / lsst.shapelet.ShapeletFunction.FLUX_FACTOR
44 m = lsst.shapelet.MultiShapeletFunction()
45 m.addComponent(s)
46 return m
49def computePsfFlux(centroid, exposure):
50 schema = lsst.afw.table.SourceTable.makeMinimalSchema()
51 pointKey = lsst.afw.table.Point2DKey.addFields(schema, "centroid", "known input centroid", "pixel")
52 schema.getAliasMap().set("slot_Centroid", "centroid")
53 algorithm = lsst.meas.base.PsfFluxAlgorithm(lsst.meas.base.PsfFluxControl(), "base_PsfFlux", schema)
54 table = lsst.afw.table.SourceTable.make(schema)
55 record = table.makeRecord()
56 record.set(pointKey, centroid)
57 algorithm.measure(record, exposure)
58 return record.get("base_PsfFlux_instFlux"), record.get("base_PsfFlux_instFluxErr")
61class CModelTestCase(lsst.utils.tests.TestCase):
63 def setUp(self):
64 # Setup test data: a single point source, initially with no noise.
65 numpy.random.seed(500)
66 crval = lsst.geom.SpherePoint(45.0, 45.0, lsst.geom.degrees)
67 crpix = lsst.geom.Point2D(0.0, 0.0)
68 scale = 0.2 * lsst.geom.arcseconds
69 cdMatrix = lsst.afw.geom.makeCdMatrix(scale=scale, flipX=True)
70 dataWcs = lsst.afw.geom.makeSkyWcs(crpix=crpix, crval=crval, cdMatrix=cdMatrix)
71 photoCalib = lsst.afw.image.PhotoCalib(4.0)
72 self.xyPosition = lsst.geom.Point2D(1.1, -0.8)
73 bbox = lsst.geom.Box2I(lsst.geom.Point2I(-100, -100), lsst.geom.Point2I(100, 100))
74 self.exposure = lsst.afw.image.ExposureF(bbox)
75 self.exposure.setWcs(dataWcs)
76 self.exposure.setPhotoCalib(photoCalib)
77 self.trueFlux = 65.0
78 self.psfSigma = 2.0
79 psf = lsst.afw.detection.GaussianPsf(25, 25, self.psfSigma)
80 self.exposure.setPsf(psf)
81 psfImage = psf.computeImage(self.xyPosition)
82 psfImage.getArray()[:, :] *= self.trueFlux
83 psfBBox = psfImage.getBBox(lsst.afw.image.PARENT)
84 subImage = lsst.afw.image.ImageF(self.exposure.getMaskedImage().getImage(), psfBBox,
85 lsst.afw.image.PARENT)
86 subImage.getArray()[:, :] = psfImage.getArray()
88 def tearDown(self):
89 del self.xyPosition
90 del self.exposure
91 del self.trueFlux
92 del self.psfSigma
94 def testNoNoise(self):
95 """Test that CModelAlgorithm.apply() works when applied to a postage-stamp
96 containing only a point source with no noise.
98 We still have to pretend there is noise (i.e. have nonzero values in
99 the variance plane) to allow it to compute a likelihood, though.
100 """
101 ctrl = lsst.meas.modelfit.CModelControl()
102 ctrl.initial.usePixelWeights = False
103 algorithm = lsst.meas.modelfit.CModelAlgorithm(ctrl)
104 var = 1E-16
105 self.exposure.getMaskedImage().getVariance().getArray()[:, :] = var
106 psfImage = self.exposure.getPsf().computeKernelImage(self.xyPosition).getArray()
107 expectedFluxErr = var**0.5 * (psfImage**2).sum()**(-0.5)
108 pos = self.exposure.getPsf().getAveragePosition()
109 result = algorithm.apply(
110 self.exposure, makeMultiShapeletCircularGaussian(self.psfSigma),
111 self.xyPosition, self.exposure.getPsf().computeShape(pos)
112 )
113 self.assertFalse(result.initial.flags[result.FAILED])
114 self.assertFloatsAlmostEqual(result.initial.instFlux, self.trueFlux, rtol=0.01)
115 self.assertFloatsAlmostEqual(result.initial.instFluxErr, expectedFluxErr, rtol=0.01)
116 self.assertLess(result.initial.ellipse.getDeterminantRadius(), 0.2)
117 self.assertFalse(result.exp.flags[result.FAILED])
118 self.assertFloatsAlmostEqual(result.exp.instFlux, self.trueFlux, rtol=0.01)
119 self.assertFloatsAlmostEqual(result.exp.instFluxErr, expectedFluxErr, rtol=0.01)
120 self.assertLess(result.exp.ellipse.getDeterminantRadius(), 0.2)
121 self.assertFalse(result.dev.flags[result.FAILED])
122 self.assertFloatsAlmostEqual(result.dev.instFlux, self.trueFlux, rtol=0.01)
123 self.assertFloatsAlmostEqual(result.dev.instFluxErr, expectedFluxErr, rtol=0.01)
124 self.assertLess(result.dev.ellipse.getDeterminantRadius(), 0.2)
125 self.assertFalse(result.flags[result.FAILED])
126 self.assertFloatsAlmostEqual(result.instFlux, self.trueFlux, rtol=0.01)
128 def testVsPsfFlux(self):
129 """Test that CModel produces results comparable to PsfFlux when run
130 on point sources.
131 """
132 noiseSigma = 1.0
133 for fluxFactor in (1.0, 10.0, 100.0):
134 exposure = self.exposure.Factory(self.exposure, True)
135 exposure.getMaskedImage().getImage().getArray()[:] *= fluxFactor
136 exposure.getMaskedImage().getVariance().getArray()[:] = noiseSigma**2
137 exposure.getMaskedImage().getImage().getArray()[:] += \
138 noiseSigma*numpy.random.randn(exposure.getHeight(), exposure.getWidth())
139 ctrl = lsst.meas.modelfit.CModelControl()
140 algorithm = lsst.meas.modelfit.CModelAlgorithm(ctrl)
141 pos = self.exposure.getPsf().getAveragePosition()
142 cmodel = algorithm.apply(
143 exposure, makeMultiShapeletCircularGaussian(self.psfSigma),
144 self.xyPosition, self.exposure.getPsf().computeShape(pos)
145 )
146 psfFlux, psfFluxErr = computePsfFlux(self.xyPosition, exposure)
147 self.assertFloatsAlmostEqual(psfFlux, cmodel.instFlux, rtol=0.1/fluxFactor**0.5)
148 self.assertFloatsAlmostEqual(psfFluxErr, cmodel.instFluxErr, rtol=0.1/fluxFactor**0.5)
151class TestMemory(lsst.utils.tests.MemoryTestCase):
152 pass
155def setup_module(module):
156 lsst.utils.tests.init()
159if __name__ == "__main__": 159 ↛ 160line 159 didn't jump to line 160, because the condition on line 159 was never true
160 lsst.utils.tests.init()
161 unittest.main()