Coverage for tests/test_packer.py: 24%

95 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-15 02:34 -0700

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 LsstCamSim, 

32 LsstComCam, 

33 LsstComCamSim, 

34 LsstTS3, 

35 LsstTS8, 

36 LsstUCDCam, 

37 RubinDimensionPacker, 

38) 

39from lsst.pex.config import Config 

40from lsst.pipe.base import Instrument, ObservationDimensionPacker 

41 

42 

43class _TestConfig(Config): 

44 packer = Instrument.make_dimension_packer_config_field() 

45 

46 

47class RubinDimensionPackerTestCase(unittest.TestCase): 

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

49 instruments. 

50 

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

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

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

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

55 """ 

56 

57 def setUp(self) -> None: 

58 registry_config = RegistryConfig() 

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

60 self.registry = SqlRegistry.createFromConfig(registry_config) 

61 self.rubin_packer_instruments = [LsstCam, LsstComCam, LsstComCamSim, 

62 Latiss] 

63 self.old_packer_instruments = [ 

64 LsstCamImSim, 

65 LsstCamPhoSim, 

66 LsstTS8, 

67 LsstTS3, 

68 LsstUCDCam, 

69 ] 

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

71 cls().register(self.registry) 

72 

73 def check_rubin_dimension_packer( 

74 self, 

75 instrument: Instrument, 

76 is_exposure: bool, 

77 *, 

78 exposure_id: int, 

79 day_obs: int, 

80 seq_num: int, 

81 detector: int, 

82 controller: str = "O", 

83 is_one_to_one_reinterpretation: bool = False, 

84 visit_id: int | None = None, 

85 ) -> None: 

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

87 

88 Parameters 

89 ---------- 

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

91 Instrument instance to be tested. 

92 is_exposure : `bool` 

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

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

95 exposure_id : `int` 

96 Integer data ID. 

97 day_obs : `int` 

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

99 ``exposure_id``. 

100 seq_num : `int` 

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

102 detector : `int` 

103 Integer detector data ID value. 

104 controller : `str`, optional 

105 Controller code consistent with ``exposure_id``. 

106 is_one_to_one_reinterpretation : `bool`, optional 

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

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

109 multi-snap sequence) as a standalone visit. 

110 visit_id : `int` 

111 Integer visit ID. Must be provided only if 

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

113 same as ``exposure_id``. 

114 """ 

115 if visit_id is None: 

116 assert ( 

117 not is_one_to_one_reinterpretation 

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

119 visit_id = exposure_id 

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

121 config = _TestConfig() 

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

123 self.assertIsInstance(packer, RubinDimensionPacker) 

124 self.assertEqual(packer.maxBits, 41) 

125 full_data_id = DataCoordinate.standardize( 

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

127 ) 

128 packed1 = RubinDimensionPacker.pack_decomposition( 

129 day_obs, 

130 seq_num, 

131 detector, 

132 controller, 

133 is_one_to_one_reinterpretation=is_one_to_one_reinterpretation, 

134 ) 

135 packed2 = RubinDimensionPacker.pack_id_pair( 

136 exposure_id, 

137 detector, 

138 is_one_to_one_reinterpretation=is_one_to_one_reinterpretation, 

139 ) 

140 packed3 = packer.pack(full_data_id) 

141 self.assertEqual(packed1, packed2) 

142 self.assertEqual(packed1, packed3) 

143 ( 

144 u_day_obs, 

145 u_seq_num, 

146 u_detector, 

147 u_controller, 

148 u_is_one_to_one_reinterpretation, 

149 ) = RubinDimensionPacker.unpack_decomposition(packed1) 

150 self.assertEqual(u_day_obs, day_obs) 

151 self.assertEqual(u_seq_num, seq_num) 

152 self.assertEqual(u_detector, detector) 

153 self.assertEqual(u_controller, controller) 

154 self.assertEqual(u_is_one_to_one_reinterpretation, is_one_to_one_reinterpretation) 

155 ( 

156 u_exposure_id, 

157 u_detector, 

158 u_is_one_to_one_reinterpretation, 

159 ) = RubinDimensionPacker.unpack_id_pair(packed1) 

160 self.assertEqual(u_exposure_id, exposure_id) 

161 self.assertEqual(u_detector, detector) 

162 self.assertEqual(u_is_one_to_one_reinterpretation, is_one_to_one_reinterpretation) 

163 u_data_id = packer.unpack(packed1) 

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

165 

166 def check_old_dimension_packer( 

167 self, 

168 instrument: Instrument, 

169 is_exposure: bool, 

170 ) -> None: 

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

172 `lsst.pipe.base.ObservationDimensionPacker`. 

173 """ 

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

175 config = _TestConfig() 

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

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

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

179 self.assertIsInstance(packer, ObservationDimensionPacker) 

180 

181 def test_latiss(self): 

182 instrument = Latiss() 

183 instrument.register(self.registry) 

184 # Input values obtained from: 

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

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

187 self.check_rubin_dimension_packer( 

188 instrument, 

189 is_exposure=True, 

190 exposure_id=2022062800004, 

191 day_obs=20220628, 

192 seq_num=4, 

193 detector=0, 

194 ) 

195 # Input values obtained from: 

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

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

198 self.check_rubin_dimension_packer( 

199 instrument, 

200 is_exposure=False, 

201 exposure_id=2021090800749, 

202 day_obs=20210908, 

203 seq_num=749, 

204 detector=0, 

205 ) 

206 # Input data obtained from: 

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

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

209 # --limit 1 

210 self.check_rubin_dimension_packer( 

211 instrument, 

212 is_exposure=False, 

213 exposure_id=2022101101105, 

214 day_obs=20221011, 

215 seq_num=1105, 

216 detector=0, 

217 visit_id=92022101101105, 

218 is_one_to_one_reinterpretation=True, 

219 ) 

220 

221 def test_lsstCam(self): 

222 instrument = LsstCam() 

223 instrument.register(self.registry) 

224 # Input values obtained from: 

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

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

227 self.check_rubin_dimension_packer( 

228 instrument, 

229 is_exposure=True, 

230 exposure_id=3021121400075, 

231 day_obs=20211214, 

232 seq_num=75, 

233 detector=150, 

234 controller="C", 

235 ) 

236 

237 def test_comCam(self): 

238 instrument = LsstComCam() 

239 instrument.register(self.registry) 

240 # Input values obtained from: 

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

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

243 self.check_rubin_dimension_packer( 

244 instrument, 

245 is_exposure=True, 

246 exposure_id=2020091100004, 

247 day_obs=20200911, 

248 seq_num=4, 

249 detector=5, 

250 ) 

251 

252 def test_comCamSim(self): 

253 instrument = LsstComCamSim() 

254 instrument.register(self.registry) 

255 # Input values obtained from: 

256 # $ butler query-dimension-records data/input/comCamSim exposure \ 

257 # --where "instrument='LSSTComCamSim'" --limit 1 

258 self.check_rubin_dimension_packer( 

259 instrument, 

260 is_exposure=False, 

261 exposure_id=7024032100720, 

262 day_obs=20240321, 

263 seq_num=720, 

264 detector=4, 

265 controller="S" 

266 ) 

267 

268 def test_lsstCamSim(self): 

269 instrument = LsstCamSim() 

270 instrument.register(self.registry) 

271 # Input values obtained from: 

272 # $ butler query-dimension-records data/input/lsstCamSim exposure \ 

273 # --where "instrument='LSSTCamSim'" --limit 1 

274 self.check_rubin_dimension_packer( 

275 instrument, 

276 is_exposure=True, 

277 exposure_id=7024032100720, 

278 day_obs=20240321, 

279 seq_num=720, 

280 detector=94, 

281 controller="S", 

282 ) 

283 

284 def test_imsim(self): 

285 instrument = LsstCamImSim() 

286 instrument.register(self.registry) 

287 self.check_old_dimension_packer(instrument, is_exposure=True) 

288 self.check_old_dimension_packer(instrument, is_exposure=False) 

289 

290 def test_phosim(self): 

291 instrument = LsstCamPhoSim() 

292 instrument.register(self.registry) 

293 self.check_old_dimension_packer(instrument, is_exposure=True) 

294 self.check_old_dimension_packer(instrument, is_exposure=False) 

295 

296 def test_ts3(self): 

297 instrument = LsstTS3() 

298 instrument.register(self.registry) 

299 self.check_old_dimension_packer(instrument, is_exposure=True) 

300 

301 def test_ts8(self): 

302 instrument = LsstTS8() 

303 instrument.register(self.registry) 

304 self.check_old_dimension_packer(instrument, is_exposure=True) 

305 

306 def test_ucdcam(self): 

307 instrument = LsstUCDCam() 

308 instrument.register(self.registry) 

309 self.check_old_dimension_packer(instrument, is_exposure=True) 

310 

311 

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

313 unittest.main()