Coverage for tests/test_id_generator.py: 28%

59 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-07 10:11 +0000

1# This file is part of meas_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 unittest 

23from typing import Callable 

24 

25from lsst.pex.config import Config 

26from lsst.afw.table import SourceTable 

27from lsst.daf.butler import DimensionUniverse, DataCoordinate 

28from lsst.meas.base import ( 

29 IdGenerator, 

30 DetectorVisitIdGeneratorConfig, 

31 DetectorExposureIdGeneratorConfig, 

32 SkyMapIdGeneratorConfig, 

33) 

34 

35 

36class _TestConfig(Config): 

37 skymap = SkyMapIdGeneratorConfig.make_field() 

38 visit = DetectorVisitIdGeneratorConfig.make_field() 

39 exposure = DetectorExposureIdGeneratorConfig.make_field() 

40 

41 

42class IdGeneratorTestCase(unittest.TestCase): 

43 """Tests for the IdGenerator class and its config-based construction 

44 pattern. 

45 """ 

46 

47 def setUp(self): 

48 self.schema = SourceTable.makeMinimalSchema() 

49 self.universe = DimensionUniverse() 

50 

51 def test_no_packer(self): 

52 """Test a simple IdGenerator that doesn't embed anything.""" 

53 id_gen = IdGenerator() 

54 self.check_invariants(id_gen) 

55 

56 def test_visit(self): 

57 """Test an IdGenerator that packs {visit, detector} data IDs.""" 

58 data_id = DataCoordinate.standardize( 

59 instrument="I", 

60 visit=312, 

61 detector=5, 

62 universe=self.universe, 

63 ) 

64 config = _TestConfig() 

65 config.visit.packer.name = "observation" 

66 config.visit.packer["observation"].n_observations = 10000 

67 config.visit.packer["observation"].n_detectors = 99 

68 config.visit.n_releases = 8 

69 config.visit.release_id = 2 

70 id_generator = config.visit.apply(data_id) 

71 self.check_invariants( 

72 id_generator, 

73 unpacker=IdGenerator.unpacker_from_config( 

74 config.visit, data_id.subset(self.universe.conform(["instrument"])) 

75 ), 

76 expected_release_id=2, 

77 ) 

78 

79 def test_exposure(self): 

80 """Test an IdGenerator that packs {exposure, detector} data IDs.""" 

81 data_id = DataCoordinate.standardize( 

82 instrument="I", 

83 exposure=312, 

84 detector=5, 

85 universe=self.universe, 

86 ) 

87 config = _TestConfig() 

88 config.exposure.packer.name = "observation" 

89 config.exposure.packer["observation"].n_observations = 10000 

90 config.exposure.packer["observation"].n_detectors = 99 

91 config.exposure.n_releases = 4 

92 config.exposure.release_id = 3 

93 id_generator = config.exposure.apply(data_id) 

94 self.check_invariants( 

95 id_generator, 

96 unpacker=IdGenerator.unpacker_from_config( 

97 config.exposure, data_id.subset(self.universe.conform(["instrument"])) 

98 ), 

99 expected_release_id=3, 

100 ) 

101 

102 def test_skymap(self): 

103 """Test an IdGenerator that packs {tract, patch, band} data IDs.""" 

104 config = _TestConfig() 

105 config.skymap.packer.n_tracts = 11 

106 config.skymap.packer.n_patches = 9 

107 data_id = DataCoordinate.standardize( 

108 skymap="S", tract=9, patch=5, band="r", universe=self.universe 

109 ) 

110 id_generator = config.skymap.apply(data_id) 

111 self.check_invariants( 

112 id_generator, 

113 unpacker=IdGenerator.unpacker_from_config( 

114 config.skymap, data_id.subset(self.universe.conform(["skymap"])) 

115 ), 

116 ) 

117 

118 def check_invariants( 

119 self, 

120 id_gen: IdGenerator, 

121 unpacker: Callable[[int], tuple[DataCoordinate, int]] | None = None, 

122 expected_release_id: int = 0, 

123 ): 

124 """Check methods of the `IdGenerator` class for self-consistency and 

125 expected values. 

126 """ 

127 catalog = id_gen.make_source_catalog(self.schema) 

128 for _ in range(5): 

129 catalog.addNew() 

130 array = id_gen.arange(1, 6) 

131 self.assertEqual(list(catalog["id"]), list(array)) 

132 if unpacker is not None: 

133 expected_data_id = id_gen.data_id 

134 for i in range(5): 

135 embedded_release_id, embedded_data_id, counter = unpacker(array[i]) 

136 self.assertEqual(counter, i + 1) 

137 self.assertEqual(embedded_data_id, expected_data_id) 

138 self.assertEqual(embedded_release_id, expected_release_id) 

139 

140 

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

142 unittest.main()