Coverage for tests/test_projectedLikelihood.py: 16%
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#
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.tests
28import lsst.geom
29import lsst.afw.geom
30import lsst.afw.geom.ellipses
31import lsst.afw.image
32import lsst.afw.math
33import lsst.afw.detection
34import lsst.meas.modelfit
37ASSERT_CLOSE_KWDS = dict(plotOnFailure=False, printFailures=False)
40def makeGaussianFunction(ellipse, flux=1.0):
41 """Create a single-Gaussian MultiShapeletFunction
43 ellipse may be an afw.geom.ellipses.Ellipse or a float radius for a circle
44 """
45 s = lsst.shapelet.ShapeletFunction(0, lsst.shapelet.HERMITE, ellipse)
46 s.getCoefficients()[0] = 1.0
47 s.normalize()
48 s.getCoefficients()[0] *= flux
49 msf = lsst.shapelet.MultiShapeletFunction()
50 msf.addComponent(s)
51 return msf
54def addGaussian(exposure, ellipse, flux, psf=None):
55 s = makeGaussianFunction(ellipse, flux)
56 if psf is not None:
57 s = s.convolve(psf)
58 imageF = exposure.getMaskedImage().getImage()
59 imageD = lsst.afw.image.ImageD(imageF.getBBox())
60 s.evaluate().addToImage(imageD)
61 imageF += imageD.convertF()
64def scaleExposure(exposure, factor):
65 mi = exposure.getMaskedImage()
66 mi *= factor
69class UnitTransformedLikelihoodTestCase(lsst.utils.tests.TestCase):
71 def setUp(self):
72 numpy.random.seed(500)
73 self.position = lsst.geom.SpherePoint(45.0, 45.0, lsst.geom.degrees)
74 self.model = lsst.meas.modelfit.Model.makeGaussian(lsst.meas.modelfit.Model.FIXED_CENTER)
75 self.ellipse = lsst.afw.geom.ellipses.Ellipse(lsst.afw.geom.ellipses.Axes(6.0, 5.0, numpy.pi/6))
76 self.flux = 50.0
77 ev = self.model.makeEllipseVector()
78 ev[0].setCore(self.ellipse.getCore())
79 ev[0].setCenter(self.ellipse.getCenter())
80 self.nonlinear = numpy.zeros(self.model.getNonlinearDim(), dtype=lsst.meas.modelfit.Scalar)
81 self.fixed = numpy.zeros(self.model.getFixedDim(), dtype=lsst.meas.modelfit.Scalar)
82 self.model.readEllipses(ev, self.nonlinear, self.fixed)
83 self.amplitudes = numpy.zeros(self.model.getAmplitudeDim(), dtype=lsst.meas.modelfit.Scalar)
84 self.amplitudes[:] = self.flux
85 # setup ideal exposure0: uses fit Wcs and PhotoCalib, has delta function PSF
86 scale0 = 0.2*lsst.geom.arcseconds
87 self.crpix0 = lsst.geom.Point2D(0, 0)
88 wcs0 = lsst.afw.geom.makeSkyWcs(crpix=self.crpix0,
89 crval=self.position,
90 cdMatrix=lsst.afw.geom.makeCdMatrix(scale=scale0))
91 photoCalib0 = lsst.afw.image.PhotoCalib(10)
92 self.psf0 = makeGaussianFunction(0.0)
93 self.bbox0 = lsst.geom.Box2I(lsst.geom.Point2I(-100, -100), lsst.geom.Point2I(100, 100))
94 self.spanSet0 = lsst.afw.geom.SpanSet(self.bbox0)
95 self.footprint0 = lsst.afw.detection.Footprint(self.spanSet0)
96 self.exposure0 = lsst.afw.image.ExposureF(self.bbox0)
97 self.exposure0.setWcs(wcs0)
98 self.exposure0.setPhotoCalib(photoCalib0)
99 self.sys0 = lsst.meas.modelfit.UnitSystem(self.exposure0)
100 addGaussian(self.exposure0, self.ellipse, self.flux, psf=self.psf0)
101 self.exposure0.getMaskedImage().getVariance().set(1.0)
102 # setup secondary exposure: 2x pixel scale, 3x gain, Gaussian PSF with sigma=2.5pix
103 scale1 = 0.4 * lsst.geom.arcseconds
104 wcs1 = lsst.afw.geom.makeSkyWcs(crpix=lsst.geom.Point2D(),
105 crval=self.position,
106 cdMatrix=lsst.afw.geom.makeCdMatrix(scale=scale1))
107 photoCalib1 = lsst.afw.image.PhotoCalib(30)
108 self.sys1 = lsst.meas.modelfit.UnitSystem(wcs1, photoCalib1)
109 # transform object that maps between exposures (not including PSF)
110 self.t01 = lsst.meas.modelfit.LocalUnitTransform(self.sys0.wcs.getPixelOrigin(), self.sys0, self.sys1)
111 self.bbox1 = lsst.geom.Box2I(self.bbox0)
112 self.bbox1.grow(-60)
113 self.spanSet1 = lsst.afw.geom.SpanSet(self.bbox1)
114 self.footprint1 = lsst.afw.detection.Footprint(self.spanSet1)
115 self.psfSigma1 = 2.5
116 self.psf1 = makeGaussianFunction(self.psfSigma1)
118 def tearDown(self):
119 del self.position
120 del self.model
121 del self.ellipse
122 del self.bbox0
123 del self.spanSet0
124 del self.footprint0
125 del self.exposure0
126 del self.sys0
127 del self.sys1
128 del self.t01
129 del self.bbox1
130 del self.spanSet1
131 del self.footprint1
132 del self.psf1
134 def checkLikelihood(self, likelihood, data):
135 self.assertFloatsAlmostEqual(likelihood.getData().reshape(data.shape), data, rtol=1E-6,
136 **ASSERT_CLOSE_KWDS)
137 matrix = numpy.zeros((1, likelihood.getDataDim()), dtype=lsst.meas.modelfit.Pixel).transpose()
138 likelihood.computeModelMatrix(matrix, self.nonlinear)
139 model = numpy.dot(matrix, self.amplitudes)
140 self.assertFloatsAlmostEqual(model.reshape(data.shape), data, rtol=1E-6, atol=1E-7,
141 **ASSERT_CLOSE_KWDS)
143 def testModel(self):
144 """Test that when we use a Model to create a MultiShapeletFunction from our parameter vectors
145 it agrees with the reimplementation here."""
146 msf = self.model.makeShapeletFunction(self.nonlinear, self.amplitudes, self.fixed)
147 image0a = lsst.afw.image.ImageD(self.bbox0)
148 msf.evaluate().addToImage(image0a)
149 self.assertFloatsAlmostEqual(image0a.getArray(),
150 self.exposure0.getMaskedImage().getImage().getArray(),
151 rtol=1E-6, atol=1E-7, **ASSERT_CLOSE_KWDS)
153 def testWarp(self):
154 """Test that transforming ellipses and fluxes with LocalUnitTransform agrees with warping
155 """
156 warpCtrl = lsst.afw.math.WarpingControl("lanczos5")
157 # exposure1: check image; just a transform and scaling of exposure0 (no PSF...yet)
158 exposure1 = lsst.afw.image.ExposureF(self.bbox1)
159 addGaussian(exposure1, self.ellipse.transform(self.t01.geometric), self.flux * self.t01.flux)
160 # exposure1a: warp exposure0 using warpExposure with WCS arguments
161 exposure1a = lsst.afw.image.ExposureF(self.bbox1)
162 exposure1a.setWcs(self.sys1.wcs)
163 lsst.afw.math.warpExposure(exposure1a, self.exposure0, warpCtrl)
164 exposure1a.setPhotoCalib(self.sys1.photoCalib)
165 scaleExposure(exposure1a, self.t01.flux)
166 self.assertFloatsAlmostEqual(exposure1.getMaskedImage().getImage().getArray(),
167 exposure1a.getMaskedImage().getImage().getArray(),
168 rtol=1E-6, **ASSERT_CLOSE_KWDS)
169 # exposure1b: warp exposure0 using warpImage with AffineTransform arguments
170 exposure1b = lsst.afw.image.ExposureF(self.bbox1)
171 exposure1b.setWcs(self.sys1.wcs)
172 srcToDest = lsst.afw.geom.makeTransform(self.t01.geometric)
173 lsst.afw.math.warpImage(exposure1b.getMaskedImage(), self.exposure0.getMaskedImage(),
174 srcToDest, warpCtrl)
175 exposure1b.setPhotoCalib(self.sys1.photoCalib)
176 scaleExposure(exposure1b, self.t01.flux)
177 self.assertFloatsAlmostEqual(exposure1.getMaskedImage().getImage().getArray(),
178 exposure1b.getMaskedImage().getImage().getArray(),
179 rtol=1E-6, **ASSERT_CLOSE_KWDS)
180 # now we rebuild exposure1 with the PSF convolution included, and convolve 1a->1c using an
181 # afw::math::Kernel. Since 1a is the same as 1b, there's no need to convolve 1b too.
182 exposure1 = lsst.afw.image.ExposureF(self.bbox1)
183 addGaussian(exposure1, self.ellipse.transform(self.t01.geometric), self.flux * self.t01.flux,
184 psf=self.psf1)
185 kernel = lsst.afw.math.AnalyticKernel(
186 int(self.psfSigma1*16)+1, int(self.psfSigma1*16)+1,
187 lsst.afw.math.GaussianFunction2D(self.psfSigma1, self.psfSigma1)
188 )
189 exposure1c = lsst.afw.image.ExposureF(self.bbox1)
190 ctrl = lsst.afw.math.ConvolutionControl()
191 ctrl.setDoCopyEdge(True)
192 lsst.afw.math.convolve(exposure1c.getMaskedImage(), exposure1a.getMaskedImage(), kernel, ctrl)
193 self.assertFloatsAlmostEqual(exposure1.getMaskedImage().getImage().getArray(),
194 exposure1c.getMaskedImage().getImage().getArray(),
195 rtol=1E-5, atol=1E-6, **ASSERT_CLOSE_KWDS)
197 def testDirect(self):
198 """Test likelihood evaluation when the fit system is the same as the data system.
199 """
200 ctrl = lsst.meas.modelfit.UnitTransformedLikelihoodControl()
201 var = numpy.random.rand(self.bbox0.getHeight(), self.bbox0.getWidth()) + 2.0
202 self.exposure0.getMaskedImage().getVariance().getArray()[:, :] = var
203 efv = [lsst.meas.modelfit.EpochFootprint(self.footprint0, self.exposure0, self.psf0)]
204 # test with per-pixel weights, using both ctors
205 ctrl.usePixelWeights = True
206 data = self.exposure0.getMaskedImage().getImage().getArray() / var**0.5
207 l0a = lsst.meas.modelfit.UnitTransformedLikelihood(self.model, self.fixed, self.sys0, self.position,
208 self.exposure0, self.footprint0, self.psf0, ctrl)
209 self.checkLikelihood(l0a, data)
210 l0b = lsst.meas.modelfit.UnitTransformedLikelihood(self.model, self.fixed, self.sys0, self.position,
211 efv, ctrl)
212 self.checkLikelihood(l0b, data)
213 # test with constant weights, using both ctors
214 ctrl.usePixelWeights = False
215 data = self.exposure0.getMaskedImage().getImage().getArray()
216 l0c = lsst.meas.modelfit.UnitTransformedLikelihood(self.model, self.fixed, self.sys0, self.position,
217 self.exposure0, self.footprint0, self.psf0, ctrl)
218 weights = numpy.exp((-0.5*numpy.log(l0c.getVariance())/l0c.getDataDim()).sum())
219 self.checkLikelihood(l0c, data*weights)
220 l0d = lsst.meas.modelfit.UnitTransformedLikelihood(self.model, self.fixed, self.sys0, self.position,
221 efv, ctrl)
222 self.checkLikelihood(l0d, data*weights)
224 def testProjected(self):
225 """Test likelihood evaluation when the fit system is not the same as the data system.
226 """
227 # Start by building the data exposure
228 exposure1 = lsst.afw.image.ExposureF(self.bbox1)
229 addGaussian(exposure1, self.ellipse.transform(self.t01.geometric), self.flux * self.t01.flux,
230 psf=self.psf1)
231 exposure1.setWcs(self.sys1.wcs)
232 exposure1.setPhotoCalib(self.sys1.photoCalib)
233 var = numpy.random.rand(self.bbox1.getHeight(), self.bbox1.getWidth()) + 2.0
234 exposure1.getMaskedImage().getVariance().getArray()[:, :] = var
235 ctrl = lsst.meas.modelfit.UnitTransformedLikelihoodControl()
236 efv = [lsst.meas.modelfit.EpochFootprint(self.footprint1, exposure1, self.psf1)]
237 # test with per-pixel weights, using both ctors
238 ctrl.usePixelWeights = True
239 data = exposure1.getMaskedImage().getImage().getArray() / var**0.5
240 l1a = lsst.meas.modelfit.UnitTransformedLikelihood(self.model, self.fixed, self.sys0, self.position,
241 exposure1, self.footprint1, self.psf1, ctrl)
242 self.checkLikelihood(l1a, data)
243 l1b = lsst.meas.modelfit.UnitTransformedLikelihood(self.model, self.fixed, self.sys0, self.position,
244 efv, ctrl)
245 self.checkLikelihood(l1b, data)
246 # test with constant weights, using both ctors
247 ctrl.usePixelWeights = False
248 data = exposure1.getMaskedImage().getImage().getArray()
249 l1c = lsst.meas.modelfit.UnitTransformedLikelihood(self.model, self.fixed, self.sys0, self.position,
250 exposure1, self.footprint1, self.psf1, ctrl)
251 weights = numpy.exp((-0.5*numpy.log(l1c.getVariance())/l1c.getDataDim()).sum())
252 self.checkLikelihood(l1c, data*weights)
253 l1d = lsst.meas.modelfit.UnitTransformedLikelihood(self.model, self.fixed, self.sys0, self.position,
254 efv, ctrl)
255 self.checkLikelihood(l1d, data*weights)
258class TestMemory(lsst.utils.tests.MemoryTestCase):
259 pass
262def setup_module(module):
263 lsst.utils.tests.init()
266if __name__ == "__main__": 266 ↛ 267line 266 didn't jump to line 267, because the condition on line 266 was never true
267 lsst.utils.tests.init()
268 unittest.main()