Coverage for tests/test_methods.py: 7%

229 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-22 02:38 -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.getArrays(), mi1, atol=0, rtol=0) 

114 self.assertMaskedImagesAlmostEqual( 

115 mi0, mi1.getArrays(), atol=0, rtol=0) 

116 self.assertMaskedImagesAlmostEqual( 

117 mi0.getArrays(), mi1.getArrays(), atol=0, rtol=0) 

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

119 plane0 = getattr(mi0, getName)() 

120 plane1 = getattr(mi1, getName)() 

121 self.assertImagesEqual(plane0, plane1) 

122 self.assertImagesEqual(plane1, plane0) 

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

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

125 self.assertImagesAlmostEqual( 

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

127 self.assertImagesAlmostEqual( 

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

129 self.assertImagesAlmostEqual( 

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

131 self.assertMasksEqual(plane0, plane1) 

132 self.assertMasksEqual(plane1, plane0) 

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

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

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

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

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

138 

139 # alter image and variance planes and check the results 

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

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

142 if isFloat: 

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

144 mi0 = mi.Factory(mi, True) 

145 mi1 = mi.Factory(mi, True) 

146 plane0 = getattr(mi0, getName)() 

147 plane1 = getattr(mi1, getName)() 

148 plane1[2, 2] = errVal 

149 with self.assertRaises(Exception): 

150 self.assertImagesAlmostEqual(plane0, plane1) 

151 with self.assertRaises(Exception): 

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

153 with self.assertRaises(Exception): 

154 self.assertImagesAlmostEqual(plane1, plane0) 

155 with self.assertRaises(Exception): 

156 self.assertMaskedImagesAlmostEqual(mi0, mi1) 

157 with self.assertRaises(Exception): 

158 self.assertMaskedImagesAlmostEqual( 

159 mi0, mi1.getArrays()) 

160 with self.assertRaises(Exception): 

161 self.assertMaskedImagesAlmostEqual(mi1, mi0) 

162 

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

164 skipMaskArr = skipMask.getArray() 

165 skipMaskArr[:] = 0 

166 skipMaskArr[2, 2] = 1 

167 self.assertImagesAlmostEqual( 

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

169 self.assertImagesAlmostEqual( 

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

171 self.assertMaskedImagesAlmostEqual( 

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

173 self.assertMaskedImagesAlmostEqual( 

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

175 

176 for dval in (0.001, 0.03): 

177 mi0 = mi.Factory(mi, True) 

178 mi1 = mi.Factory(mi, True) 

179 plane0 = getattr(mi0, getName)() 

180 plane1 = getattr(mi1, getName)() 

181 plane1[2, 2] += dval 

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

183 self.assertImagesAlmostEqual( 

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

185 self.assertImagesAlmostEqual( 

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

187 self.assertMaskedImagesAlmostEqual( 

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

189 self.assertMaskedImagesAlmostEqual( 

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

191 with self.assertRaises(Exception): 

192 self.assertImagesAlmostEqual( 

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

194 with self.assertRaises(Exception): 

195 self.assertImagesAlmostEqual( 

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

197 with self.assertRaises(Exception): 

198 self.assertMaskedImagesAlmostEqual( 

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

200 with self.assertRaises(Exception): 

201 self.assertMaskedImagesAlmostEqual( 

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

203 else: 

204 # plane is an integer of some type 

205 for dval in (1, 3): 

206 mi0 = mi.Factory(mi, True) 

207 mi1 = mi.Factory(mi, True) 

208 plane0 = getattr(mi0, getName)() 

209 plane1 = getattr(mi1, getName)() 

210 plane1[2, 2] += dval 

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

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

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

214 # the rtol test 

215 self.assertImagesAlmostEqual( 

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

217 self.assertImagesAlmostEqual( 

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

219 with self.assertRaises(Exception): 

220 self.assertImagesAlmostEqual( 

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

222 with self.assertRaises(Exception): 

223 self.assertImagesAlmostEqual( 

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

225 

226 # alter mask and check the results 

227 mi0 = mi.Factory(mi, True) 

228 mi1 = mi.Factory(mi, True) 

229 mask0 = mi0.getMask() 

230 mask1 = mi1.getMask() 

231 for dval in (1, 3): 

232 # getArray avoids "unsupported operand type" failure 

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

234 with self.assertRaises(Exception): 

235 self.assertMasksEqual(mask0, mask1) 

236 with self.assertRaises(Exception): 

237 self.assertMasksEqual(mask1, mask0) 

238 with self.assertRaises(Exception): 

239 self.assertMaskedImagesEqual(mi0, mi1) 

240 with self.assertRaises(Exception): 

241 self.assertMaskedImagesEqual(mi1, mi0) 

242 

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

244 skipMaskArr = skipMask.getArray() 

245 skipMaskArr[:] = 0 

246 skipMaskArr[2, 2] = 1 

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

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

249 self.assertMaskedImagesAlmostEqual( 

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

251 self.assertMaskedImagesAlmostEqual( 

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

253 

254 def testAssertImagesAlmostEqual(self): 

255 """Test assertImagesAlmostEqual, assertMasksEqual and assertMaskedImagesAlmostEqual 

256 """ 

257 width = 10 

258 height = 9 

259 

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

261 afwImage.MaskedImageU): 

262 mi = makeRampMaskedImageWithNans(width, height, miType) 

263 self.checkMaskedImage(mi) 

264 

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

266 mi = makeRampMaskedImageWithNans(width, height, miType) 

267 with self.assertRaises(TypeError): 

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

269 with self.assertRaises(TypeError): 

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

271 with self.assertRaises(TypeError): 

272 self.assertMasksEqual( 

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

274 

275 with self.assertRaises(TypeError): 

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

277 with self.assertRaises(TypeError): 

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

279 with self.assertRaises(TypeError): 

280 self.assertImagesAlmostEqual( 

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

282 

283 with self.assertRaises(TypeError): 

284 self.assertMaskedImagesAlmostEqual(mi, invalidType) 

285 with self.assertRaises(TypeError): 

286 self.assertMaskedImagesAlmostEqual(invalidType, mi) 

287 with self.assertRaises(TypeError): 

288 self.assertMaskedImagesAlmostEqual( 

289 mi, mi, skipMask=invalidType) 

290 

291 with self.assertRaises(TypeError): 

292 self.assertMaskedImagesAlmostEqual( 

293 mi.getImage(), mi.getImage()) 

294 

295 def testUnsignedImages(self): 

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

297 """ 

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

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

300 image0[0, 0] = 1 

301 image1[0, 1] = 2 

302 

303 # arrays differ by a maximum of 2 

304 errMsg1 = imagesDiffer(image0, image1) 

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

306 self.assertIsNotNone(match) 

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

308 

309 # arrays are equal to within 5 

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

311 

312 

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

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

315 

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

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

318 - nan at [0, 0] 

319 - inf at [1, 0] 

320 - -inf at [0, 1] 

321 """ 

322 mi = makeRampMaskedImage(width, height, imgClass) 

323 

324 var = mi.getVariance() 

325 var[0, 0] = np.nan 

326 var[1, 0] = np.inf 

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

328 

329 im = mi.getImage() 

330 try: 

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

332 except Exception: 

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

334 # variety) 

335 pass 

336 else: 

337 # image plane does support nan, etc. 

338 im[0, 0] = np.nan 

339 im[1, 0] = np.inf 

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

341 return mi 

342 

343 

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

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

346 

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

348 Variance values equal image values + 100 

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

350 """ 

351 mi = imgClass(width, height) 

352 image = mi.getImage() 

353 mask = mi.getMask() 

354 variance = mi.getVariance() 

355 val = 0 

356 for yInd in range(height): 

357 for xInd in range(width): 

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

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

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

361 val += 1 

362 return mi 

363 

364 

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

366 pass 

367 

368 

369def setup_module(module): 

370 lsst.utils.tests.init() 

371 

372 

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

374 lsst.utils.tests.init() 

375 unittest.main()