Coverage for tests/test_packer.py: 24%
95 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-26 11:36 +0000
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-26 11:36 +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/>.
22import unittest
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
43class _TestConfig(Config):
44 packer = Instrument.make_dimension_packer_config_field()
47class RubinDimensionPackerTestCase(unittest.TestCase):
48 """Test the custom data ID packer implementation for the main Rubin
49 instruments.
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 """
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)
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.
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))
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)
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 )
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 )
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 )
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 )
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 )
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)
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)
296 def test_ts3(self):
297 instrument = LsstTS3()
298 instrument.register(self.registry)
299 self.check_old_dimension_packer(instrument, is_exposure=True)
301 def test_ts8(self):
302 instrument = LsstTS8()
303 instrument.register(self.registry)
304 self.check_old_dimension_packer(instrument, is_exposure=True)
306 def test_ucdcam(self):
307 instrument = LsstUCDCam()
308 instrument.register(self.registry)
309 self.check_old_dimension_packer(instrument, is_exposure=True)
312if __name__ == "__main__": 312 ↛ 313line 312 didn't jump to line 313, because the condition on line 312 was never true
313 unittest.main()