Coverage for tests/test_transformBoundedField.py: 21%

101 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-03-30 02:46 -0700

1# This file is part of afw. 

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 

22""" 

23Tests for math.TransformBoundedField 

24 

25Run with: 

26 python test_transformBoundedField.py 

27or 

28 pytest test_transformBoundedField.py 

29""" 

30 

31import unittest 

32 

33import astshim 

34import numpy as np 

35from numpy.testing import assert_allclose 

36 

37import lsst.utils.tests 

38import lsst.pex.exceptions 

39import lsst.geom 

40import lsst.afw.geom 

41import lsst.afw.image 

42from lsst.afw.math import TransformBoundedField 

43 

44 

45CHEBYSHEV_T = [ 45 ↛ exitline 45 didn't jump to the function exit

46 lambda x: x**0, 

47 lambda x: x, 

48 lambda x: 2*x**2 - 1, 

49 lambda x: (4*x**2 - 3)*x, 

50 lambda x: (8*x**2 - 8)*x**2 + 1, 

51 lambda x: ((16*x**2 - 20)*x**2 + 5)*x, 

52] 

53 

54 

55class TransformBoundedFieldTestCase(lsst.utils.tests.TestCase): 

56 

57 def setUp(self): 

58 self.longMessage = True 

59 

60 # an arbitrary bounding box (not that this kind of field cares) 

61 self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-3, 4), 

62 lsst.geom.Extent2I(5, 30)) 

63 

64 # a list of points contained in the bbox 

65 self.pointList = lsst.geom.Box2D(self.bbox).getCorners() 

66 self.pointList.append(lsst.geom.Box2D(self.bbox).getCenter()) 

67 self.xList = np.array([p[0] for p in self.pointList]) 

68 self.yList = np.array([p[1] for p in self.pointList]) 

69 

70 # a simple polynomial mapping 

71 coeff_f = np.array([ 

72 [1.5, 1, 0, 0], 

73 [-0.5, 1, 1, 0], 

74 [1.0, 1, 0, 1], 

75 ]) 

76 polyMap = astshim.PolyMap(coeff_f, 1) 

77 self.transform = lsst.afw.geom.TransformPoint2ToGeneric(polyMap) 

78 self.boundedField = TransformBoundedField(self.bbox, self.transform) 

79 

80 def tearDown(self): 

81 del self.transform 

82 

83 def testEvaluate(self): 

84 """Test the various overloads of `evaluate` 

85 """ 

86 for point in self.pointList: 

87 # applylForward returns a vector with one entry per axis 

88 # and in this case there is just one axis 

89 predRes = self.transform.applyForward(point)[0] 

90 

91 res = self.boundedField.evaluate(point) 

92 self.assertFloatsAlmostEqual(res, predRes) 

93 

94 x, y = point 

95 res2 = self.boundedField.evaluate(x, y) 

96 self.assertFloatsAlmostEqual(res2, predRes) 

97 

98 resArr = self.boundedField.evaluate(self.xList, self.yList) 

99 # applylForward returns an array with one row of values per axis 

100 # and in this case there is just one axis 

101 predResArr = self.transform.applyForward(self.pointList)[0] 

102 assert_allclose(resArr, predResArr) 

103 

104 def testMultiplyOperator(self): 

105 """Test operator* 

106 """ 

107 maxVal = np.max(np.abs(self.transform.applyForward(self.pointList)[0])) 

108 for multFactor in (-9e99, -1.5e-7, 3.6e-7, 1.5, 9.23e99): 

109 atol = abs(maxVal*multFactor*1e-15) 

110 predResult = self.transform.applyForward(self.pointList)[0]*multFactor 

111 

112 scaledField1 = self.boundedField*multFactor 

113 assert_allclose(scaledField1.evaluate(self.xList, self.yList), predResult, atol=atol) 

114 

115 scaledField2 = multFactor*self.boundedField 

116 assert_allclose(scaledField2.evaluate(self.xList, self.yList), predResult, atol=atol) 

117 

118 def testBBox(self): 

119 """The BBox should have no effect on the kind of transform being tested 

120 

121 Use an empty bbox as an extreme test of this 

122 """ 

123 self.assertEqual(self.boundedField.getBBox(), self.bbox) 

124 

125 emptyBBox = lsst.geom.Box2I() 

126 noBBoxField = TransformBoundedField(emptyBBox, self.transform) 

127 self.assertEqual(noBBoxField.getBBox(), emptyBBox) 

128 

129 resArr = self.boundedField.evaluate(self.xList, self.yList) 

130 resArrNoBBox = noBBoxField.evaluate(self.xList, self.yList) 

131 assert_allclose(resArr, resArrNoBBox) 

132 

133 def testPersistenceAndEquality(self): 

134 """Test persistence using writeFits and readFits 

135 

136 Also test operator== 

137 """ 

138 with lsst.utils.tests.getTempFilePath(".fits") as filename: 

139 self.boundedField.writeFits(filename) 

140 readField = TransformBoundedField.readFits(filename) 

141 

142 self.assertTrue(self.boundedField == readField) 

143 self.assertFalse(self.boundedField != readField) 

144 self.assertEqual(self.boundedField, readField) 

145 

146 resArr = self.boundedField.evaluate(self.xList, self.yList) 

147 readResArr = readField.evaluate(self.xList, self.yList) 

148 assert_allclose(resArr, readResArr) 

149 self.assertEqual(readField.getBBox(), self.bbox) 

150 

151 def testComplexPersistence(self): 

152 """Test persistence of a TransformBoundedField whose string representation is huge 

153 """ 

154 # DM-11964 shows that CFITSIO cannot handle string fields 

155 # in binary tables that have more than 28799 characters 

156 # make sure the test has plenty of margin 

157 minChars = 10*28799 

158 degree = 100 # make large enough that len(transform.writeString()) > minChars 

159 n_coeffs = (degree + 1)*(degree + 2)//2 

160 coeffs = np.zeros((n_coeffs, 4), dtype=float) 

161 k = 0 

162 for j in range(degree + 1): 

163 for i in range(degree - j + 1): 

164 coeffs[k][0] = np.random.random() 

165 coeffs[k][1] = 1 

166 coeffs[k][2] = i 

167 coeffs[k][3] = j 

168 k += 1 

169 chebyMap = astshim.PolyMap(coeffs, 1) 

170 transform = lsst.afw.geom.TransformPoint2ToGeneric(chebyMap) 

171 lenTransformStr = len(transform.writeString()) 

172 print(f"len transform str={lenTransformStr}; minChars={minChars}") 

173 self.assertGreater(lenTransformStr, minChars) 

174 complexBoundedField = TransformBoundedField(self.bbox, transform) 

175 with lsst.utils.tests.getTempFilePath(".fits") as filename: 

176 complexBoundedField.writeFits(filename) 

177 readField = TransformBoundedField.readFits(filename) 

178 

179 self.assertTrue(complexBoundedField == readField) 

180 self.assertFalse(complexBoundedField != readField) 

181 self.assertEqual(complexBoundedField, readField) 

182 

183 resArr = complexBoundedField.evaluate(self.xList, self.yList) 

184 readResArr = readField.evaluate(self.xList, self.yList) 

185 assert_allclose(resArr, readResArr) 

186 self.assertEqual(readField.getBBox(), self.bbox) 

187 

188 

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

190 pass 

191 

192 

193def setup_module(module): 

194 lsst.utils.tests.init() 

195 

196 

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

198 lsst.utils.tests.init() 

199 unittest.main()