Coverage for python/lsst/cell_coadds/_identifiers.py: 86%
47 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-08 11:19 +0000
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-08 11:19 +0000
1# This file is part of cell_coadds.
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/>.
22from __future__ import annotations
24__all__ = (
25 "PatchIdentifiers",
26 "CellIdentifiers",
27 "ObservationIdentifiers",
28)
31from dataclasses import dataclass
32from typing import Self, cast
34from lsst.daf.butler import DataCoordinate, DimensionRecord
35from lsst.skymap import Index2D
38@dataclass(frozen=True)
39class PatchIdentifiers:
40 """Struct of identifiers for a coadd patch."""
42 skymap: str
43 """The name of the skymap this patch belongs to.
44 """
46 tract: int
47 """The name of the tract this patch belongs to.
48 """
50 patch: Index2D
51 """Identifiers for the patch itself.
52 """
54 band: str | None
55 """Name of the band, if any.
56 """
58 @classmethod
59 def from_data_id(cls, data_id: DataCoordinate) -> PatchIdentifiers:
60 """Construct from a data ID.
62 Parameters
63 ----------
64 data_id : `~lsst.daf.butler.DataCoordinate`
65 Fully-expanded data ID that includes the 'patch' dimension and
66 optionally the `band` dimension.
68 Returns
69 -------
70 identifiers : `PatchIdentifiers`
71 Struct of identifiers for this patch.
72 """
73 patch_record = cast(DimensionRecord, data_id.records["patch"])
74 return cls(
75 skymap=cast(str, data_id["skymap"]),
76 tract=cast(int, data_id["tract"]),
77 patch=Index2D(x=patch_record.cell_x, y=patch_record.cell_y),
78 band=cast(str, data_id.get("band")),
79 )
82@dataclass(frozen=True)
83class CellIdentifiers(PatchIdentifiers):
84 """Struct of identifiers for a coadd cell."""
86 cell: Index2D
87 """Identifiers for the cell itself."""
89 @classmethod
90 def from_data_id( # type: ignore [override]
91 cls, data_id: DataCoordinate, cell: Index2D
92 ) -> CellIdentifiers:
93 """Construct from a data ID and a cell index.
95 Parameters
96 ----------
97 data_id : `~lsst.daf.butler.DataCoordinate`
98 Fully-expanded data ID that includes the 'patch' dimension and
99 optionally the `band` dimension.
100 cell : `~lsst.skymap.Index2D`
101 Index of the cell within the patch.
103 Returns
104 -------
105 identifiers : `CellIdentifiers`
106 Struct of identifiers for this cell within a patch.
107 """
108 patch_record = cast(DimensionRecord, data_id.records["patch"])
109 return cls(
110 skymap=cast(str, data_id["skymap"]),
111 tract=cast(int, data_id["tract"]),
112 patch=Index2D(x=patch_record.cell_x, y=patch_record.cell_y),
113 band=cast(str, data_id.get("band")),
114 cell=cell,
115 )
118@dataclass(frozen=True)
119class ObservationIdentifiers:
120 """Struct of identifiers for an observation that contributed to a coadd
121 cell.
122 """
124 instrument: str
125 """Name of the instrument that this observation was taken with.
126 """
128 physical_filter: str
129 """Name of the physical filter that this observation was taken with.
130 """
132 visit: int
133 """Unique identifier for the visit.
135 A visit may be comprised of more than one exposure only if all were
136 observed back-to-back with no dithers, allowing them to be combined early
137 the processing with no resampling. All detector-level images in a visit
138 share the same visit ID.
139 """
141 day_obs: int
142 """A day and night of observations that rolls over during daylight hours.
143 The identifier is an decimal integer-concatenated date, i.e. YYYYMMDD,
144 with the exact rollover time observatory-dependent.
145 """
147 detector: int
148 """Unique identifier for the detector.
149 """
151 @classmethod
152 def from_data_id(cls, data_id: DataCoordinate, *, backup_detector: int = -1) -> ObservationIdentifiers:
153 """Construct from a data ID.
155 Parameters
156 ----------
157 data_id : `~lsst.daf.butler.DataCoordinate`
158 Fully-expanded data ID that includes the 'visit', 'detector' and
159 'day_obs' dimensions.
160 backup_detector : `int`, optional
161 Detector ID to use as a backup if not present in ``data_id``.
162 This is not used if detector information is available in
163 ``data_id`` and does not override it.
165 Returns
166 -------
167 identifiers : `ObservationIdentifiers`
168 Struct of identifiers for this observation.
169 """
170 detector = data_id.get("detector", backup_detector)
171 day_obs = data_id.get("day_obs", None)
172 return cls(
173 instrument=cast(str, data_id["instrument"]),
174 physical_filter=cast(str, data_id["physical_filter"]),
175 visit=cast(int, data_id["visit"]),
176 day_obs=cast(int, day_obs),
177 detector=cast(int, detector),
178 )
180 def __lt__(self, other: Self, /) -> bool:
181 return (self.visit, self.detector) < (other.visit, other.detector)