Coverage for tests / test_uniform_grid.py: 18%

105 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-17 09:22 +0000

1# This file is part of cell_coadds. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

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 GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21 

22from __future__ import annotations 

23 

24import pickle 

25import unittest 

26 

27import lsst.utils.tests 

28from lsst.cell_coadds import UniformGrid 

29from lsst.geom import Box2I, Extent2I, Point2I 

30from lsst.skymap import Index2D 

31 

32 

33class UniformGridTestCase(unittest.TestCase): 

34 """Tests for UniformGrid and GridIndex/Index2D's C++/Python 

35 translation. 

36 """ 

37 

38 def setUp(self) -> None: # noqa: D102 

39 self.x0 = 1 

40 self.y0 = 2 

41 self.bw = 15 

42 self.bh = 12 

43 self.nx = 5 

44 self.ny = 6 

45 self.cw = 3 

46 self.ch = 2 

47 

48 self.bbox = Box2I(Point2I(x=self.x0, y=self.y0), Extent2I(x=self.bw, y=self.bh)) 

49 self.cell_size = Extent2I(x=self.cw, y=self.ch) 

50 self.shape = Index2D(x=self.nx, y=self.ny) 

51 self.padding = 0 

52 

53 def test_ctor_bbox_cell_size(self) -> None: 

54 """Test UniformGrid after construction with (bbox, cell_size).""" 

55 grid = UniformGrid.from_bbox_cell_size(self.bbox, self.cell_size) 

56 self._check(grid) 

57 

58 def test_ctor_bbox_shape(self) -> None: 

59 """Test UniformGrid after construction with (bbox, shape).""" 

60 grid = UniformGrid.from_bbox_shape(self.bbox, self.shape) 

61 self._check(grid) 

62 

63 def test_ctor_cell_size_shape_min(self) -> None: 

64 """Test UniformGrid after construction with (cell_size, shape, min).""" 

65 grid = UniformGrid(self.cell_size, self.shape, min=self.bbox.getMin()) 

66 self._check(grid) 

67 

68 def _check(self, grid: UniformGrid) -> None: 

69 self.assertEqual(grid.bbox, self.bbox) 

70 self.assertEqual(grid.cell_size, self.cell_size) 

71 self.assertEqual(grid.shape, self.shape) 

72 self.assertEqual(grid.padding, self.padding) 

73 self.assertIsInstance(grid.shape, Index2D) 

74 self.assertEqual(grid.bbox_of(Index2D(x=3, y=4)), Box2I(Point2I(x=10, y=10), self.cell_size)) 

75 index = grid.index(Point2I(x=11, y=9)) 

76 self.assertEqual(index, Index2D(x=3, y=3)) 

77 self.assertIsInstance(index, Index2D) 

78 

79 def test_index(self): 

80 """Test various inputs to UniformGrid.index.""" 

81 grid = UniformGrid.from_bbox_cell_size(self.bbox, self.cell_size) 

82 self.assertEqual(grid.index(self.bbox.getMin()), Index2D(x=0, y=0)) 

83 self.assertEqual(grid.index(self.bbox.getMax()), Index2D(x=4, y=5)) 

84 self.assertEqual(grid.index(Point2I(x=9, y=5)), Index2D(x=2, y=1)) 

85 self.assertEqual(grid.index(Point2I(x=9, y=6)), Index2D(x=2, y=2)) 

86 self.assertEqual(grid.index(Point2I(x=10, y=5)), Index2D(x=3, y=1)) 

87 self.assertEqual(grid.index(Point2I(x=10, y=6)), Index2D(x=3, y=2)) 

88 with self.assertRaises(ValueError): 

89 grid.index(self.bbox.getMin() - Extent2I(x=0, y=1)) 

90 with self.assertRaises(ValueError): 

91 grid.index(self.bbox.getMin() - Extent2I(x=1, y=0)) 

92 with self.assertRaises(ValueError): 

93 grid.index(self.bbox.getMin() - Extent2I(x=1, y=1)) 

94 with self.assertRaises(ValueError): 

95 grid.index(self.bbox.getMax() + Extent2I(x=0, y=1)) 

96 with self.assertRaises(ValueError): 

97 grid.index(self.bbox.getMax() + Extent2I(x=1, y=0)) 

98 with self.assertRaises(ValueError): 

99 grid.index(self.bbox.getMax() + Extent2I(x=1, y=1)) 

100 

101 def test_repr(self): 

102 """Test that UniformGrid.__repr__ round-trips through eval.""" 

103 for grid in ( 

104 UniformGrid.from_bbox_cell_size(self.bbox, self.cell_size), 

105 UniformGrid.from_bbox_shape(self.bbox, self.shape, padding=1), 

106 UniformGrid(self.cell_size, self.shape, min=self.bbox.getMin(), padding=3), 

107 ): 

108 self.assertEqual(eval(repr(grid)), grid, msg=repr(grid)) 

109 

110 @lsst.utils.tests.methodParameters(padding=[0, 3]) 

111 def test_pickle(self, padding: int): 

112 """Test that UniformGrid objects are pickleable.""" 

113 grid1 = UniformGrid.from_bbox_cell_size(self.bbox, self.cell_size, padding=padding) 

114 grid2 = pickle.loads(pickle.dumps(grid1, pickle.HIGHEST_PROTOCOL)) 

115 self.assertIsInstance(grid2, UniformGrid) 

116 self.assertEqual(grid1, grid2) 

117 

118 @lsst.utils.tests.methodParameters(padding=(1, 2, 3, 4, 7, 10)) 

119 def test_padding(self, padding: int): 

120 """Test that bbox_of and index methods work with padding > 0.""" 

121 grid = UniformGrid.from_bbox_cell_size(self.bbox, self.cell_size, padding=padding) 

122 

123 # Test all interior cells 

124 for x in range(1, self.nx - 1): 

125 for y in range(1, self.ny - 1): 

126 bbox = grid.bbox_of(Index2D(x=x, y=y)) 

127 self.assertEqual(bbox.getDimensions(), self.cell_size) 

128 self.assertEqual(bbox.getMin(), Point2I(x=x * self.cw + self.x0, y=y * self.ch + self.y0)) 

129 

130 # Test the four corners 

131 for x in (0, self.nx - 1): 

132 for y in (0, self.ny - 1): 

133 bbox = grid.bbox_of(Index2D(x=x, y=y)) 

134 self.assertEqual( 

135 bbox.getDimensions(), 

136 self.cell_size + Extent2I(padding, padding), 

137 ) 

138 self.assertEqual( 

139 bbox.getMin(), 

140 Point2I( 

141 x=x * self.cw + self.x0 - padding * (x == 0), 

142 y=y * self.ch + self.y0 - padding * (y == 0), 

143 ), 

144 ) 

145 

146 # Test along the two horizontal edges 

147 for x in (0, self.nx - 1): 

148 for y in range(1, self.ny - 1): 

149 bbox = grid.bbox_of(Index2D(x=x, y=y)) 

150 self.assertEqual(bbox.getDimensions(), self.cell_size + Extent2I(padding, 0)) 

151 self.assertEqual( 

152 bbox.getMin(), 

153 Point2I(x=x * self.cw + self.x0 - padding * (x == 0), y=y * self.ch + self.y0), 

154 ) 

155 

156 # Test along the two vertical edges 

157 for x in range(1, self.nx - 1): 

158 for y in (0, self.ny - 1): 

159 bbox = grid.bbox_of(Index2D(x=x, y=y)) 

160 self.assertEqual(bbox.getDimensions(), self.cell_size + Extent2I(0, padding)) 

161 self.assertEqual( 

162 bbox.getMin(), 

163 Point2I(x=x * self.cw + self.x0, y=y * self.ch + self.y0 - padding * (y == 0)), 

164 ) 

165 

166 # Check the mapping between positions and indices 

167 positions_index = ( 

168 # Check the four interior corners 

169 (Point2I(x=self.x0, y=self.y0), Index2D(x=0, y=0)), # Lower-left corner, in the x and y buffer 

170 ( 

171 Point2I(x=self.x0 + self.bw - 1, y=self.y0), 

172 Index2D(x=self.nx - 1, y=0), 

173 ), # Lower-right corner, in the x buffer 

174 ( 

175 Point2I(x=self.x0, y=self.y0 + self.bh - 1), 

176 Index2D(x=0, y=self.ny - 1), 

177 ), # Upper-left corner, in the y buffer 

178 ( 

179 Point2I(x=self.x0 + self.bw - 1, y=self.y0 + self.bh - 1), 

180 Index2D(x=self.nx - 1, y=self.ny - 1), 

181 ), # Upper-right corner, in the x and y buffer 

182 # Check for one cell from the origin in either directions 

183 (Point2I(x=self.x0, y=self.y0 + self.ch), Index2D(x=0, y=1)), # Left edge, in the x buffer 

184 (Point2I(x=self.x0 + self.cw, y=self.y0), Index2D(x=1, y=0)), 

185 # Check the four corners of the lower left buffer region 

186 (Point2I(x=self.x0 - padding, y=self.y0), Index2D(0, 0)), 

187 (Point2I(x=self.x0, y=self.y0 - padding), Index2D(0, 0)), 

188 (Point2I(x=self.x0 - padding, y=self.y0), Index2D(0, 0)), 

189 (Point2I(x=self.x0 - padding, y=self.y0 - padding), Index2D(0, 0)), 

190 # Check the four corners of the lower right buffer region 

191 (Point2I(x=self.x0 + self.bw, y=self.y0), Index2D(self.nx - 1, 0)), 

192 (Point2I(x=self.x0 + self.bw + padding - 1, y=self.y0), Index2D(self.nx - 1, 0)), 

193 (Point2I(x=self.x0 + self.bw + padding - 1, y=self.y0 - padding), Index2D(self.nx - 1, 0)), 

194 (Point2I(x=self.x0 + self.bw, y=self.y0 - padding), Index2D(self.nx - 1, 0)), 

195 # Check the four corners of the upper left buffer region 

196 (Point2I(x=self.x0, y=self.y0 + self.bh), Index2D(0, self.ny - 1)), 

197 (Point2I(x=self.x0, y=self.y0 + self.bh + padding - 1), Index2D(0, self.ny - 1)), 

198 (Point2I(x=self.x0 - padding, y=self.y0 + self.bh + padding - 1), Index2D(0, self.ny - 1)), 

199 (Point2I(x=self.x0 - padding, y=self.y0 + self.bh), Index2D(0, self.ny - 1)), 

200 # Check the four corners of the upper right buffer region 

201 (Point2I(x=self.x0 + self.bw, y=self.y0 + self.bh), Index2D(self.nx - 1, self.ny - 1)), 

202 ( 

203 Point2I(x=self.x0 + self.bw, y=self.y0 + self.bh + padding - 1), 

204 Index2D(self.nx - 1, self.ny - 1), 

205 ), 

206 ( 

207 Point2I(x=self.x0 + self.bw + padding - 1, y=self.y0 + self.bh), 

208 Index2D(self.nx - 1, self.ny - 1), 

209 ), 

210 ( 

211 Point2I(x=self.x0 + self.bw + padding - 1, y=self.y0 + self.bh + padding - 1), 

212 Index2D(self.nx - 1, self.ny - 1), 

213 ), 

214 ) 

215 

216 for position, index in positions_index: 

217 self.assertEqual(grid.index(position), index, msg=f"{position} does not map to {index}") 

218 

219 # Check that positions outside the grid raise an exception 

220 self.assertRaises(ValueError, grid.index, Point2I(x=self.x0 - padding - 1, y=self.y0)) 

221 self.assertRaises(ValueError, grid.index, Point2I(x=self.x0 + self.bw + padding, y=self.y0)) 

222 self.assertRaises(ValueError, grid.index, Point2I(x=self.x0, y=self.y0 - padding - 1)) 

223 self.assertRaises(ValueError, grid.index, Point2I(x=self.x0, y=self.y0 + self.bh + padding)) 

224 

225 

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

227 """Test for memory/resource leaks.""" 

228 

229 

230def setup_module(module): # noqa: D103 

231 lsst.utils.tests.init() 

232 

233 

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

235 lsst.utils.tests.init() 

236 unittest.main()