Coverage for tests/test_multiShapelet.py: 13%

125 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-03-10 02:34 -0800

1# 

2# LSST Data Management System 

3# Copyright 2008-2017 LSST Corporation. 

4# 

5# This product includes software developed by the 

6# LSST Project (http://www.lsst.org/). 

7# 

8# This program is free software: you can redistribute it and/or modify 

9# it under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# This program is distributed in the hope that it will be useful, 

14# but WITHOUT ANY WARRANTY; without even the implied warranty of 

15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

19# the GNU General Public License along with this program. If not, 

20# see <http://www.lsstcorp.org/LegalNotices/>. 

21# 

22 

23import pickle 

24import unittest 

25 

26import numpy as np 

27 

28import lsst.utils.tests 

29import lsst.afw.geom.ellipses 

30import lsst.shapelet.tests 

31import lsst.afw.image 

32 

33 

34class MultiShapeletTestCase(lsst.shapelet.tests.ShapeletTestCase): 

35 

36 def setUp(self): 

37 np.random.seed(500) 

38 

39 def testMoments(self): 

40 x = np.linspace(-50, 50, 1001) 

41 y = x 

42 function = self.makeRandomMultiShapeletFunction() 

43 x = np.linspace(-10, 10, 101) 

44 y = x 

45 z = self.makeImage(function, x, y) 

46 self.checkMoments(function, x, y, z) 

47 

48 def testPickle(self): 

49 function1 = self.makeRandomMultiShapeletFunction() 

50 s = pickle.dumps(function1, protocol=2) 

51 function2 = pickle.loads(s) 

52 for component1, component2 in zip(function1.getComponents(), function2.getComponents()): 

53 self.assertEqual(component1.getOrder(), component2.getOrder()) 

54 self.assertEqual(component1.getBasisType(), component2.getBasisType()) 

55 self.assertFloatsAlmostEqual(component1.getEllipse().getParameterVector(), 

56 component2.getEllipse().getParameterVector()) 

57 self.assertFloatsAlmostEqual(component1.getCoefficients(), component2.getCoefficients()) 

58 

59 def testConvolveGaussians(self): 

60 sigma1 = [lsst.afw.geom.ellipses.Quadrupole(6.0, 5.0, 2.0), 

61 lsst.afw.geom.ellipses.Quadrupole(8.0, 10.0, -1.0)] 

62 sigma2 = [lsst.afw.geom.ellipses.Quadrupole(7.0, 12.0, -2.0), 

63 lsst.afw.geom.ellipses.Quadrupole(7.0, 9.0, 1.0)] 

64 alpha1 = [0.6, 0.4] 

65 alpha2 = [0.35, 0.65] 

66 sigma3 = [] 

67 alpha3 = [] 

68 

69 def makeMultiShapeletFunction(alpha, sigma): 

70 msf = lsst.shapelet.MultiShapeletFunction() 

71 for a, s in zip(alpha, sigma): 

72 f = lsst.shapelet.ShapeletFunction(0, lsst.shapelet.HERMITE, 

73 lsst.afw.geom.ellipses.Ellipse(s)) 

74 f.getCoefficients()[0] = a / lsst.shapelet.ShapeletFunction.FLUX_FACTOR 

75 msf.addComponent(f) 

76 return msf 

77 for a1, s1 in zip(alpha1, sigma1): 

78 for a2, s2 in zip(alpha2, sigma2): 

79 sigma3.append(lsst.afw.geom.ellipses.Quadrupole(s1.getIxx() + s2.getIxx(), 

80 s1.getIyy() + s2.getIyy(), 

81 s1.getIxy() + s2.getIxy())) 

82 alpha3.append(a1 * a2) 

83 msf1 = makeMultiShapeletFunction(alpha1, sigma1) 

84 msf2 = makeMultiShapeletFunction(alpha2, sigma2) 

85 msf3a = makeMultiShapeletFunction(alpha3, sigma3) 

86 msf3b = msf1.convolve(msf2) 

87 

88 # Compare the parameters of the MultiShapeletFunctions 

89 self.compareMultiShapeletFunctions(msf3a, msf3b) 

90 

91 # Just to be extra sure, we test that the images are also the same 

92 x = np.linspace(-20, 20, 41) 

93 y = np.linspace(-20, 20, 41) 

94 image3a = self.makeImage(msf3a, x, y) 

95 image3b = self.makeImage(msf3b, x, y) 

96 self.assertFloatsAlmostEqual(image3a, image3b) 

97 

98 # Now we test against two test images: one implemented right here with numpy calls... 

99 xg, yg = np.meshgrid(x, y) 

100 

101 def evalMultiGaussian(alpha, sigma): 

102 matQ = np.array([[sigma.getIxx(), sigma.getIxy()], 

103 [sigma.getIxy(), sigma.getIyy()]], 

104 dtype=float) 

105 invQ = np.linalg.inv(matQ) 

106 norm = alpha / np.linalg.det(2.0 * np.pi * matQ)**0.5 

107 return norm * np.exp(-0.5 * (invQ[0, 0]*xg**2 + 2.0*invQ[0, 1]*xg*yg + invQ[1, 1]*yg**2)) 

108 image3c = np.zeros(xg.shape, dtype=float) 

109 for a, s in zip(alpha3, sigma3): 

110 image3c += evalMultiGaussian(a, s) 

111 self.assertFloatsAlmostEqual(image3c, image3a, rtol=1E-6, relTo=np.max(image3c), 

112 printFailures=True, plotOnFailure=False) 

113 

114 # And the second produced by GalSim 

115 if False: 

116 # Print inputs to screen so we can make a test image with GalSim (see tests/data/generate.py) 

117 # Output can be pasted into that file to generate the check image. 

118 def printForGalSim(alpha, sigma): 

119 print("galsim.Add([") 

120 for a, s in zip(alpha, sigma): 

121 e = lsst.afw.geom.ellipses.Separable[lsst.afw.geom.ellipses.Distortion, 

122 lsst.afw.geom.ellipses.DeterminantRadius](s) 

123 print(" makeGaussian(flux=%f, e1=%8.8f, e2=%8.8f, sigma=%8.8f)," 

124 % (a, e.getE1(), e.getE2(), e.getRadius())) 

125 print("])") 

126 printForGalSim(alpha1, sigma1) 

127 printForGalSim(alpha2, sigma2) 

128 image3d = lsst.afw.image.ImageF("tests/data/gaussians.fits").getArray().astype(float) 

129 self.assertFloatsAlmostEqual(image3d, image3a, rtol=1E-6, relTo=np.max(image3d), 

130 printFailures=True, plotOnFailure=False) 

131 

132 def testBasisNormalize(self): 

133 def makePositiveMatrix(*shape): 

134 """Return a random basis matrix, but with a lot of power 

135 in the zeroth component to ensure the integral is positve.""" 

136 a = np.random.randn(*shape) 

137 a[0, :] += 4.0 

138 return a 

139 basis = lsst.shapelet.MultiShapeletBasis(2) 

140 basis.addComponent(0.5, 1, makePositiveMatrix(3, 2)) 

141 basis.addComponent(1.0, 2, makePositiveMatrix(6, 2)) 

142 basis.addComponent(1.2, 0, makePositiveMatrix(1, 2)) 

143 basis.normalize() 

144 for n in range(2): 

145 coefficients = np.zeros(2, dtype=float) 

146 coefficients[n] = 1.0 

147 msf = basis.makeFunction(lsst.afw.geom.ellipses.Ellipse(lsst.afw.geom.ellipses.Axes()), 

148 coefficients) 

149 self.assertFloatsAlmostEqual(msf.evaluate().integrate(), 1.0) 

150 

151 def testBasisScale(self): 

152 ellipse = lsst.afw.geom.ellipses.Ellipse(lsst.afw.geom.ellipses.Axes()) 

153 basis = lsst.shapelet.MultiShapeletBasis(2) 

154 basis.addComponent(0.5, 1, np.random.randn(3, 2)) 

155 basis.addComponent(1.0, 2, np.random.randn(6, 2)) 

156 basis.addComponent(1.2, 0, np.random.randn(1, 2)) 

157 msf1 = [basis.makeFunction(ellipse, self.makeUnitVector(i, 2)) for i in range(2)] 

158 basis.scale(2.0) 

159 ellipse.getCore().scale(0.5) 

160 msf2 = [basis.makeFunction(ellipse, self.makeUnitVector(i, 2)) for i in range(2)] 

161 for a, b in zip(msf1, msf2): 

162 self.compareMultiShapeletFunctions(a, b) 

163 

164 def testBasisMerge(self): 

165 ellipse = lsst.afw.geom.ellipses.Ellipse(lsst.afw.geom.ellipses.Axes()) 

166 basis1 = lsst.shapelet.MultiShapeletBasis(2) 

167 basis1.addComponent(0.5, 1, np.random.randn(3, 2)) 

168 basis1.addComponent(1.0, 2, np.random.randn(6, 2)) 

169 basis1.addComponent(1.2, 0, np.random.randn(1, 2)) 

170 basis2 = lsst.shapelet.MultiShapeletBasis(3) 

171 basis2.addComponent(0.4, 1, np.random.randn(3, 3)) 

172 basis2.addComponent(1.1, 2, np.random.randn(6, 3)) 

173 basis2.addComponent(1.6, 0, np.random.randn(1, 3)) 

174 basis3 = lsst.shapelet.MultiShapeletBasis(basis1) 

175 basis3.merge(basis2) 

176 self.assertEqual(basis3.getSize(), 5) 

177 msf1 = [basis1.makeFunction(ellipse, self.makeUnitVector(i, 2)) for i in range(2)] 

178 msf2 = [basis2.makeFunction(ellipse, self.makeUnitVector(i, 3)) for i in range(3)] 

179 msf3 = [basis3.makeFunction(ellipse, self.makeUnitVector(i, 5)) for i in range(5)] 

180 for a, b in zip(msf3, msf1+msf2): 

181 self.compareMultiShapeletFunctions(a, b) 

182 

183 

184class MemoryTester(lsst.utils.tests.MemoryTestCase): 

185 pass 

186 

187 

188def setup_module(module): 

189 lsst.utils.tests.init() 

190 

191 

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

193 lsst.utils.tests.init() 

194 unittest.main()