Coverage for python/lsst/obs/base/butler_tests.py: 19%

78 statements  

« prev     ^ index     » next       coverage.py v7.2.1, created at 2023-03-12 01:53 -0800

1# This file is part of obs_base. 

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 abc 

23import inspect 

24import unittest 

25import collections 

26 

27__all__ = ["ButlerGetTests"] 

28 

29 

30class ButlerGetTests(metaclass=abc.ABCMeta): 

31 """Tests of obs_* Butler get() functionality. 

32 

33 In the subclasses's setUp(): 

34 * Call setUp_butler_get() to fill in required parameters. 

35 """ 

36 

37 def setUp_butler_get(self, 

38 ccdExposureId_bits=None, 

39 exposureIds=None, 

40 filters=None, 

41 exptimes=None, 

42 detectorIds=None, 

43 detector_names=None, 

44 detector_serials=None, 

45 dimensions=None, 

46 sky_origin=None, 

47 raw_subsets=None, 

48 good_detectorIds=None, 

49 bad_detectorIds=None, 

50 linearizer_type=None, 

51 raw_header_wcs=None 

52 ): 

53 """ 

54 Set up the necessary variables for butlerGet tests. 

55 

56 All "exposure name" entries below should correspond to an entry in 

57 self.dataIds. 

58 

59 Parameters 

60 ---------- 

61 

62 ccdExposureId_bits : `int` 

63 expected value of ccdExposureId_bits 

64 exposureIds : `dict` 

65 dict of exposure name : ccdExposureId (the number as returned by 

66 the butler) 

67 filters : `dict` 

68 dict of exposure name : filter name 

69 exptimes : `dict` 

70 dict of exposure name : exposure time 

71 detector_names : `dict` 

72 dict of exposure name : detector name 

73 detectorIds : `dict` 

74 dict of exposure name : detectorId 

75 detector_serials : `dict` 

76 dict of exposure name : detector serial 

77 dimensions : `dict` 

78 dict of exposure name : dimensions (as a geom.Extent2I) 

79 sky_origin : `tuple` of `float` 

80 Longitude, Latitude of 'raw' exposure 

81 raw_subsets : `tuple` of (kwargs, `int`) 

82 keyword args and expected number of subsets for 

83 ``butler.subset('raw', **kwargs)`` 

84 good_detectorIds : `list` of `int` 

85 list of valid ccd numbers 

86 bad_detectorIds : `list` of `int` 

87 list of invalid ccd numbers 

88 linearizer_type : `dict` 

89 dict of detectorId (usually `int`): LinearizerType 

90 (e.g. lsst.ip.isr.LinearizeLookupTable.LinearityType), 

91 or unittest.SkipTest to skip all linearizer tests. 

92 raw_header_wcs : `lsst.afw.geom.SkyWcs` 

93 The SkyWcs object that should be returned by 

94 ``butler.get("raw_header_wcs", dataId=self.dataIds["raw"])`` 

95 """ 

96 

97 fields = ['ccdExposureId_bits', 

98 'exposureIds', 

99 'filters', 

100 'exptimes', 

101 'detector_names', 

102 'detectorIds', 

103 'detector_serials', 

104 'dimensions', 

105 'sky_origin', 

106 'raw_subsets', 

107 'good_detectorIds', 

108 'bad_detectorIds', 

109 'linearizer_type', 

110 'raw_header_wcs' 

111 ] 

112 ButlerGet = collections.namedtuple("ButlerGetData", fields) 

113 

114 self.butler_get_data = ButlerGet(ccdExposureId_bits=ccdExposureId_bits, 

115 exposureIds=exposureIds, 

116 filters=filters, 

117 exptimes=exptimes, 

118 detectorIds=detectorIds, 

119 detector_names=detector_names, 

120 detector_serials=detector_serials, 

121 dimensions=dimensions, 

122 sky_origin=sky_origin, 

123 raw_subsets=raw_subsets, 

124 good_detectorIds=good_detectorIds, 

125 bad_detectorIds=bad_detectorIds, 

126 linearizer_type=linearizer_type, 

127 raw_header_wcs=raw_header_wcs 

128 ) 

129 

130 def test_exposureId_bits(self): 

131 bits = self.butler.get('ccdExposureId_bits') 

132 self.assertEqual(bits, self.butler_get_data.ccdExposureId_bits) 

133 

134 def _test_exposure(self, name): 

135 if self.dataIds[name] is unittest.SkipTest: 

136 self.skipTest('Skipping %s as requested' % (inspect.currentframe().f_code.co_name)) 

137 exp = self.butler.get(name, self.dataIds[name]) 

138 

139 exp_md = self.butler.get(name + "_md", self.dataIds[name]) 

140 self.assertEqual(type(exp_md), type(exp.getMetadata())) 

141 

142 self.assertEqual(exp.getDimensions(), self.butler_get_data.dimensions[name]) 

143 self.assertEqual(exp.getDetector().getId(), self.butler_get_data.detectorIds[name]) 

144 self.assertEqual(exp.getDetector().getName(), self.butler_get_data.detector_names[name]) 

145 self.assertEqual(exp.getDetector().getSerial(), self.butler_get_data.detector_serials[name]) 

146 # obs_test does not have physical filters, so include a fallback 

147 exposureFilter = exp.getFilterLabel() 

148 if exposureFilter: 

149 if exposureFilter.hasPhysicalLabel(): 

150 filterName = exposureFilter.physicalLabel 

151 else: 

152 filterName = exposureFilter.bandLabel 

153 else: 

154 filterName = "_unknown_" 

155 self.assertEqual(filterName, self.butler_get_data.filters[name]) 

156 exposureId = self.butler.get('ccdExposureId', dataId=self.dataIds[name]) 

157 self.assertEqual(exposureId, self.butler_get_data.exposureIds[name]) 

158 self.assertEqual(exp.getInfo().getVisitInfo().getExposureTime(), self.butler_get_data.exptimes[name]) 

159 return exp 

160 

161 def test_raw(self): 

162 exp = self._test_exposure('raw') 

163 # We only test the existence of WCS in the raw files, since it's only 

164 # well-defined for raw, and other exposure types could have or not 

165 # have a WCS depending on various implementation details. 

166 # Even for raw, there are data that do not have a WCS, e.g. teststand 

167 # data 

168 if self.butler_get_data.sky_origin is not unittest.SkipTest: 

169 self.assertEqual(exp.hasWcs(), True) 

170 origin = exp.getWcs().getSkyOrigin() 

171 self.assertAlmostEqual(origin.getLongitude().asDegrees(), self.butler_get_data.sky_origin[0]) 

172 self.assertAlmostEqual(origin.getLatitude().asDegrees(), self.butler_get_data.sky_origin[1]) 

173 

174 def test_bias(self): 

175 self._test_exposure('bias') 

176 

177 def test_dark(self): 

178 self._test_exposure('dark') 

179 

180 def test_flat(self): 

181 self._test_exposure('flat') 

182 

183 def test_raw_header_wcs(self): 

184 """Test that `raw_header_wcs` returns the unmodified raw image header. 

185 """ 

186 if self.butler_get_data.raw_header_wcs is not None: 

187 wcs = self.butler.get('raw_header_wcs', self.dataIds['raw']) 

188 self.assertEqual(wcs, self.butler_get_data.raw_header_wcs) 

189 

190 @unittest.skip('Cannot test this, as there is a bug in the butler! DM-8097') 

191 def test_raw_sub_bbox(self): 

192 exp = self.butler.get('raw', self.dataIds['raw'], immediate=True) 

193 bbox = exp.getBBox() 

194 bbox.grow(-1) 

195 sub = self.butler.get("raw_sub", self.dataIds['raw'], bbox=bbox, immediate=True) 

196 self.assertEqual(sub.getImage().getBBox(), bbox) 

197 self.assertImagesEqual(sub, exp.Factory(exp, bbox)) 

198 

199 def test_subset_raw(self): 

200 for kwargs, expect in self.butler_get_data.raw_subsets: 

201 subset = self.butler.subset("raw", **kwargs) 

202 self.assertEqual(len(subset), expect, msg="Failed for kwargs: {}".format(kwargs)) 

203 

204 def test_get_linearizer(self): 

205 """Test that we can get a linearizer for good detectorIds.""" 

206 if self.butler_get_data.linearizer_type is unittest.SkipTest: 

207 self.skipTest('Skipping %s as requested' % (inspect.currentframe().f_code.co_name)) 

208 

209 camera = self.butler.get("camera") 

210 for detectorId in self.butler_get_data.good_detectorIds: 

211 detector = camera[detectorId] 

212 linearizer = self.butler.get("linearizer", dataId=dict(ccd=detectorId), immediate=True) 

213 self.assertEqual(linearizer.LinearityType, self.butler_get_data.linearizer_type[detectorId]) 

214 linearizer.checkDetector(detector) 

215 

216 def test_get_linearizer_bad_detectorIds(self): 

217 """Do bad detectorIds raise?""" 

218 if self.butler_get_data.linearizer_type is unittest.SkipTest: 

219 self.skipTest('Skipping %s as requested' % (inspect.currentframe().f_code.co_name)) 

220 

221 for badccd in self.butler_get_data.bad_detectorIds: 

222 with self.assertRaises(RuntimeError): 

223 self.butler.get("linearizer", dataId=dict(ccd=badccd), immediate=True)