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

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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 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/>.
22from __future__ import annotations
24__all__ = (
25 "SkyPixDimension",
26 "SkyPixSystem",
27)
29from types import MappingProxyType
30from typing import (
31 AbstractSet,
32 Dict,
33 Mapping,
34 Optional,
35 Type,
36 TYPE_CHECKING,
37)
39import sqlalchemy
41from lsst.sphgeom import Pixelization
42from lsst.utils import doImport
43from .. import ddl
44from .._topology import TopologicalFamily, TopologicalRelationshipEndpoint, TopologicalSpace
46from ..named import NamedValueAbstractSet, NamedValueSet
47from ._elements import Dimension
48from .construction import DimensionConstructionBuilder, DimensionConstructionVisitor
50if TYPE_CHECKING: 50 ↛ 51line 50 didn't jump to line 51, because the condition on line 50 was never true
51 from ...registry.interfaces import SkyPixDimensionRecordStorage
54class SkyPixSystem(TopologicalFamily):
55 """A `TopologicalFamily` that represents a hierarchical pixelization of the
56 sky.
58 Parameters
59 ----------
60 name : `str`
61 Name of the system.
62 maxLevel : `int`
63 Maximum level (inclusive) of the hierarchy.
64 PixelizationClass : `type` (`lsst.sphgeom.Pixelization` subclass)
65 Class whose instances represent a particular level of this
66 pixelization.
67 """
68 def __init__(
69 self,
70 name: str, *,
71 maxLevel: int,
72 PixelizationClass: Type[Pixelization],
73 ):
74 super().__init__(name, TopologicalSpace.SPATIAL)
75 self.maxLevel = maxLevel
76 self.PixelizationClass = PixelizationClass
77 self._members: Dict[int, SkyPixDimension] = {}
78 for level in range(maxLevel + 1):
79 self._members[level] = SkyPixDimension(self, level)
81 def choose(self, endpoints: NamedValueAbstractSet[TopologicalRelationshipEndpoint]) -> SkyPixDimension:
82 # Docstring inherited from TopologicalFamily.
83 best: Optional[SkyPixDimension] = None
84 for endpoint in endpoints:
85 if endpoint not in self:
86 continue
87 assert isinstance(endpoint, SkyPixDimension)
88 if best is None or best.level < endpoint.level:
89 best = endpoint
90 if best is None:
91 raise RuntimeError(f"No recognized endpoints for {self.name} in {endpoints}.")
92 return best
94 def __getitem__(self, level: int) -> SkyPixDimension:
95 return self._members[level]
98class SkyPixDimension(Dimension):
99 """A special `Dimension` subclass for hierarchical pixelizations of the
100 sky at a particular level.
102 Unlike most other dimensions, skypix dimension records are not stored in
103 the database, as these records only contain an integer pixel ID and a
104 region on the sky, and each of these can be computed directly from the
105 other.
107 Parameters
108 ----------
109 system : `SkyPixSystem`
110 Pixelization system this dimension belongs to.
111 level : `int`
112 Integer level of this pixelization (smaller numbers are coarser grids).
113 """
114 def __init__(self, system: SkyPixSystem, level: int):
115 self.system = system
116 self.level = level
117 self.pixelization = system.PixelizationClass(level)
119 @property
120 def name(self) -> str:
121 return f"{self.system.name}{self.level}"
123 @property
124 def required(self) -> NamedValueAbstractSet[Dimension]:
125 # Docstring inherited from DimensionElement.
126 return NamedValueSet({self}).freeze()
128 @property
129 def implied(self) -> NamedValueAbstractSet[Dimension]:
130 # Docstring inherited from DimensionElement.
131 return NamedValueSet().freeze()
133 @property
134 def topology(self) -> Mapping[TopologicalSpace, TopologicalFamily]:
135 # Docstring inherited from TopologicalRelationshipEndpoint
136 return MappingProxyType({TopologicalSpace.SPATIAL: self.system})
138 @property
139 def metadata(self) -> NamedValueAbstractSet[ddl.FieldSpec]:
140 # Docstring inherited from DimensionElement.
141 return NamedValueSet().freeze()
143 def hasTable(self) -> bool:
144 # Docstring inherited from DimensionElement.hasTable.
145 return False
147 def makeStorage(self) -> SkyPixDimensionRecordStorage:
148 """Construct the `DimensionRecordStorage` instance that should
149 be used to back this element in a registry.
151 Returns
152 -------
153 storage : `SkyPixDimensionRecordStorage`
154 Storage object that should back this element in a registry.
155 """
156 from ...registry.dimensions.skypix import BasicSkyPixDimensionRecordStorage
157 return BasicSkyPixDimensionRecordStorage(self)
159 @property
160 def uniqueKeys(self) -> NamedValueAbstractSet[ddl.FieldSpec]:
161 # Docstring inherited from DimensionElement.
162 return NamedValueSet({
163 ddl.FieldSpec(
164 name="id",
165 dtype=sqlalchemy.BigInteger,
166 primaryKey=True,
167 nullable=False,
168 )
169 }).freeze()
171 # Class attributes below are shadowed by instance attributes, and are
172 # present just to hold the docstrings for those instance attributes.
174 system: SkyPixSystem
175 """Pixelization system this dimension belongs to (`SkyPixSystem`).
176 """
178 level: int
179 """Integer level of this pixelization (smaller numbers are coarser grids).
180 """
182 pixelization: Pixelization
183 """Pixelization instance that can compute regions from IDs and IDs from
184 points (`sphgeom.Pixelization`).
185 """
188class SkyPixConstructionVisitor(DimensionConstructionVisitor):
189 """Builder visitor for a single `SkyPixSystem` and its dimensions.
191 Parameters
192 ----------
193 name : `str`
194 Name of the `SkyPixSystem` to be constructed.
195 pixelizationClassName : `str`
196 Fully-qualified name of the class whose instances represent a
197 particular level of this pixelization.
198 maxLevel : `int`, optional
199 Maximum level (inclusive) of the hierarchy. If not provided,
200 an attempt will be made to obtain it from a ``MAX_LEVEL`` attribute
201 of the pixelization class.
203 Notes
204 -----
205 At present, this class adds both a new `SkyPixSystem` instance all possible
206 `SkyPixDimension` to the builder that invokes it. In the future, it may
207 add only the `SkyPixSystem`, with dimension instances created on-the-fly
208 by the `DimensionUniverse`; this depends on `DimensionGraph.encode` going
209 away or otherwise eliminating assumptions about the set of dimensions in a
210 universe being static.
211 """
212 def __init__(self, name: str, pixelizationClassName: str, maxLevel: Optional[int] = None):
213 super().__init__(name)
214 self._pixelizationClassName = pixelizationClassName
215 self._maxLevel = maxLevel
217 def hasDependenciesIn(self, others: AbstractSet[str]) -> bool:
218 # Docstring inherited from DimensionConstructionVisitor.
219 return False
221 def visit(self, builder: DimensionConstructionBuilder) -> None:
222 # Docstring inherited from DimensionConstructionVisitor.
223 PixelizationClass = doImport(self._pixelizationClassName)
224 maxLevel = self._maxLevel if self._maxLevel is not None else PixelizationClass.MAX_LEVEL
225 system = SkyPixSystem(
226 self.name,
227 maxLevel=maxLevel,
228 PixelizationClass=PixelizationClass,
229 )
230 builder.topology[TopologicalSpace.SPATIAL].add(system)
231 for level in range(maxLevel + 1):
232 dimension = system[level]
233 builder.dimensions.add(dimension)
234 builder.elements.add(dimension)