Coverage for tests/test_simpleShape.py: 24%

60 statements  

« prev     ^ index     » next       coverage.py v7.2.5, created at 2023-05-05 03:51 -0700

1# 

2# LSST Data Management System 

3# 

4# Copyright 2008-2017 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 

24 

25import numpy as np 

26 

27import lsst.utils.tests 

28import lsst.geom 

29import lsst.afw.geom.ellipses as el 

30import lsst.afw.image 

31from lsst.meas.extensions.simpleShape import SimpleShape 

32 

33 

34class SimpleShapeTestCase(lsst.utils.tests.TestCase): 

35 

36 def setUp(self): 

37 self.ellipseCores = [ 

38 el.Quadrupole(25.0, 25.0, 0.0), 

39 el.Quadrupole(27.0, 22.0, -5.0), 

40 el.Quadrupole(23.0, 28.0, 2.0), 

41 ] 

42 self.centers = [ 

43 lsst.geom.Point2D(0.0, 0.0), 

44 lsst.geom.Point2D(2.0, 3.0), 

45 lsst.geom.Point2D(-1.0, 2.5), 

46 ] 

47 for ellipseCore in self.ellipseCores: 

48 ellipseCore.scale(2) 

49 self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-500, -500), lsst.geom.Point2I(50, 50)) 

50 self.xg, self.yg = np.meshgrid( 

51 np.arange(self.bbox.getBeginX(), self.bbox.getEndX(), dtype=float), 

52 np.arange(self.bbox.getBeginY(), self.bbox.getEndY(), dtype=float) 

53 ) 

54 

55 def evaluateGaussian(self, ellipse): 

56 ''' 

57 Create an elliptical Guassian as a Numpy array. Does not normalize the Gaussian 

58 ''' 

59 gt = ellipse.getGridTransform() 

60 xt = gt[gt.XX] * self.xg + gt[gt.XY] * self.yg + gt[gt.X] 

61 yt = gt[gt.YX] * self.xg + gt[gt.YY] * self.yg + gt[gt.Y] 

62 return np.exp(-0.5 * (xt**2 + yt**2)) 

63 

64 def buildImageAndMoments(self, dEllipseCore, dCenter, wEllipseCore, wCenter): 

65 ''' 

66 Generates a elliptical Gaussian image from input ellipse (dEllipse) 

67 and uses an elliptical Gaussian (wEllipse) to calculate the shape 

68 of the generated image. 

69 ''' 

70 dEllipse = el.Ellipse(dEllipseCore, dCenter) 

71 image = lsst.afw.image.MaskedImageF(self.bbox) 

72 image.getImage().getArray()[:, :] = self.evaluateGaussian(dEllipse) 

73 wEllipse = el.Ellipse(wEllipseCore, wCenter) 

74 result = SimpleShape.computeMoments(wEllipse, image) 

75 return result 

76 

77 def testCorrectWeightedMoments(self): 

78 ''' 

79 Test that the measured moments can be corrected for the fact that the measurement 

80 contains information on the moments of the weight function used to make the 

81 measurement. The results should only contain the objects shape and not the moments 

82 used to make the measurement. This is a subset of the functionality in testNoNoiseGaussians. 

83 Because the other test tests a broader scope, it is useful to have this test happen under 

84 more restrictive conditions. 

85 ''' 

86 for dEllipseCore in self.ellipseCores: 

87 for dCenter in self.centers: 

88 dEllipse = el.Ellipse(dEllipseCore, dCenter) 

89 dArray = self.evaluateGaussian(dEllipse) 

90 for wEllipseCore in self.ellipseCores: 

91 for wCenter in self.centers: 

92 wEllipse = el.Ellipse(wEllipseCore, wCenter) 

93 wArray = self.evaluateGaussian(wEllipse) 

94 product = dArray * wArray 

95 i0 = np.sum(product) 

96 ix = np.sum(product * self.xg) / i0 

97 iy = np.sum(product * self.yg) / i0 

98 ixx = np.sum(product * (self.xg - ix)**2) / i0 

99 iyy = np.sum(product * (self.yg - iy)**2) / i0 

100 ixy = np.sum(product * (self.xg - ix) * (self.yg - iy)) / i0 

101 mEllipseCore = el.Quadrupole(ixx, iyy, ixy) 

102 mCenter = lsst.geom.Point2D(ix, iy) 

103 SimpleShape.correctWeightedMoments(wEllipseCore, mEllipseCore, mCenter) 

104 self.assertFloatsAlmostEqual(mEllipseCore.getParameterVector(), 

105 dEllipseCore.getParameterVector(), 

106 rtol=1E-8, atol=1E-11) 

107 

108 def testNoNoiseGaussians(self): 

109 ''' 

110 Test that shape moments can be actuately determined for Gaussian images with no noise 

111 ''' 

112 for ellipseCore in self.ellipseCores: 

113 for center in self.centers: 

114 result = self.buildImageAndMoments(ellipseCore, center, ellipseCore, center) 

115 self.assertFloatsAlmostEqual(result.ellipse.getParameterVector(), 

116 ellipseCore.getParameterVector(), 

117 rtol=3E-3, atol=2E-15) 

118 self.assertFloatsAlmostEqual(np.array(result.center), 

119 np.array(center), 

120 rtol=1E-8, atol=2E-15) 

121 

122 

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

124 pass 

125 

126 

127def setup_module(module): 

128 lsst.utils.tests.init() 

129 

130 

131if __name__ == "__main__": 131 ↛ 132line 131 didn't jump to line 132, because the condition on line 131 was never true

132 lsst.utils.tests.init() 

133 unittest.main()