Coverage for tests/test_methods.py: 7%

229 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-15 02:24 -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 unittest 

23import re 

24 

25import numpy as np 

26 

27import lsst.utils.tests 

28import lsst.daf.base as dafBase 

29import lsst.geom 

30import lsst.afw.geom as afwGeom 

31import lsst.afw.image as afwImage 

32from lsst.afw.image.testUtils import imagesDiffer 

33from lsst.afw.geom.utils import _compareWcsOverBBox 

34 

35 

36class TestTestUtils(lsst.utils.tests.TestCase): 

37 """Test test methods added to lsst.utils.tests.TestCase 

38 """ 

39 def testAssertWcsAlmostEqualOverBBox(self): 

40 """Test assertWcsAlmostEqualOverBBox and wcsAlmostEqualOverBBox""" 

41 bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), 

42 lsst.geom.Extent2I(3001, 3001)) 

43 ctrPix = lsst.geom.Point2I(1500, 1500) 

44 metadata = dafBase.PropertySet() 

45 metadata.set("RADESYS", "FK5") 

46 metadata.set("EQUINOX", 2000.0) 

47 metadata.set("CTYPE1", "RA---TAN") 

48 metadata.set("CTYPE2", "DEC--TAN") 

49 metadata.set("CUNIT1", "deg") 

50 metadata.set("CUNIT2", "deg") 

51 metadata.set("CRVAL1", 215.5) 

52 metadata.set("CRVAL2", 53.0) 

53 metadata.set("CRPIX1", ctrPix[0] + 1) 

54 metadata.set("CRPIX2", ctrPix[1] + 1) 

55 metadata.set("CD1_1", 5.1e-05) 

56 metadata.set("CD1_2", 0.0) 

57 metadata.set("CD2_2", -5.1e-05) 

58 metadata.set("CD2_1", 0.0) 

59 wcs0 = lsst.afw.geom.makeSkyWcs(metadata, strip=False) 

60 metadata.set("CRVAL2", 53.000001) # tweak CRVAL2 for wcs1 

61 wcs1 = lsst.afw.geom.makeSkyWcs(metadata) 

62 

63 self.assertWcsAlmostEqualOverBBox(wcs0, wcs0, bbox, 

64 maxDiffSky=0*lsst.geom.arcseconds, maxDiffPix=0) 

65 self.assertTrue(afwGeom.wcsAlmostEqualOverBBox(wcs0, wcs0, bbox, 

66 maxDiffSky=0*lsst.geom.arcseconds, maxDiffPix=0)) 

67 

68 self.assertWcsAlmostEqualOverBBox(wcs0, wcs1, bbox, 

69 maxDiffSky=0.04*lsst.geom.arcseconds, maxDiffPix=0.02) 

70 self.assertTrue(afwGeom.wcsAlmostEqualOverBBox(wcs0, wcs1, bbox, 

71 maxDiffSky=0.04*lsst.geom.arcseconds, maxDiffPix=0.02)) 

72 

73 with self.assertRaises(AssertionError): 

74 self.assertWcsAlmostEqualOverBBox(wcs0, wcs1, bbox, 

75 maxDiffSky=0.001*lsst.geom.arcseconds, maxDiffPix=0.02) 

76 self.assertFalse(afwGeom.wcsAlmostEqualOverBBox(wcs0, wcs1, bbox, 

77 maxDiffSky=0.001*lsst.geom.arcseconds, 

78 maxDiffPix=0.02)) 

79 

80 with self.assertRaises(AssertionError): 

81 self.assertWcsAlmostEqualOverBBox(wcs0, wcs1, bbox, 

82 maxDiffSky=0.04*lsst.geom.arcseconds, maxDiffPix=0.001) 

83 self.assertFalse(afwGeom.wcsAlmostEqualOverBBox(wcs0, wcs1, bbox, 

84 maxDiffSky=0.04*lsst.geom.arcseconds, 

85 maxDiffPix=0.001)) 

86 

87 # check that doShortCircuit works in the private implementation 

88 errStr1 = _compareWcsOverBBox(wcs0, wcs1, bbox, 

89 maxDiffSky=0.001*lsst.geom.arcseconds, maxDiffPix=0.001, 

90 doShortCircuit=False) 

91 errStr2 = _compareWcsOverBBox(wcs0, wcs1, bbox, 

92 maxDiffSky=0.001*lsst.geom.arcseconds, maxDiffPix=0.001, 

93 doShortCircuit=True) 

94 self.assertNotEqual(errStr1, errStr2) 

95 

96 def checkMaskedImage(self, mi): 

97 """Run assertImage-like function tests on a masked image 

98 

99 Compare the masked image to itself, then alter copies and check that the altered copy 

100 is or is not nearly equal the original, depending on the amount of change, rtol and atol 

101 """ 

102 epsilon = 1e-5 # margin to avoid roundoff error 

103 

104 mi0 = mi.Factory(mi, True) # deep copy 

105 mi1 = mi.Factory(mi, True) 

106 

107 # a masked image should be exactly equal to itself 

108 self.assertMaskedImagesEqual(mi0, mi1) 

109 self.assertMaskedImagesEqual(mi1, mi0) 

110 self.assertMaskedImagesAlmostEqual(mi0, mi1, atol=0, rtol=0) 

111 self.assertMaskedImagesAlmostEqual(mi0, mi1, atol=0, rtol=0) 

112 self.assertMaskedImagesAlmostEqual( 

113 (mi0.image.array, mi0.mask.array, mi0.variance.array), mi1, atol=0, rtol=0) 

114 self.assertMaskedImagesAlmostEqual( 

115 mi0, (mi1.image.array, mi1.mask.array, mi1.variance.array), atol=0, rtol=0) 

116 self.assertMaskedImagesAlmostEqual( 

117 (mi0.image.array, mi0.mask.array, mi0.variance.array), 

118 (mi1.image.array, mi1.mask.array, mi1.variance.array), atol=0, rtol=0) 

119 for getName in ("getImage", "getVariance"): 

120 plane0 = getattr(mi0, getName)() 

121 plane1 = getattr(mi1, getName)() 

122 self.assertImagesEqual(plane0, plane1) 

123 self.assertImagesEqual(plane1, plane0) 

124 self.assertImagesAlmostEqual(plane0, plane1, atol=0, rtol=0) 

125 self.assertImagesAlmostEqual(plane1, plane0, atol=0, rtol=0) 

126 self.assertImagesAlmostEqual( 

127 plane0.getArray(), plane1, atol=0, rtol=0) 

128 self.assertImagesAlmostEqual( 

129 plane0, plane1.getArray(), atol=0, rtol=0) 

130 self.assertImagesAlmostEqual( 

131 plane0.getArray(), plane1.getArray(), atol=0, rtol=0) 

132 self.assertMasksEqual(plane0, plane1) 

133 self.assertMasksEqual(plane1, plane0) 

134 self.assertMasksEqual(plane0.getArray(), plane1) 

135 self.assertMasksEqual(plane0, plane1.getArray()) 

136 self.assertMasksEqual(plane0.getArray(), plane1.getArray()) 

137 self.assertMasksEqual(mi0.getMask(), mi1.getMask()) 

138 self.assertMasksEqual(mi1.getMask(), mi0.getMask()) 

139 

140 # alter image and variance planes and check the results 

141 for getName in ("getImage", "getVariance"): 

142 isFloat = getattr(mi, getName)().getArray().dtype.kind == "f" 

143 if isFloat: 

144 for errVal in (np.nan, np.inf, -np.inf): 

145 mi0 = mi.Factory(mi, True) 

146 mi1 = mi.Factory(mi, True) 

147 plane0 = getattr(mi0, getName)() 

148 plane1 = getattr(mi1, getName)() 

149 plane1[2, 2] = errVal 

150 with self.assertRaises(Exception): 

151 self.assertImagesAlmostEqual(plane0, plane1) 

152 with self.assertRaises(Exception): 

153 self.assertImagesAlmostEqual(plane0.getArray(), plane1) 

154 with self.assertRaises(Exception): 

155 self.assertImagesAlmostEqual(plane1, plane0) 

156 with self.assertRaises(Exception): 

157 self.assertMaskedImagesAlmostEqual(mi0, mi1) 

158 with self.assertRaises(Exception): 

159 self.assertMaskedImagesAlmostEqual( 

160 mi0, (mi1.image.array, mi1.mask.array, mi1.variance.array)) 

161 with self.assertRaises(Exception): 

162 self.assertMaskedImagesAlmostEqual(mi1, mi0) 

163 

164 skipMask = mi.getMask().Factory(mi.getMask(), True) 

165 skipMaskArr = skipMask.getArray() 

166 skipMaskArr[:] = 0 

167 skipMaskArr[2, 2] = 1 

168 self.assertImagesAlmostEqual( 

169 plane0, plane1, skipMask=skipMaskArr, atol=0, rtol=0) 

170 self.assertImagesAlmostEqual( 

171 plane0, plane1, skipMask=skipMask, atol=0, rtol=0) 

172 self.assertMaskedImagesAlmostEqual( 

173 mi0, mi1, skipMask=skipMaskArr, atol=0, rtol=0) 

174 self.assertMaskedImagesAlmostEqual( 

175 mi0, mi1, skipMask=skipMask, atol=0, rtol=0) 

176 

177 for dval in (0.001, 0.03): 

178 mi0 = mi.Factory(mi, True) 

179 mi1 = mi.Factory(mi, True) 

180 plane0 = getattr(mi0, getName)() 

181 plane1 = getattr(mi1, getName)() 

182 plane1[2, 2] += dval 

183 val1 = plane1[2, 2, afwImage.LOCAL] 

184 self.assertImagesAlmostEqual( 

185 plane0, plane1, rtol=0, atol=dval + epsilon) 

186 self.assertImagesAlmostEqual( 

187 plane0, plane1, rtol=dval/val1 + epsilon, atol=0) 

188 self.assertMaskedImagesAlmostEqual( 

189 mi0, mi1, rtol=0, atol=dval + epsilon) 

190 self.assertMaskedImagesAlmostEqual( 

191 mi1, mi0, rtol=0, atol=dval + epsilon) 

192 with self.assertRaises(Exception): 

193 self.assertImagesAlmostEqual( 

194 plane0, plane1, rtol=0, atol=dval - epsilon) 

195 with self.assertRaises(Exception): 

196 self.assertImagesAlmostEqual( 

197 plane0, plane1, rtol=dval/val1 - epsilon, atol=0) 

198 with self.assertRaises(Exception): 

199 self.assertMaskedImagesAlmostEqual( 

200 mi0, mi1, rtol=0, atol=dval - epsilon) 

201 with self.assertRaises(Exception): 

202 self.assertMaskedImagesAlmostEqual( 

203 mi0, mi1, rtol=dval/val1 - epsilon, atol=0) 

204 else: 

205 # plane is an integer of some type 

206 for dval in (1, 3): 

207 mi0 = mi.Factory(mi, True) 

208 mi1 = mi.Factory(mi, True) 

209 plane0 = getattr(mi0, getName)() 

210 plane1 = getattr(mi1, getName)() 

211 plane1[2, 2] += dval 

212 val1 = plane1[2, 2, afwImage.LOCAL] 

213 # int value and test is <= so epsilon not required for atol 

214 # but rtol is a fraction, so epsilon is still safest for 

215 # the rtol test 

216 self.assertImagesAlmostEqual( 

217 plane0, plane1, rtol=0, atol=dval) 

218 self.assertImagesAlmostEqual( 

219 plane0, plane1, rtol=dval/val1 + epsilon, atol=0) 

220 with self.assertRaises(Exception): 

221 self.assertImagesAlmostEqual( 

222 plane0, plane1, rtol=0, atol=dval - epsilon) 

223 with self.assertRaises(Exception): 

224 self.assertImagesAlmostEqual( 

225 plane0, plane1, rtol=dval/val1 - epsilon, atol=0) 

226 

227 # alter mask and check the results 

228 mi0 = mi.Factory(mi, True) 

229 mi1 = mi.Factory(mi, True) 

230 mask0 = mi0.getMask() 

231 mask1 = mi1.getMask() 

232 for dval in (1, 3): 

233 # getArray avoids "unsupported operand type" failure 

234 mask1.getArray()[2, 2] += 1 

235 with self.assertRaises(Exception): 

236 self.assertMasksEqual(mask0, mask1) 

237 with self.assertRaises(Exception): 

238 self.assertMasksEqual(mask1, mask0) 

239 with self.assertRaises(Exception): 

240 self.assertMaskedImagesEqual(mi0, mi1) 

241 with self.assertRaises(Exception): 

242 self.assertMaskedImagesEqual(mi1, mi0) 

243 

244 skipMask = mi.getMask().Factory(mi.getMask(), True) 

245 skipMaskArr = skipMask.getArray() 

246 skipMaskArr[:] = 0 

247 skipMaskArr[2, 2] = 1 

248 self.assertMasksEqual(mask0, mask1, skipMask=skipMaskArr) 

249 self.assertMasksEqual(mask0, mask1, skipMask=skipMask) 

250 self.assertMaskedImagesAlmostEqual( 

251 mi0, mi1, skipMask=skipMaskArr, atol=0, rtol=0) 

252 self.assertMaskedImagesAlmostEqual( 

253 mi0, mi1, skipMask=skipMask, atol=0, rtol=0) 

254 

255 def testAssertImagesAlmostEqual(self): 

256 """Test assertImagesAlmostEqual, assertMasksEqual and assertMaskedImagesAlmostEqual 

257 """ 

258 width = 10 

259 height = 9 

260 

261 for miType in (afwImage.MaskedImageF, afwImage.MaskedImageD, afwImage.MaskedImageI, 

262 afwImage.MaskedImageU): 

263 mi = makeRampMaskedImageWithNans(width, height, miType) 

264 self.checkMaskedImage(mi) 

265 

266 for invalidType in (np.zeros([width+1, height]), str, self.assertRaises): 

267 mi = makeRampMaskedImageWithNans(width, height, miType) 

268 with self.assertRaises(TypeError): 

269 self.assertMasksEqual(mi.getMask(), invalidType) 

270 with self.assertRaises(TypeError): 

271 self.assertMasksEqual(invalidType, mi.getMask()) 

272 with self.assertRaises(TypeError): 

273 self.assertMasksEqual( 

274 mi.getMask(), mi.getMask(), skipMask=invalidType) 

275 

276 with self.assertRaises(TypeError): 

277 self.assertImagesAlmostEqual(mi.getImage(), invalidType) 

278 with self.assertRaises(TypeError): 

279 self.assertImagesAlmostEqual(invalidType, mi.getImage()) 

280 with self.assertRaises(TypeError): 

281 self.assertImagesAlmostEqual( 

282 mi.getImage(), mi.getImage(), skipMask=invalidType) 

283 

284 with self.assertRaises(TypeError): 

285 self.assertMaskedImagesAlmostEqual(mi, invalidType) 

286 with self.assertRaises(TypeError): 

287 self.assertMaskedImagesAlmostEqual(invalidType, mi) 

288 with self.assertRaises(TypeError): 

289 self.assertMaskedImagesAlmostEqual( 

290 mi, mi, skipMask=invalidType) 

291 

292 with self.assertRaises(TypeError): 

293 self.assertMaskedImagesAlmostEqual( 

294 mi.getImage(), mi.getImage()) 

295 

296 def testUnsignedImages(self): 

297 """Unsigned images can give incorrect differences unless the test code is careful 

298 """ 

299 image0 = np.zeros([5, 5], dtype=np.uint8) 

300 image1 = np.zeros([5, 5], dtype=np.uint8) 

301 image0[0, 0] = 1 

302 image1[0, 1] = 2 

303 

304 # arrays differ by a maximum of 2 

305 errMsg1 = imagesDiffer(image0, image1) 

306 match = re.match(r"maxDiff *= *(\d+)", errMsg1, re.IGNORECASE) 

307 self.assertIsNotNone(match) 

308 self.assertEqual(match.group(1), "2") 

309 

310 # arrays are equal to within 5 

311 self.assertImagesAlmostEqual(image0, image1, atol=5) 

312 

313 

314def makeRampMaskedImageWithNans(width, height, imgClass=afwImage.MaskedImageF): 

315 """Make a masked image that is a ramp with additional non-finite values 

316 

317 Make a masked image with the following additional non-finite values 

318 in the variance plane and (if image is of some floating type) image plane: 

319 - nan at [0, 0] 

320 - inf at [1, 0] 

321 - -inf at [0, 1] 

322 """ 

323 mi = makeRampMaskedImage(width, height, imgClass) 

324 

325 var = mi.getVariance() 

326 var[0, 0] = np.nan 

327 var[1, 0] = np.inf 

328 var[0, 1] = -np.inf 

329 

330 im = mi.getImage() 

331 try: 

332 np.array([np.nan], dtype=im.getArray().dtype) 

333 except Exception: 

334 # image plane does not support nan, etc. (presumably an int of some 

335 # variety) 

336 pass 

337 else: 

338 # image plane does support nan, etc. 

339 im[0, 0] = np.nan 

340 im[1, 0] = np.inf 

341 im[0, 1] = -np.inf 

342 return mi 

343 

344 

345def makeRampMaskedImage(width, height, imgClass=afwImage.MaskedImageF): 

346 """Make a ramp image of the specified size and image class 

347 

348 Image values start from 0 at the lower left corner and increase by 1 along rows 

349 Variance values equal image values + 100 

350 Mask values equal image values modulo 8 bits (leaving plenty of unused values) 

351 """ 

352 mi = imgClass(width, height) 

353 image = mi.getImage() 

354 mask = mi.getMask() 

355 variance = mi.getVariance() 

356 val = 0 

357 for yInd in range(height): 

358 for xInd in range(width): 

359 image[xInd, yInd, afwImage.LOCAL] = val 

360 variance[xInd, yInd, afwImage.LOCAL] = val + 100 

361 mask[xInd, yInd, afwImage.LOCAL] = val % 0x100 

362 val += 1 

363 return mi 

364 

365 

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

367 pass 

368 

369 

370def setup_module(module): 

371 lsst.utils.tests.init() 

372 

373 

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

375 lsst.utils.tests.init() 

376 unittest.main()