Coverage for tests/test_curve.py: 20%

104 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-03 11:03 +0000

1# This file is part of meas_algorithms. 

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 

22import os 

23import unittest 

24import numpy as np 

25from scipy import signal 

26import astropy.units as u 

27 

28import lsst.meas.algorithms as algorithms 

29import lsst.utils.tests 

30from lsst.geom import Point2I, Point2D, Box2I, Extent2I 

31import lsst.afw.cameraGeom.utils as cgUtils 

32 

33TESTDIR = os.path.abspath(os.path.dirname(__file__)) 

34 

35 

36class MockAmp: 

37 def __init__(self, name, bbox): 

38 self.name = name 

39 self.box = bbox 

40 

41 def getName(self): 

42 return self.name 

43 

44 def getBBox(self): 

45 return self.box 

46 

47 

48class CurveTestCase(lsst.utils.tests.TestCase): 

49 """Tests for the Curve class""" 

50 

51 def setUp(self): 

52 self.wavelength = np.linspace(3000, 5000, 150)*u.angstrom 

53 self.efficiency = signal.gaussian(len(self.wavelength), std=100)*u.percent 

54 self.metadata = dict([('MODE', 'AMP'), ('TYPE', 'QE'), ('CALIBDATE', '1970-01-01T00:00:00'), 

55 ('INSTRUME', 'ts8'), ('OBSTYPE', 'qe_curve'), ('DETECTOR', 99), 

56 ('DATE', '2019-09-27T22:15:13.518320'), ('CALIB_CREATION_DATE', '2019-09-27'), 

57 ('CALIB_CREATION_TIME', '22:15:13')]) 

58 

59 def tearDown(self): 

60 del self.wavelength 

61 del self.efficiency 

62 del self.metadata 

63 

64 def curve_tester(self, curve_class, args): 

65 curve = curve_class(*args) 

66 

67 # Serialization round trip 

68 table = curve.toTable() 

69 curve2 = curve_class.fromTable(table) 

70 self.assertEqual(curve, curve2) 

71 

72 # via FITS 

73 with lsst.utils.tests.getTempFilePath(".fits") as tmpFile: 

74 curve.writeFits(tmpFile) 

75 curve2 = algorithms.Curve.readFits(tmpFile) 

76 

77 self.assertEqual(curve2, curve) 

78 

79 # via text file 

80 with lsst.utils.tests.getTempFilePath(".ecsv") as tmpFile: 

81 curve.writeText(tmpFile) 

82 curve2 = algorithms.Curve.readText(tmpFile) 

83 

84 self.assertEqual(curve2, curve) 

85 

86 # Check bad values 

87 with self.assertRaises(ValueError): 

88 # test that raised when non quantities are passed 

89 nargs = [] 

90 for arg in args: 

91 if hasattr(arg, 'unit'): 

92 nargs.append(arg.value) 

93 else: 

94 nargs.append(arg) 

95 _ = curve_class(*nargs) 

96 

97 # Check bad values 

98 with self.assertRaises(ValueError): 

99 # test that raised when non-length quantities are passed 

100 nargs = [] 

101 for arg in args: 

102 if hasattr(arg, 'unit'): 

103 nargs.append(arg.value*u.amp) 

104 else: 

105 nargs.append(arg) 

106 _ = curve_class(*nargs) 

107 

108 def interp_tester(self, curve_class, args, detector): 

109 curve = curve_class(*args) 

110 w = 3500*u.angstrom 

111 xs = np.linspace(0, 1023, 33) 

112 ys = np.linspace(0, 1023, 33) 

113 val_map = {'A': 0.9329662, 'B': 0.7463730} 

114 # Does interpolation work 

115 for x, y in zip(xs, ys): 

116 point = Point2D(x, y) 

117 if detector: 

118 amp = cgUtils.findAmp(detector, Point2I(point)) 

119 value = val_map[amp.getName()] 

120 else: 

121 value = 0.9329662 

122 interp_val = curve.evaluate(detector, point, w) 

123 self.assertAlmostEqual(interp_val.value, value, places=5) 

124 self.assertEqual(interp_val.unit, u.percent) 

125 # Does interpolation work with arrays 

126 w_arr = np.linspace(320, 430, 70)*u.nm 

127 out_arr = curve.evaluate(detector, point, w_arr) 

128 self.assertEqual(len(w_arr), len(out_arr)) 

129 # Does interpolation with different units work as expected 

130 point = Point2D(500., 500.) 

131 val1 = curve.evaluate(detector, point, w) 

132 new_w = w.to(u.mm) 

133 val2 = curve.evaluate(detector, point, new_w) 

134 self.assertEqual(val1.value, val2.value) 

135 # Does out of band interpolation do something reasonable 

136 # Default is to clamp to 0 outside the bounds. 

137 w = 0.*u.angstrom 

138 interp_val = curve.evaluate(detector, point, w) 

139 self.assertEqual(interp_val, 0.*u.percent) 

140 # interpolation with non-quantity should raise 

141 with self.assertRaises(ValueError): 

142 interp_val = curve.evaluate(detector, point, w.value) 

143 # Does interpolation fail with non-length unit 

144 with self.assertRaises(ValueError): 

145 w = 0.*u.Kelvin 

146 interp_val = curve.evaluate(detector, point, w) 

147 

148 def test_detector_curve(self): 

149 args = (self.wavelength, self.efficiency, self.metadata) 

150 self.curve_tester(algorithms.DetectorCurve, args) 

151 self.interp_tester(algorithms.DetectorCurve, args, None) 

152 

153 def test_amp_curve(self): 

154 # Future versions of astropy will pass unit through concatenation 

155 amp_wavelength = np.concatenate([self.wavelength.value, self.wavelength.value])*u.angstrom # Two amps 

156 amp_efficiency = np.concatenate([self.efficiency.value, 

157 self.efficiency.value*0.8])*u.percent # Two amps 

158 amp_name = np.concatenate([['A' for el in self.wavelength], ['B' for el in self.wavelength]]) 

159 amplist = [MockAmp('A', Box2I(Point2I(0, 0), Extent2I(512, 1025))), 

160 MockAmp('B', Box2I(Point2I(512, 10), Extent2I(512, 1024)))] 

161 args = (amp_name, amp_wavelength, amp_efficiency, self.metadata) 

162 self.curve_tester(algorithms.AmpCurve, args) 

163 self.interp_tester(algorithms.AmpCurve, args, amplist) 

164 

165 

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

167 pass 

168 

169 

170def setup_module(module): 

171 lsst.utils.tests.init() 

172 

173 

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

175 lsst.utils.tests.init() 

176 unittest.main()