Coverage for python/lsst/obs/base/exposureIdInfo.py: 25%
Shortcuts 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
Shortcuts 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 obs_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/>.
22__all__ = ["ExposureIdInfo"]
24from lsst.daf.butler import DataCoordinate
25from lsst.afw.table import IdFactory
28class ExposureIdInfo:
29 """Struct representing an exposure ID and the number of bits it uses.
31 Parameters
32 ----------
33 expId : `int`
34 Exposure ID. Note that this is typically the ID of an
35 `afw.image.Exposure`, not the ID of an actual observation, and hence it
36 usually either includes a detector component or is derived from SkyMap
37 IDs, and the observation ID component usually represents a ``visit``
38 rather than ``exposure``. For code using the Gen3 butler, this will
39 usually be obtained via a `~lsst.daf.butler.DimensionPacker` (see
40 example below).
41 expBits : `int`
42 Maximum number of bits allowed for exposure IDs of this type.
43 maxBits : `int`, optional
44 Maximum number of bits available for values that combine exposure ID
45 with other information, such as source ID. If not provided
46 (recommended when possible), `unusedBits` will be computed by assuming
47 the full ID must fit an an `lsst.afw.table` RecordId field.
49 Examples
50 --------
51 One common use is creating an ID factory for making a source table.
52 For example, given a `ExposureIdInfo` instance ``info``,
54 .. code-block:: python
56 from lsst.afw.table import SourceTable
57 schema = SourceTable.makeMinimalSchema()
58 #...add fields to schema as desired, then...
59 sourceTable = SourceTable.make(self.schema, info.makeSourceIdFactory())
61 An `ExposureIdInfo` instance can be obtained from a Gen2 data butler
62 ``butler`` and dictionary ``dataId`` that identifies a visit and a detector
63 via
65 .. code-block:: python
67 info = butler.get("expIdInfo", dataId)
69 The Gen3 version is
71 .. code-block:: python
73 expandedDataId = butler.registry.expandDataId(dataId)
74 info = ExposureIdInfo.fromDataId(expandedDataId, "visit_detector")
76 The first line should be unnecessary for the data IDs passed to
77 `~lsst.pipe.base.PipelineTask` methods, as those are already expanded, and
78 ``"visit_detector"`` can be replaced by other strings to pack data IDs with
79 different dimensions (e.g. ``"tract_patch"`` or ``"tract_patch_band"``);
80 see the data repository's dimensions configuration for other options.
82 At least one bit must be reserved for the exposure ID, even if there is no
83 exposure ID, for reasons that are not entirely clear (this is DM-6664).
84 """
86 def __init__(self, expId=0, expBits=1, maxBits=None):
87 """Construct an ExposureIdInfo
89 See the class doc string for an explanation of the arguments.
90 """
91 expId = int(expId)
92 expBits = int(expBits)
94 if expId.bit_length() > expBits:
95 raise RuntimeError("expId=%s uses %s bits > expBits=%s" % (expId, expId.bit_length(), expBits))
97 self.expId = expId
98 self.expBits = expBits
100 if maxBits is not None:
101 maxBits = int(maxBits)
102 if maxBits < expBits:
103 raise RuntimeError("expBits=%s > maxBits=%s" % (expBits, maxBits))
104 self.maxBits = maxBits
106 @classmethod
107 def fromDataId(cls, dataId, name="visit_detector", maxBits=None):
108 """Construct an instance from a fully-expanded data ID.
110 Parameters
111 ----------
112 dataId : `lsst.daf.butler.DataCoordinate`
113 An expanded data ID that identifies the dimensions to be packed and
114 contains extra information about the maximum values for those
115 dimensions. An expanded data ID can be obtained from
116 `Registry.expandDataId`, but all data IDs passed to `PipelineTask`
117 methods should already be expanded.
118 name : `str`, optional
119 Name of the packer to use. The set of available packers can be
120 found in the data repository's dimension configuration (see the
121 "packers" section of ``dimensions.yaml`` in ``daf_butler`` for the
122 defaults).
123 maxBits : `int`, optional
124 Forwarded as the ``__init__`` parameter of the same name. Should
125 usually be unnecessary.
127 Returns
128 -------
129 info : `ExposureIdInfo`
130 An `ExposureIdInfo` instance.
131 """
132 if not isinstance(dataId, DataCoordinate) or not dataId.hasRecords():
133 raise RuntimeError(
134 "A fully-expanded data ID is required; use "
135 "Registry.expandDataId to obtain one."
136 )
137 expId, expBits = dataId.pack(name, returnMaxBits=True)
138 return cls(expId=expId, expBits=expBits, maxBits=maxBits)
140 @property
141 def unusedBits(self):
142 """Maximum number of bits available for non-exposure info `(int)`.
143 """
144 if self.maxBits is None:
145 from lsst.afw.table import IdFactory
146 return IdFactory.computeReservedFromMaxBits(self.expBits)
147 else:
148 return self.maxBits - self.expBits
150 def makeSourceIdFactory(self):
151 """Make a `lsst.afw.table.SourceTable.IdFactory` instance from this
152 exposure information.
154 Returns
155 -------
156 idFactory : `lsst.afw.table.SourceTable.IdFactory`
157 An ID factory that generates new IDs that fold in the image IDs
158 managed by this object.
159 """
160 return IdFactory.makeSource(self.expId, self.unusedBits)