Coverage for tests/test_projectedLikelihood.py: 18%

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

169 statements  

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 

25 

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 

35 

36 

37ASSERT_CLOSE_KWDS = dict(plotOnFailure=False, printFailures=False) 

38 

39 

40def makeGaussianFunction(ellipse, flux=1.0): 

41 """Create a single-Gaussian MultiShapeletFunction 

42 

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 

52 

53 

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() 

62 

63 

64def scaleExposure(exposure, factor): 

65 mi = exposure.getMaskedImage() 

66 mi *= factor 

67 

68 

69class UnitTransformedLikelihoodTestCase(lsst.utils.tests.TestCase): 

70 

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) 

117 

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 

133 

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) 

142 

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) 

152 

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) 

196 

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) 

223 

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) 

256 

257 

258class TestMemory(lsst.utils.tests.MemoryTestCase): 

259 pass 

260 

261 

262def setup_module(module): 

263 lsst.utils.tests.init() 

264 

265 

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()