22from __future__
import annotations
24__all__ = (
"SkyMapDimensionPacker",)
29from lsst.daf.butler
import DimensionPacker, DimensionGraph, DataCoordinate
30from deprecated.sphinx
import deprecated
35 "Mapping from band name to integer to use in the packed ID. "
36 "The default (None) is to use a hard-coded list of common bands; "
37 "pipelines that can enumerate the set of bands they are likely to see "
38 "should override this.",
45 "Number of bands to reserve space for. "
46 "If zero, bands are not included in the packed integer at all. "
47 "If `None`, the size of 'bands' is used.",
53 "Number of tracts, or, more precisely, one greater than the maximum tract ID."
54 "Default (None) obtains this value from the skymap dimension record.",
60 "Number of patches per tract, or, more precisely, one greater than the maximum patch ID."
61 "Default (None) obtains this value from the skymap dimension record.",
69 """A `DimensionPacker` for tract, patch and optionally band,
74 fixed : `lsst.daf.butler.DataCoordinate`
75 Data ID that identifies just the ``skymap`` dimension. Must have
76 dimension records attached unless ``n_tracts`` and ``n_patches`` are
78 dimensions : `lsst.daf.butler.DimensionGraph`, optional
79 The dimensions of data IDs packed by this instance. Must include
80 ``{skymap, tract, patch}``,
and may include ``band``. If
not provided,
81 this will be set to include ``band``
if ``n_bands != 0``.
82 bands : `~collections.abc.Mapping` [ `str`, `int` ]
or `
None`, optional
83 Mapping
from band name to integer to use
in the packed ID. `
None` uses
84 a fixed set of bands defined
in this
class. When calling code can
85 enumerate the bands it
is likely to see, providing an explicit mapping
87 n_bands : `int`
or `
None`, optional
88 The number of bands to leave room
for in the packed ID. If `
None`,
89 this will be set to ``len(bands)``. If ``0``, the band will
not be
90 included
in the dimensions at all. If ``1``, the band will be included
91 in the dimensions but will
not occupy any extra bits
in the packed ID.
92 This may be larger
or smaller than ``len(bands)``, to reserve extra
93 space
for the future
or align to byte boundaries,
or support a subset
94 of a larger mapping, respectively.
95 n_tracts : `int`
or `
None`, optional
96 The number of tracts to leave room
for in the packed ID. If `
None`,
97 this will be set via the ``skymap`` dimension record
in ``fixed``.
98 n_patches : `int`
or `
None`, optional
99 The number of patches (per tract) to leave room
for in the packed ID.
100 If `
None`, this will be set via the ``skymap`` dimension record
in
105 The standard pattern
for constructing instances of this
class is
to use
106 `make_config_field`::
109 packer = ObservationDimensionPacker.make_config_field()
111 class SomeTask(lsst.pipe.base.Task):
112 ConfigClass = SomeConfig
114 def run(self, ..., data_id: DataCoordinate):
115 packer = self.config.packer.apply(data_id)
116 packed_id = packer.pack(data_id)
121 SUPPORTED_FILTERS = (
123 +
list(
"ugrizyUBGVRIZYJHK")
124 + [f
"N{d}" for d
in (387, 515, 656, 816, 921, 1010)]
125 + [f
"N{d}" for d
in (419, 540, 708, 964)]
127 """Sequence of supported bands used to construct a mapping from band name
128 to integer when the 'bands' config option
is `
None`
or no config
is
131 This variable should no longer be modified to add new filters;
pass
132 ``bands`` at construction
or use `from_config` instead.
135 ConfigClass = SkyMapDimensionPackerConfig
140 reason=
"This classmethod cannot reflect all __init__ args and will be removed after v26.",
142 category=FutureWarning,
145 """Return an integer that represents the band with the given
151 raise NotImplementedError(f
"band '{name}' not supported by this ID packer.")
156 reason=
"This classmethod cannot reflect all __init__ args and will be removed after v26.",
158 category=FutureWarning,
161 """Return an band name from its integer representation."""
167 reason=
"This classmethod cannot reflect all __init__ args and will be removed after v26.",
169 category=FutureWarning,
176 fixed: DataCoordinate,
177 dimensions: DimensionGraph |
None =
None,
178 bands: Mapping[str, int] |
None =
None,
179 n_bands: int |
None =
None,
180 n_tracts: int |
None =
None,
181 n_patches: int |
None =
None,
185 if dimensions
is None:
188 dimension_names = [
"tract",
"patch"]
190 dimension_names.append(
"band")
191 dimensions = fixed.universe.extract(dimension_names)
193 if "band" not in dimensions.names:
195 if dimensions.names != {
"tract",
"patch",
"skymap"}:
197 f
"Invalid dimensions for skymap dimension packer with n_bands=0: {dimensions}."
200 if dimensions.names != {
"tract",
"patch",
"skymap",
"band"}:
202 f
"Invalid dimensions for skymap dimension packer with n_bands>0: {dimensions}."
207 n_tracts = fixed.records[
"skymap"].tract_max
208 if n_patches
is None:
210 fixed.records[
"skymap"].patch_nx_max
211 * fixed.records[
"skymap"].patch_ny_max
223 doc: str =
"How to pack tract, patch, and possibly band into an integer."
224 ) -> ConfigurableField:
225 """Make a config field to control how skymap data IDs are packed.
229 doc : `str`, optional
230 Documentation for the config field.
235 A config field whose instance values are [wrapper proxies to]
236 `SkyMapDimensionPackerConfig` instances.
242 cls, data_id: DataCoordinate, config: SkyMapDimensionPackerConfig
243 ) -> SkyMapDimensionPacker:
244 """Construct a dimension packer from a config object and a data ID.
248 data_id : `lsst.daf.butler.DataCoordinate`
249 Data ID that identifies at least the ``skymap`` dimension. Must
250 have dimension records attached unless ``config.n_tracts`` and
251 ``config.n_patches`` are both
not `
None`.
252 config : `SkyMapDimensionPackerConfig`
253 Configuration object.
257 packer : `SkyMapDimensionPackerConfig`
258 New dimension packer.
263 "Configurable" concept,
and is invoked when ``apply(data_id)``
is
264 called on a config instance attribute that corresponds to a field
265 created by `make_config_field`. The constructor signature cannot play
266 this role easily
for backwards compatibility reasons.
269 data_id.subset(data_id.universe.extract([
"skymap"])),
270 n_bands=config.n_bands,
272 n_tracts=config.n_tracts,
273 n_patches=config.n_patches,
282 return (packedMax - 1).bit_length()
284 def _pack(self, dataId: DataCoordinate) -> int:
287 raise ValueError(f
"Patch ID {dataId['patch']} is out of bounds; expected <{self._n_patches}.")
289 raise ValueError(f
"Tract ID {dataId['tract']} is out of bounds; expected <{self._n_tracts}.")
290 packed = dataId[
"patch"] + self.
_n_patches * dataId[
"tract"]
292 if (band_index := self.
_bands.get(dataId[
"band"]))
is None:
294 f
"Band {dataId['band']!r} is not supported by SkyMapDimensionPacker "
295 f
"configuration; expected one of {list(self._bands)}."
299 f
"Band index {band_index} for {dataId['band']!r} is out of bounds; "
300 f
"expected <{self._n_bands}."
305 def unpack(self, packedId: int) -> DataCoordinate:
307 d = {
"skymap": self.fixed[
"skymap"]}
313 d[
"tract"], d[
"patch"] = divmod(packedId, self.
_n_patches)
314 return DataCoordinate.standardize(d, graph=self.dimensions)
getFilterNameFromInt(cls, num)
__init__(self, DataCoordinate fixed, DimensionGraph|None dimensions=None, Mapping[str, int]|None bands=None, int|None n_bands=None, int|None n_tracts=None, int|None n_patches=None)
ConfigurableField make_config_field(cls, str doc="How to pack tract, patch, and possibly band into an integer.")
SkyMapDimensionPacker from_config(cls, DataCoordinate data_id, SkyMapDimensionPackerConfig config)
int _pack(self, DataCoordinate dataId)
getIntFromFilter(cls, name)
DataCoordinate unpack(self, int packedId)
daf::base::PropertyList * list