Coverage for tests / test_kernelImagesForRegion.py: 16%

139 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-25 01:20 -0700

1# 

2# LSST Data Management System 

3# Copyright 2008, 2009, 2010 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# 

22import math 

23import unittest 

24 

25import numpy as np 

26 

27import lsst.utils.logging 

28import lsst.utils.tests 

29import lsst.geom 

30import lsst.afw.image as afwImage 

31import lsst.afw.math as afwMath 

32import lsst.afw.math.detail as mathDetail 

33 

34# Change integer argument to adjust trace logging. 

35lsst.utils.logging.trace_set_at("lsst.afw.math.convolve", -1) 

36 

37LocNameDict = { 

38 mathDetail.KernelImagesForRegion.BOTTOM_LEFT: "BOTTOM_LEFT", 

39 mathDetail.KernelImagesForRegion.BOTTOM_RIGHT: "BOTTOM_RIGHT", 

40 mathDetail.KernelImagesForRegion.TOP_LEFT: "TOP_LEFT", 

41 mathDetail.KernelImagesForRegion.TOP_RIGHT: "TOP_RIGHT", 

42} 

43 

44NameLocDict = dict((name, loc) for (loc, name) in LocNameDict.items()) 

45 

46 

47class KernelImagesForRegion(lsst.utils.tests.TestCase): 

48 

49 def setUp(self): 

50 boxCorner = lsst.geom.Point2I(11, 50) 

51 boxExtent = lsst.geom.Extent2I(100, 99) 

52 self.bbox = lsst.geom.Box2I(boxCorner, boxExtent) 

53 self.xy0 = lsst.geom.Point2I(100, 251) 

54 self.kernel = self.makeKernel() 

55 

56 def tearDown(self): 

57 self.bbox = None 

58 self.kernel = None 

59 

60 def assertRegionCorrect(self, region): 

61 """Assert that a region has correct corner images 

62 

63 This test is only relevant for operations that try to reuse the image array data 

64 """ 

65 regionCopy = mathDetail.KernelImagesForRegion( 

66 region.getKernel(), region.getBBox(), region.getXY0(), region.getDoNormalize()) 

67 

68 for location in ( 

69 region.BOTTOM_LEFT, 

70 region.BOTTOM_RIGHT, 

71 region.TOP_LEFT, 

72 region.TOP_RIGHT, 

73 ): 

74 actImage = region.getImage(location) 

75 actImArr = actImage.getArray().transpose().copy() 

76 desImage = regionCopy.getImage(location) 

77 desImArr = desImage.getArray().transpose().copy() 

78 actImArr -= desImArr 

79 if not np.allclose(actImArr, 0): 

80 actImage.writeFits(f"actImage{location}.fits") 

81 desImage.writeFits(f"desImage{location}.fits") 

82 self.fail(f"failed on location {location}") 

83 

84 def makeKernel(self): 

85 kCols = 7 

86 kRows = 6 

87 

88 # create spatial model 

89 sFunc = afwMath.PolynomialFunction2D(1) 

90 

91 minSigma = 0.1 

92 maxSigma = 3.0 

93 

94 # spatial parameters are a list of entries, one per kernel parameter; 

95 # each entry is a list of spatial parameters 

96 xSlope = (maxSigma - minSigma) / self.bbox.getWidth() 

97 ySlope = (maxSigma - minSigma) / self.bbox.getHeight() 

98 xOrigin = minSigma - (self.xy0[0] * xSlope) 

99 yOrigin = minSigma - (self.xy0[1] * ySlope) 

100 sParams = ( 

101 (xOrigin, xSlope, 0.0), 

102 (yOrigin, 0.0, ySlope), 

103 (0.0, 0.0, 0.0), 

104 ) 

105 

106 kFunc = afwMath.GaussianFunction2D(1.0, 1.0, 0.0) 

107 kernel = afwMath.AnalyticKernel(kCols, kRows, kFunc, sFunc) 

108 kernel.setSpatialParameters(sParams) 

109 return kernel 

110 

111 def testDoNormalize(self): 

112 """Test getDoNormalize 

113 """ 

114 kernel = self.makeKernel() 

115 for doNormalize in (False, True): 

116 region = mathDetail.KernelImagesForRegion( 

117 kernel, self.bbox, self.xy0, doNormalize) 

118 self.assertEqual(region.getDoNormalize(), doNormalize) 

119 

120 def testGetPixelIndex(self): 

121 """Test getPixelIndex method 

122 """ 

123 region = mathDetail.KernelImagesForRegion( 

124 self.kernel, self.bbox, self.xy0, False) 

125 leftInd = self.bbox.getMinX() 

126 rightInd = self.bbox.getMaxX() + 1 

127 bottomInd = self.bbox.getMinY() 

128 topInd = self.bbox.getMaxY() + 1 

129 int(round((leftInd + rightInd) / 2.0)) 

130 int(round((bottomInd + topInd) / 2.0)) 

131 

132 for location, desIndex in ( 

133 (region.BOTTOM_LEFT, (leftInd, bottomInd)), 

134 (region.BOTTOM_RIGHT, (rightInd, bottomInd)), 

135 (region.TOP_LEFT, (leftInd, topInd)), 

136 (region.TOP_RIGHT, (rightInd, topInd)), 

137 ): 

138 desPixIndex = lsst.geom.Point2I(desIndex[0], desIndex[1]) 

139 self.assertEqual(region.getPixelIndex(location), desPixIndex, 

140 f"getPixelIndex({LocNameDict[location]}) = {region.getPixelIndex(location)} " 

141 f"!= desPixIndex") 

142 

143 def testComputeNextRow(self): 

144 """Test computeNextRow method and the resulting RowOfKernelImagesForRegion 

145 """ 

146 nx = 6 

147 ny = 5 

148 regionRow = mathDetail.RowOfKernelImagesForRegion(nx, ny) 

149 self.assertFalse(regionRow.hasData()) 

150 self.assertFalse(regionRow.isLastRow()) 

151 self.assertEqual(regionRow.getYInd(), -1) 

152 

153 region = mathDetail.KernelImagesForRegion( 

154 self.kernel, self.bbox, self.xy0, False) 

155 floatWidth = self.bbox.getWidth() / float(nx) 

156 validWidths = (int(math.floor(floatWidth)), int(math.ceil(floatWidth))) 

157 floatHeight = self.bbox.getHeight() / float(ny) 

158 validHeights = (int(math.floor(floatHeight)), 

159 int(math.ceil(floatHeight))) 

160 

161 totalHeight = 0 

162 prevBBox = None 

163 prevFirstBBox = None 

164 for yInd in range(ny): 

165 rowWidth = 0 

166 isOK = region.computeNextRow(regionRow) 

167 self.assertTrue(isOK) 

168 self.assertTrue(regionRow.hasData()) 

169 self.assertEqual(regionRow.isLastRow(), (yInd + 1 >= ny)) 

170 self.assertEqual(regionRow.getYInd(), yInd) 

171 firstBBox = regionRow.getRegion(0).getBBox() 

172 self.assertEqual(firstBBox.getMinX(), self.bbox.getMinX()) 

173 if yInd == 0: 

174 self.assertEqual(firstBBox.getMinY(), self.bbox.getMinY()) 

175 firstBBoxHeight = firstBBox.getHeight() 

176 self.assertTrue(firstBBoxHeight in validHeights) 

177 totalHeight += firstBBoxHeight 

178 if yInd > 0: 

179 self.assertEqual(firstBBox.getMinY(), 

180 prevFirstBBox.getMaxY() + 1) 

181 if yInd == ny - 1: 

182 self.assertEqual(firstBBox.getMaxY(), self.bbox.getMaxY()) 

183 prevFirstBBox = firstBBox 

184 for xInd in range(nx): 

185 subregion = regionRow.getRegion(xInd) 

186 try: 

187 self.assertRegionCorrect(subregion) 

188 except Exception: 

189 print(f"failed on xInd={xInd}, yInd={yInd}") 

190 raise 

191 bbox = subregion.getBBox() 

192 rowWidth += bbox.getWidth() 

193 self.assertTrue(bbox.getWidth() in validWidths) 

194 self.assertEqual(bbox.getHeight(), firstBBoxHeight) 

195 if xInd > 0: 

196 self.assertEqual(bbox.getMinX(), prevBBox.getMaxX() + 1) 

197 self.assertEqual(bbox.getMinY(), prevBBox.getMinY()) 

198 self.assertEqual(bbox.getMaxY(), prevBBox.getMaxY()) 

199 if xInd == nx - 1: 

200 self.assertEqual(bbox.getMaxX(), self.bbox.getMaxX()) 

201 prevBBox = bbox 

202 self.assertEqual(rowWidth, self.bbox.getWidth()) 

203 self.assertEqual(totalHeight, self.bbox.getHeight()) 

204 self.assertTrue(not region.computeNextRow(regionRow)) 

205 

206 def testExactImages(self): 

207 """Confirm that kernel image at each location is correct 

208 """ 

209 desImage = afwImage.ImageD(lsst.geom.Extent2I( 

210 self.kernel.getWidth(), self.kernel.getHeight())) 

211 

212 for doNormalize in (False, True): 

213 region = mathDetail.KernelImagesForRegion( 

214 self.kernel, self.bbox, self.xy0, doNormalize) 

215 for location in ( 

216 region.BOTTOM_LEFT, 

217 region.BOTTOM_RIGHT, 

218 region.TOP_LEFT, 

219 region.TOP_RIGHT, 

220 ): 

221 pixelIndex = region.getPixelIndex(location) 

222 xPos = afwImage.indexToPosition(pixelIndex[0] + self.xy0[0]) 

223 yPos = afwImage.indexToPosition(pixelIndex[1] + self.xy0[1]) 

224 self.kernel.computeImage(desImage, doNormalize, xPos, yPos) 

225 

226 actImage = region.getImage(location) 

227 msg = f"exact image({LocNameDict[location]}) incorrect" 

228 self.assertImagesAlmostEqual(actImage, desImage, msg=msg) 

229 

230 

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

232 pass 

233 

234 

235def setup_module(module): 

236 lsst.utils.tests.init() 

237 

238 

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

240 lsst.utils.tests.init() 

241 unittest.main()