Coverage for tests/test_packer.py: 24%

91 statements  

« prev     ^ index     » next       coverage.py v7.4.3, created at 2024-03-01 14:58 +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 LsstComCamSim, 

33 LsstTS3, 

34 LsstTS8, 

35 LsstUCDCam, 

36 RubinDimensionPacker, 

37) 

38from lsst.pex.config import Config 

39from lsst.pipe.base import Instrument, ObservationDimensionPacker 

40 

41 

42class _TestConfig(Config): 

43 packer = Instrument.make_dimension_packer_config_field() 

44 

45 

46class RubinDimensionPackerTestCase(unittest.TestCase): 

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

48 instruments. 

49 

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

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

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

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

54 """ 

55 

56 def setUp(self) -> None: 

57 registry_config = RegistryConfig() 

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

59 self.registry = SqlRegistry.createFromConfig(registry_config) 

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

61 Latiss] 

62 self.old_packer_instruments = [ 

63 LsstCamImSim, 

64 LsstCamPhoSim, 

65 LsstTS8, 

66 LsstTS3, 

67 LsstUCDCam, 

68 ] 

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

70 cls().register(self.registry) 

71 

72 def check_rubin_dimension_packer( 

73 self, 

74 instrument: Instrument, 

75 is_exposure: bool, 

76 *, 

77 exposure_id: int, 

78 day_obs: int, 

79 seq_num: int, 

80 detector: int, 

81 controller: str = "O", 

82 is_one_to_one_reinterpretation: bool = False, 

83 visit_id: int | None = None, 

84 ) -> None: 

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

86 

87 Parameters 

88 ---------- 

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

90 Instrument instance to be tested. 

91 is_exposure : `bool` 

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

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

94 exposure_id : `int` 

95 Integer data ID. 

96 day_obs : `int` 

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

98 ``exposure_id``. 

99 seq_num : `int` 

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

101 detector : `int` 

102 Integer detector data ID value. 

103 controller : `str`, optional 

104 Controller code consistent with ``exposure_id``. 

105 is_one_to_one_reinterpretatation : `bool`, optional 

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

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

108 multi-snap sequence) as a standalone visit. 

109 visit_id : `int` 

110 Integer visit ID. Must be provided only if 

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

112 same as ``exposure_id``. 

113 """ 

114 if visit_id is None: 

115 assert ( 

116 not is_one_to_one_reinterpretation 

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

118 visit_id = exposure_id 

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

120 config = _TestConfig() 

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

122 self.assertIsInstance(packer, RubinDimensionPacker) 

123 self.assertEqual(packer.maxBits, 41) 

124 full_data_id = DataCoordinate.standardize( 

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

126 ) 

127 packed1 = RubinDimensionPacker.pack_decomposition( 

128 day_obs, 

129 seq_num, 

130 detector, 

131 controller, 

132 is_one_to_one_reinterpretation=is_one_to_one_reinterpretation, 

133 ) 

134 packed2 = RubinDimensionPacker.pack_id_pair( 

135 exposure_id, 

136 detector, 

137 is_one_to_one_reinterpretation=is_one_to_one_reinterpretation, 

138 ) 

139 packed3 = packer.pack(full_data_id) 

140 self.assertEqual(packed1, packed2) 

141 self.assertEqual(packed1, packed3) 

142 ( 

143 u_day_obs, 

144 u_seq_num, 

145 u_detector, 

146 u_controller, 

147 u_is_one_to_one_reinterpretation, 

148 ) = RubinDimensionPacker.unpack_decomposition(packed1) 

149 self.assertEqual(u_day_obs, day_obs) 

150 self.assertEqual(u_seq_num, seq_num) 

151 self.assertEqual(u_detector, detector) 

152 self.assertEqual(u_controller, controller) 

153 self.assertEqual(u_is_one_to_one_reinterpretation, is_one_to_one_reinterpretation) 

154 ( 

155 u_exposure_id, 

156 u_detector, 

157 u_is_one_to_one_reinterpretation, 

158 ) = RubinDimensionPacker.unpack_id_pair(packed1) 

159 self.assertEqual(u_exposure_id, exposure_id) 

160 self.assertEqual(u_detector, detector) 

161 self.assertEqual(u_is_one_to_one_reinterpretation, is_one_to_one_reinterpretation) 

162 u_data_id = packer.unpack(packed1) 

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

164 

165 def check_old_dimension_packer( 

166 self, 

167 instrument: Instrument, 

168 is_exposure: bool, 

169 ) -> None: 

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

171 `lsst.pipe.base.ObservationDimensionPacker`. 

172 """ 

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

174 config = _TestConfig() 

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

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

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

178 self.assertIsInstance(packer, ObservationDimensionPacker) 

179 

180 def test_latiss(self): 

181 instrument = Latiss() 

182 instrument.register(self.registry) 

183 # Input values obtained from: 

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

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

186 self.check_rubin_dimension_packer( 

187 instrument, 

188 is_exposure=True, 

189 exposure_id=2022062800004, 

190 day_obs=20220628, 

191 seq_num=4, 

192 detector=0, 

193 ) 

194 # Input values obtained from: 

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

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

197 self.check_rubin_dimension_packer( 

198 instrument, 

199 is_exposure=False, 

200 exposure_id=2021090800749, 

201 day_obs=20210908, 

202 seq_num=749, 

203 detector=0, 

204 ) 

205 # Input data obtained from: 

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

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

208 # --limit 1 

209 self.check_rubin_dimension_packer( 

210 instrument, 

211 is_exposure=False, 

212 exposure_id=2022101101105, 

213 day_obs=20221011, 

214 seq_num=1105, 

215 detector=0, 

216 visit_id=92022101101105, 

217 is_one_to_one_reinterpretation=True, 

218 ) 

219 

220 def test_lsstCam(self): 

221 instrument = LsstCam() 

222 instrument.register(self.registry) 

223 # Input values obtained from: 

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

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

226 self.check_rubin_dimension_packer( 

227 instrument, 

228 is_exposure=True, 

229 exposure_id=3021121400075, 

230 day_obs=20211214, 

231 seq_num=75, 

232 detector=150, 

233 controller="C", 

234 ) 

235 

236 def test_comCam(self): 

237 instrument = LsstComCam() 

238 instrument.register(self.registry) 

239 # Input values obtained from: 

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

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

242 self.check_rubin_dimension_packer( 

243 instrument, 

244 is_exposure=True, 

245 exposure_id=2020091100004, 

246 day_obs=20200911, 

247 seq_num=4, 

248 detector=5, 

249 ) 

250 

251 def test_comCamSim(self): 

252 instrument = LsstComCamSim() 

253 instrument.register(self.registry) 

254 # Input values obtained from: 

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

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

257 self.check_rubin_dimension_packer( 

258 instrument, 

259 is_exposure=False, 

260 exposure_id=7024032100720, 

261 day_obs=20240321, 

262 seq_num=720, 

263 detector=4, 

264 controller="S" 

265 ) 

266 

267 def test_imsim(self): 

268 instrument = LsstCamImSim() 

269 instrument.register(self.registry) 

270 self.check_old_dimension_packer(instrument, is_exposure=True) 

271 self.check_old_dimension_packer(instrument, is_exposure=False) 

272 

273 def test_phosim(self): 

274 instrument = LsstCamPhoSim() 

275 instrument.register(self.registry) 

276 self.check_old_dimension_packer(instrument, is_exposure=True) 

277 self.check_old_dimension_packer(instrument, is_exposure=False) 

278 

279 def test_ts3(self): 

280 instrument = LsstTS3() 

281 instrument.register(self.registry) 

282 self.check_old_dimension_packer(instrument, is_exposure=True) 

283 

284 def test_ts8(self): 

285 instrument = LsstTS8() 

286 instrument.register(self.registry) 

287 self.check_old_dimension_packer(instrument, is_exposure=True) 

288 

289 def test_ucdcam(self): 

290 instrument = LsstUCDCam() 

291 instrument.register(self.registry) 

292 self.check_old_dimension_packer(instrument, is_exposure=True) 

293 

294 

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

296 unittest.main()