Coverage for python / lsst / daf / butler / dimensions / _skypix.py: 49%

76 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-24 08:17 +0000

1# This file is part of daf_butler. 

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 software is dual licensed under the GNU General Public License and also 

10# under a 3-clause BSD license. Recipients may choose which of these licenses 

11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt, 

12# respectively. If you choose the GPL option then the following text applies 

13# (but note that there is still no warranty even if you opt for BSD instead): 

14# 

15# This program is free software: you can redistribute it and/or modify 

16# it under the terms of the GNU General Public License as published by 

17# the Free Software Foundation, either version 3 of the License, or 

18# (at your option) any later version. 

19# 

20# This program is distributed in the hope that it will be useful, 

21# but WITHOUT ANY WARRANTY; without even the implied warranty of 

22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

23# GNU General Public License for more details. 

24# 

25# You should have received a copy of the GNU General Public License 

26# along with this program. If not, see <http://www.gnu.org/licenses/>. 

27 

28from __future__ import annotations 

29 

30__all__ = ( 

31 "SkyPixDimension", 

32 "SkyPixSystem", 

33) 

34 

35from collections.abc import Iterator, Mapping 

36from types import MappingProxyType 

37from typing import TYPE_CHECKING, cast 

38 

39from lsst.sphgeom import PixelizationABC 

40 

41from .._named import NamedValueAbstractSet, NamedValueSet 

42from .._topology import TopologicalFamily, TopologicalRelationshipEndpoint, TopologicalSpace 

43from ..column_spec import IntColumnSpec 

44from ._elements import Dimension, KeyColumnSpec, MetadataColumnSpec 

45 

46if TYPE_CHECKING: 

47 from ..queries.tree import DimensionFieldReference 

48 from ._group import DimensionGroup 

49 

50 

51class SkyPixSystem(TopologicalFamily): 

52 """Class for hierarchical pixelization of the sky. 

53 

54 A `TopologicalFamily` that represents a hierarchical pixelization of the 

55 sky. 

56 

57 Parameters 

58 ---------- 

59 name : `str` 

60 Name of the system. 

61 maxLevel : `int` 

62 Maximum level (inclusive) of the hierarchy. 

63 PixelizationClass : `type` (`lsst.sphgeom.PixelizationABC` subclass) 

64 Class whose instances represent a particular level of this 

65 pixelization. 

66 """ 

67 

68 def __init__( 

69 self, 

70 name: str, 

71 *, 

72 maxLevel: int, 

73 PixelizationClass: type[PixelizationABC], 

74 ): 

75 super().__init__(name, TopologicalSpace.SPATIAL) 

76 self.maxLevel = maxLevel 

77 self.PixelizationClass = PixelizationClass 

78 self._members: dict[int, SkyPixDimension] = {} 

79 for level in range(maxLevel + 1): 

80 self._members[level] = SkyPixDimension(self, level) 

81 

82 def choose(self, dimensions: DimensionGroup) -> SkyPixDimension: 

83 # Docstring inherited from TopologicalFamily. 

84 best: SkyPixDimension | None = None 

85 for endpoint_name in dimensions.skypix: 

86 endpoint = dimensions.universe[endpoint_name] 

87 if endpoint not in self: 

88 continue 

89 assert isinstance(endpoint, SkyPixDimension) 

90 if best is None or best.level < endpoint.level: 

91 best = endpoint 

92 if best is None: 

93 raise RuntimeError(f"No recognized endpoints for {self.name} in {dimensions}.") 

94 return best 

95 

96 def __getitem__(self, level: int) -> SkyPixDimension: 

97 return self._members[level] 

98 

99 def __iter__(self) -> Iterator[SkyPixDimension]: 

100 return iter(self._members.values()) 

101 

102 def __len__(self) -> int: 

103 return len(self._members) 

104 

105 def make_column_reference(self, endpoint: TopologicalRelationshipEndpoint) -> DimensionFieldReference: 

106 from ..queries.tree import DimensionFieldReference 

107 

108 return DimensionFieldReference(element=cast(SkyPixDimension, endpoint), field="region") 

109 

110 

111class SkyPixDimension(Dimension): 

112 """Special dimension for sky pixelizations. 

113 

114 A special `Dimension` subclass for hierarchical pixelizations of the 

115 sky at a particular level. 

116 

117 Unlike most other dimensions, skypix dimension records are not stored in 

118 the database, as these records only contain an integer pixel ID and a 

119 region on the sky, and each of these can be computed directly from the 

120 other. 

121 

122 Parameters 

123 ---------- 

124 system : `SkyPixSystem` 

125 Pixelization system this dimension belongs to. 

126 level : `int` 

127 Integer level of this pixelization (smaller numbers are coarser grids). 

128 """ 

129 

130 def __init__(self, system: SkyPixSystem, level: int): 

131 self.system = system 

132 self.level = level 

133 self.pixelization = system.PixelizationClass(level) 

134 

135 @property 

136 def name(self) -> str: 

137 return f"{self.system.name}{self.level}" 

138 

139 @property 

140 def required(self) -> NamedValueAbstractSet[Dimension]: 

141 # Docstring inherited from DimensionElement. 

142 return NamedValueSet({self}).freeze() 

143 

144 @property 

145 def implied(self) -> NamedValueAbstractSet[Dimension]: 

146 # Docstring inherited from DimensionElement. 

147 return NamedValueSet().freeze() 

148 

149 @property 

150 def topology(self) -> Mapping[TopologicalSpace, TopologicalFamily]: 

151 # Docstring inherited from TopologicalRelationshipEndpoint 

152 return MappingProxyType({TopologicalSpace.SPATIAL: self.system}) 

153 

154 @property 

155 def metadata_columns(self) -> NamedValueAbstractSet[MetadataColumnSpec]: 

156 # Docstring inherited from DimensionElement. 

157 return NamedValueSet().freeze() 

158 

159 @property 

160 def documentation(self) -> str: 

161 # Docstring inherited from DimensionElement. 

162 return f"Level {self.level} of the {self.system.name!r} sky pixelization system." 

163 

164 def hasTable(self) -> bool: 

165 # Docstring inherited from DimensionElement.hasTable. 

166 return False 

167 

168 @property 

169 def has_own_table(self) -> bool: 

170 # Docstring inherited from DimensionElement. 

171 return False 

172 

173 @property 

174 def unique_keys(self) -> NamedValueAbstractSet[KeyColumnSpec]: 

175 # Docstring inherited from DimensionElement. 

176 return NamedValueSet([IntColumnSpec(name="id", nullable=False)]).freeze() 

177 

178 # Class attributes below are shadowed by instance attributes, and are 

179 # present just to hold the docstrings for those instance attributes. 

180 

181 system: SkyPixSystem 

182 """Pixelization system this dimension belongs to (`SkyPixSystem`). 

183 """ 

184 

185 level: int 

186 """Integer level of this pixelization (smaller numbers are coarser grids). 

187 """ 

188 

189 pixelization: PixelizationABC 

190 """Pixelization instance that can compute regions from IDs and IDs from 

191 points (`sphgeom.PixelizationABC`). 

192 """