Coverage for tests/test_interpolate.py: 19%

97 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-20 02: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# 

22 

23""" 

24Tests for Interpolate 

25 

26Run with: 

27 python test_interpolate.py 

28or 

29 pytest test_interpolate.py 

30""" 

31 

32import unittest 

33 

34import numpy as np 

35 

36import lsst.utils.tests 

37import lsst.afw.math as afwMath 

38import lsst.pex.exceptions as pexExcept 

39 

40 

41class InterpolateTestCase(lsst.utils.tests.TestCase): 

42 

43 """A test case for Interpolate Linear""" 

44 

45 def setUp(self): 

46 self.n = 10 

47 self.x = np.zeros(self.n, dtype=float) 

48 self.y1 = np.zeros(self.n, dtype=float) 

49 self.y2 = np.zeros(self.n, dtype=float) 

50 self.y0 = 1.0 

51 self.dydx = 1.0 

52 self.d2ydx2 = 0.5 

53 

54 for i in range(0, self.n, 1): 

55 self.x[i] = i 

56 self.y1[i] = self.dydx*self.x[i] + self.y0 

57 self.y2[i] = self.d2ydx2*self.x[i] * \ 

58 self.x[i] + self.dydx*self.x[i] + self.y0 

59 

60 self.xtest = 4.5 

61 self.y1test = self.dydx*self.xtest + self.y0 

62 self.y2test = self.d2ydx2*self.xtest*self.xtest + self.dydx*self.xtest + self.y0 

63 

64 def tearDown(self): 

65 del self.x 

66 del self.y1 

67 del self.y2 

68 

69 def testLinearRamp(self): 

70 

71 # === test the Linear Interpolator ============================ 

72 # default is akima spline 

73 yinterpL = afwMath.makeInterpolate(self.x, self.y1) 

74 youtL = yinterpL.interpolate(self.xtest) 

75 

76 self.assertEqual(youtL, self.y1test) 

77 

78 def testNaturalSplineRamp(self): 

79 

80 # === test the Spline interpolator ======================= 

81 # specify interp type with the string interface 

82 yinterpS = afwMath.makeInterpolate( 

83 self.x, self.y1, afwMath.Interpolate.NATURAL_SPLINE) 

84 youtS = yinterpS.interpolate(self.xtest) 

85 

86 self.assertEqual(youtS, self.y1test) 

87 

88 def testAkimaSplineParabola(self): 

89 """test the Spline interpolator""" 

90 # specify interp type with the enum style interface 

91 yinterpS = afwMath.makeInterpolate( 

92 self.x, self.y2, afwMath.Interpolate.AKIMA_SPLINE) 

93 youtS = yinterpS.interpolate(self.xtest) 

94 

95 self.assertEqual(youtS, self.y2test) 

96 

97 def testConstant(self): 

98 """test the constant interpolator""" 

99 # [xy]vec: point samples 

100 # [xy]vec_c: centered values 

101 xvec = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]) 

102 xvec_c = np.array( 

103 [-0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]) 

104 yvec = np.array([1.0, 2.4, 5.0, 8.4, 13.0, 

105 18.4, 25.0, 32.6, 41.0, 50.6]) 

106 yvec_c = np.array([1.0, 1.7, 3.7, 6.7, 10.7, 15.7, 

107 21.7, 28.8, 36.8, 45.8, 50.6]) 

108 

109 interp = afwMath.makeInterpolate( 

110 xvec, yvec, afwMath.Interpolate.CONSTANT) 

111 

112 for x, y in zip(xvec_c, yvec_c): 

113 self.assertAlmostEqual(interp.interpolate(x + 0.1), y) 

114 self.assertAlmostEqual(interp.interpolate(x), y) 

115 

116 self.assertEqual(interp.interpolate(xvec[0] - 10), yvec[0]) 

117 n = len(yvec) 

118 self.assertEqual(interp.interpolate(xvec[n - 1] + 10), yvec[n - 1]) 

119 

120 # test caching as we go backwards 

121 for x, y in reversed(list(zip(xvec_c, yvec_c))): 

122 self.assertAlmostEqual(interp.interpolate(x + 0.1), y) 

123 self.assertAlmostEqual(interp.interpolate(x), y) 

124 

125 i = 2 

126 for x in np.arange(xvec_c[i], xvec_c[i + 1], 10): 

127 self.assertEqual(interp.interpolate(x), yvec_c[i]) 

128 

129 def testInvalidInputs(self): 

130 """Test that invalid inputs cause an abort""" 

131 

132 with self.assertRaises(pexExcept.OutOfRangeError): 

133 afwMath.makeInterpolate(np.array([], dtype=float), np.array([], dtype=float), 

134 afwMath.Interpolate.CONSTANT) 

135 

136 afwMath.makeInterpolate(np.array([0], dtype=float), np.array([1], dtype=float), 

137 afwMath.Interpolate.CONSTANT) 

138 

139 with self.assertRaises(pexExcept.OutOfRangeError): 

140 afwMath.makeInterpolate(np.array([0], dtype=float), np.array([1], dtype=float), 

141 afwMath.Interpolate.LINEAR) 

142 

143 def testLookupMaxInterpStyle(self): 

144 for numPoints in range(1, 6): 

145 maxInterpStyle = afwMath.lookupMaxInterpStyle(numPoints) 

146 desiredMax = { 

147 1: afwMath.Interpolate.Style.CONSTANT, 

148 2: afwMath.Interpolate.Style.LINEAR, 

149 3: afwMath.Interpolate.Style.CUBIC_SPLINE, 

150 4: afwMath.Interpolate.Style.CUBIC_SPLINE, 

151 }.get(numPoints, afwMath.Interpolate.Style.AKIMA_SPLINE) 

152 self.assertEqual(maxInterpStyle, desiredMax) 

153 

154 for badNumPoints in (-5, -1, 0): 

155 with self.assertRaises(pexExcept.InvalidParameterError): 

156 afwMath.lookupMaxInterpStyle(badNumPoints) 

157 

158 def testLookupMinInterpPoints(self): 

159 for style in afwMath.Interpolate.Style.__members__.values(): 

160 if style in (afwMath.Interpolate.Style.UNKNOWN, afwMath.Interpolate.Style.NUM_STYLES): 

161 with self.assertRaises(pexExcept.OutOfRangeError): 

162 afwMath.lookupMinInterpPoints(style) 

163 else: 

164 minPoints = afwMath.lookupMinInterpPoints(style) 

165 desiredMin = { 

166 afwMath.Interpolate.Style.CONSTANT: 1, 

167 afwMath.Interpolate.Style.LINEAR: 2, 

168 afwMath.Interpolate.Style.NATURAL_SPLINE: 3, 

169 afwMath.Interpolate.Style.CUBIC_SPLINE: 3, 

170 afwMath.Interpolate.Style.CUBIC_SPLINE_PERIODIC: 3, 

171 afwMath.Interpolate.Style.AKIMA_SPLINE: 5, 

172 afwMath.Interpolate.Style.AKIMA_SPLINE_PERIODIC: 5, 

173 }.get(style, None) 

174 if desiredMin is None: 

175 self.fail(f"Unrecognized style: {style}") 

176 self.assertEqual(minPoints, desiredMin) 

177 

178 def testStringToInterpStyle(self): 

179 for name, desiredStyle in afwMath.Interpolate.Style.__members__.items(): 

180 if name in ("UNKNOWN", "NUM_STYLES"): 

181 with self.assertRaises(pexExcept.InvalidParameterError): 

182 afwMath.stringToInterpStyle(name) 

183 else: 

184 style = afwMath.stringToInterpStyle(name) 

185 self.assertEqual(style, desiredStyle) 

186 

187 for badName in ("BOGUS", ""): 

188 with self.assertRaises(pexExcept.InvalidParameterError): 

189 afwMath.stringToInterpStyle(badName) 

190 

191 

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

193 pass 

194 

195 

196def setup_module(module): 

197 lsst.utils.tests.init() 

198 

199 

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

201 lsst.utils.tests.init() 

202 unittest.main()