Coverage for tests/test_packer.py: 24%

87 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-11 20:01 +0000

1# This file is part of obs_lsst. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://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 <http://www.gnu.org/licenses/>. 

21 

22import unittest 

23 

24from lsst.daf.butler import DataCoordinate, RegistryConfig 

25from lsst.daf.butler.registry.sql_registry import SqlRegistry 

26from lsst.obs.lsst import ( 

27 Latiss, 

28 LsstCam, 

29 LsstCamImSim, 

30 LsstCamPhoSim, 

31 LsstComCam, 

32 LsstTS3, 

33 LsstTS8, 

34 LsstUCDCam, 

35 RubinDimensionPacker, 

36) 

37from lsst.pex.config import Config 

38from lsst.pipe.base import Instrument, ObservationDimensionPacker 

39 

40 

41class _TestConfig(Config): 

42 packer = Instrument.make_dimension_packer_config_field() 

43 

44 

45class RubinDimensionPackerTestCase(unittest.TestCase): 

46 """Test the custom data ID packer implementation for the main Rubin 

47 instruments. 

48 

49 This test mostly checks the data ID packer's methods for self-consistency, 

50 and that the Instrument-class overrides work as expected. Direct tests of 

51 The packing algorithm is tested against hard-coded values in 

52 test_translators.py, since some translators now delegate to it. 

53 """ 

54 

55 def setUp(self) -> None: 

56 registry_config = RegistryConfig() 

57 registry_config["db"] = "sqlite://" 

58 self.registry = SqlRegistry.createFromConfig(registry_config) 

59 self.rubin_packer_instruments = [LsstCam, LsstComCam, Latiss] 

60 self.old_packer_instruments = [ 

61 LsstCamImSim, 

62 LsstCamPhoSim, 

63 LsstTS8, 

64 LsstTS3, 

65 LsstUCDCam, 

66 ] 

67 for cls in self.rubin_packer_instruments + self.old_packer_instruments: 

68 cls().register(self.registry) 

69 

70 def check_rubin_dimension_packer( 

71 self, 

72 instrument: Instrument, 

73 is_exposure: bool, 

74 *, 

75 exposure_id: int, 

76 day_obs: int, 

77 seq_num: int, 

78 detector: int, 

79 controller: str = "O", 

80 is_one_to_one_reinterpretation: bool = False, 

81 visit_id: int | None = None, 

82 ) -> None: 

83 """Run tests on an instrument that uses the new Rubin dimension packer. 

84 

85 Parameters 

86 ---------- 

87 instrument : `lsst.pipe.base.Instrument` 

88 Instrument instance to be tested. 

89 is_exposure : `bool` 

90 `True` to pack ``{detector, exposure}`` data IDs, `False` to pack 

91 ``{detector, visit}`` data IDs. 

92 exposure_id : `int` 

93 Integer data ID. 

94 day_obs : `int` 

95 Date of observations as a YYYYMMDD decimal integer, consistent with 

96 ``exposure_id``. 

97 seq_num : `int` 

98 Instrument sequence number, consistent with ``exposure_id``. 

99 detector : `int` 

100 Integer detector data ID value. 

101 controller : `str`, optional 

102 Controller code consistent with ``exposure_id``. 

103 is_one_to_one_reinterpretatation : `bool`, optional 

104 If `True`, this is a visit ID that represents the alternate 

105 interpretation of that exposure (which must be the first snap in a 

106 multi-snap sequence) as a standalone visit. 

107 visit_id : `int` 

108 Integer visit ID. Must be provided only if 

109 ``is_one_to_one_reinterpretatation=True``; otherwise this is the 

110 same as ``exposure_id``. 

111 """ 

112 if visit_id is None: 

113 assert ( 

114 not is_one_to_one_reinterpretation 

115 ), "Test should not infer visit_id in this case." 

116 visit_id = exposure_id 

117 instrument_data_id = self.registry.expandDataId(instrument=instrument.getName()) 

118 config = _TestConfig() 

119 packer = config.packer.apply(instrument_data_id, is_exposure=is_exposure) 

120 self.assertIsInstance(packer, RubinDimensionPacker) 

121 self.assertEqual(packer.maxBits, 41) 

122 full_data_id = DataCoordinate.standardize( 

123 instrument_data_id, exposure=exposure_id, visit=visit_id, detector=detector 

124 ) 

125 packed1 = RubinDimensionPacker.pack_decomposition( 

126 day_obs, 

127 seq_num, 

128 detector, 

129 controller, 

130 is_one_to_one_reinterpretation=is_one_to_one_reinterpretation, 

131 ) 

132 packed2 = RubinDimensionPacker.pack_id_pair( 

133 exposure_id, 

134 detector, 

135 is_one_to_one_reinterpretation=is_one_to_one_reinterpretation, 

136 ) 

137 packed3 = packer.pack(full_data_id) 

138 self.assertEqual(packed1, packed2) 

139 self.assertEqual(packed1, packed3) 

140 ( 

141 u_day_obs, 

142 u_seq_num, 

143 u_detector, 

144 u_controller, 

145 u_is_one_to_one_reinterpretation, 

146 ) = RubinDimensionPacker.unpack_decomposition(packed1) 

147 self.assertEqual(u_day_obs, day_obs) 

148 self.assertEqual(u_seq_num, seq_num) 

149 self.assertEqual(u_detector, detector) 

150 self.assertEqual(u_controller, controller) 

151 self.assertEqual(u_is_one_to_one_reinterpretation, is_one_to_one_reinterpretation) 

152 ( 

153 u_exposure_id, 

154 u_detector, 

155 u_is_one_to_one_reinterpretation, 

156 ) = RubinDimensionPacker.unpack_id_pair(packed1) 

157 self.assertEqual(u_exposure_id, exposure_id) 

158 self.assertEqual(u_detector, detector) 

159 self.assertEqual(u_is_one_to_one_reinterpretation, is_one_to_one_reinterpretation) 

160 u_data_id = packer.unpack(packed1) 

161 self.assertEqual(u_data_id, full_data_id.subset(packer.dimensions)) 

162 

163 def check_old_dimension_packer( 

164 self, 

165 instrument: Instrument, 

166 is_exposure: bool, 

167 ) -> None: 

168 """Test that an Instrument's default dimension packer is still 

169 `lsst.pipe.base.ObservationDimensionPacker`. 

170 """ 

171 instrument_data_id = self.registry.expandDataId(instrument=instrument.getName()) 

172 config = _TestConfig() 

173 packer = config.packer.apply(instrument_data_id, is_exposure=is_exposure) 

174 # This instrument still uses the pipe_base default dimension packer, 

175 # which is tested there. Nothing more to do here. 

176 self.assertIsInstance(packer, ObservationDimensionPacker) 

177 

178 def test_latiss(self): 

179 instrument = Latiss() 

180 instrument.register(self.registry) 

181 # Input values obtained from: 

182 # $ butler query-dimension-records /repo/main exposure --where \ 

183 # "instrument='LATISS'" --limit 1 

184 self.check_rubin_dimension_packer( 

185 instrument, 

186 is_exposure=True, 

187 exposure_id=2022062800004, 

188 day_obs=20220628, 

189 seq_num=4, 

190 detector=0, 

191 ) 

192 # Input values obtained from: 

193 # $ butler query-dimension-records /repo/main visit --where \ 

194 # "instrument='LATISS'" --limit 1 

195 self.check_rubin_dimension_packer( 

196 instrument, 

197 is_exposure=False, 

198 exposure_id=2021090800749, 

199 day_obs=20210908, 

200 seq_num=749, 

201 detector=0, 

202 ) 

203 # Input data obtained from: 

204 # $ butler query-dimension-records /repo/embargo visit --where \ 

205 # "instrument='LATISS' AND visit_system=0 AND exposure != visit" \ 

206 # --limit 1 

207 self.check_rubin_dimension_packer( 

208 instrument, 

209 is_exposure=False, 

210 exposure_id=2022101101105, 

211 day_obs=20221011, 

212 seq_num=1105, 

213 detector=0, 

214 visit_id=92022101101105, 

215 is_one_to_one_reinterpretation=True, 

216 ) 

217 

218 def test_lsstCam(self): 

219 instrument = LsstCam() 

220 instrument.register(self.registry) 

221 # Input values obtained from: 

222 # $ butler query-dimension-records /repo/main exposure --where \ 

223 # "instrument='LSSTCam'" --limit 1 

224 self.check_rubin_dimension_packer( 

225 instrument, 

226 is_exposure=True, 

227 exposure_id=3021121400075, 

228 day_obs=20211214, 

229 seq_num=75, 

230 detector=150, 

231 controller="C", 

232 ) 

233 

234 def test_comCam(self): 

235 instrument = LsstComCam() 

236 instrument.register(self.registry) 

237 # Input values obtained from: 

238 # $ butler query-dimension-records /repo/main exposure --where \ 

239 # "instrument='LSSTComCam'" --limit 1 

240 self.check_rubin_dimension_packer( 

241 instrument, 

242 is_exposure=True, 

243 exposure_id=2020091100004, 

244 day_obs=20200911, 

245 seq_num=4, 

246 detector=5, 

247 ) 

248 

249 def test_imsim(self): 

250 instrument = LsstCamImSim() 

251 instrument.register(self.registry) 

252 self.check_old_dimension_packer(instrument, is_exposure=True) 

253 self.check_old_dimension_packer(instrument, is_exposure=False) 

254 

255 def test_phosim(self): 

256 instrument = LsstCamPhoSim() 

257 instrument.register(self.registry) 

258 self.check_old_dimension_packer(instrument, is_exposure=True) 

259 self.check_old_dimension_packer(instrument, is_exposure=False) 

260 

261 def test_ts3(self): 

262 instrument = LsstTS3() 

263 instrument.register(self.registry) 

264 self.check_old_dimension_packer(instrument, is_exposure=True) 

265 

266 def test_ts8(self): 

267 instrument = LsstTS8() 

268 instrument.register(self.registry) 

269 self.check_old_dimension_packer(instrument, is_exposure=True) 

270 

271 def test_ucdcam(self): 

272 instrument = LsstUCDCam() 

273 instrument.register(self.registry) 

274 self.check_old_dimension_packer(instrument, is_exposure=True) 

275 

276 

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

278 unittest.main()