Coverage for python/lsst/obs/lsst/_instrument.py: 62%
108 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-09 04:28 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-09 04:28 -0800
1# This file is part of obs_lsst.
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/>.
22__all__ = ("LsstCam", "LsstCamImSim", "LsstCamPhoSim", "LsstTS8",
23 "Latiss", "LsstTS3", "LsstUCDCam", "LsstComCam")
25import os.path
27import lsst.obs.base.yamlCamera as yamlCamera
28from lsst.utils.introspection import get_full_type_name
29from lsst.utils import getPackageDir
30from lsst.obs.base import Instrument, VisitSystem
31from .filters import (LSSTCAM_FILTER_DEFINITIONS, LATISS_FILTER_DEFINITIONS,
32 LSSTCAM_IMSIM_FILTER_DEFINITIONS, TS3_FILTER_DEFINITIONS,
33 TS8_FILTER_DEFINITIONS, COMCAM_FILTER_DEFINITIONS,
34 )
36from .translators import LatissTranslator, LsstCamTranslator, \
37 LsstUCDCamTranslator, LsstTS3Translator, LsstComCamTranslator, \
38 LsstCamPhoSimTranslator, LsstTS8Translator, LsstCamImSimTranslator
40PACKAGE_DIR = getPackageDir("obs_lsst")
43class LsstCam(Instrument):
44 """Gen3 Butler specialization for the LSST Main Camera.
46 Parameters
47 ----------
48 camera : `lsst.cameraGeom.Camera`
49 Camera object from which to extract detector information.
50 filters : `list` of `FilterDefinition`
51 An ordered list of filters to define the set of PhysicalFilters
52 associated with this instrument in the registry.
54 While both the camera geometry and the set of filters associated with a
55 camera are expected to change with time in general, their Butler Registry
56 representations defined by an Instrument do not. Instead:
58 - We only extract names, IDs, and purposes from the detectors in the
59 camera, which should be static information that actually reflects
60 detector "slots" rather than the physical sensors themselves. Because
61 the distinction between physical sensors and slots is unimportant in
62 the vast majority of Butler use cases, we just use "detector" even
63 though the concept really maps better to "detector slot". Ideally in
64 the future this distinction between static and time-dependent
65 information would be encoded in cameraGeom itself (e.g. by making the
66 time-dependent Detector class inherit from a related class that only
67 carries static content).
69 - The Butler Registry is expected to contain physical_filter entries for
70 all filters an instrument has ever had, because we really only care
71 about which filters were used for particular observations, not which
72 filters were *available* at some point in the past. And changes in
73 individual filters over time will be captured as changes in their
74 TransmissionCurve datasets, not changes in the registry content (which
75 is really just a label). While at present Instrument and Registry
76 do not provide a way to add new physical_filters, they will in the
77 future.
78 """
79 filterDefinitions = LSSTCAM_FILTER_DEFINITIONS
80 instrument = "LSSTCam"
81 policyName = "lsstCam"
82 translatorClass = LsstCamTranslator
83 obsDataPackage = "obs_lsst_data"
84 visitSystem = VisitSystem.BY_SEQ_START_END
86 @property
87 def configPaths(self):
88 return [os.path.join(PACKAGE_DIR, "config"),
89 os.path.join(PACKAGE_DIR, "config", self.policyName)]
91 @classmethod
92 def getName(cls):
93 # Docstring inherited from Instrument.getName
94 return cls.instrument
96 @classmethod
97 def getCamera(cls):
98 # Constructing a YAML camera takes a long time but we rely on
99 # yamlCamera to cache for us.
100 cameraYamlFile = os.path.join(PACKAGE_DIR, "policy", f"{cls.policyName}.yaml")
101 camera = yamlCamera.makeCamera(cameraYamlFile)
102 if camera.getName() != cls.getName():
103 raise RuntimeError(f"Expected to read camera geometry for {cls.instrument}"
104 f" but instead got geometry for {camera.getName()}")
105 return camera
107 def getRawFormatter(self, dataId):
108 # Docstring inherited from Instrument.getRawFormatter
109 # local import to prevent circular dependency
110 from .rawFormatter import LsstCamRawFormatter
111 return LsstCamRawFormatter
113 def register(self, registry, update=False):
114 # Docstring inherited from Instrument.register
115 # The maximum values below make Gen3's ObservationDataIdPacker produce
116 # outputs that match Gen2's ccdExposureId.
117 obsMax = self.translatorClass.max_exposure_id()
118 # Make sure this is at least 1 to avoid non-uniqueness issues (e.g.
119 # for data ids that also get used in indexing).
120 detectorMax = max(self.translatorClass.DETECTOR_MAX, 1)
121 with registry.transaction():
122 registry.syncDimensionData(
123 "instrument",
124 {
125 "name": self.getName(),
126 "detector_max": detectorMax,
127 "visit_max": obsMax,
128 "exposure_max": obsMax,
129 "class_name": get_full_type_name(self),
130 "visit_system": None if self.visitSystem is None else self.visitSystem.value,
131 },
132 update=update
133 )
134 for detector in self.getCamera():
135 registry.syncDimensionData("detector", self.extractDetectorRecord(detector), update=update)
137 self._registerFilters(registry, update=update)
139 def extractDetectorRecord(self, camGeomDetector):
140 """Create a Gen3 Detector entry dict from a cameraGeom.Detector.
141 """
142 # All of the LSST instruments have detector names like R??_S??; we'll
143 # split them up here, and instruments with only one raft can override
144 # to change the group to something else if desired.
145 # Long-term, we should get these fields into cameraGeom separately
146 # so there's no need to specialize at this stage.
147 # They are separate in ObservationInfo
148 group, name = camGeomDetector.getName().split("_")
150 # getType() returns a pybind11-wrapped enum, which unfortunately
151 # has no way to extract the name of just the value (it's always
152 # prefixed by the enum type name).
153 purpose = str(camGeomDetector.getType()).split(".")[-1]
155 return dict(
156 instrument=self.getName(),
157 id=camGeomDetector.getId(),
158 full_name=camGeomDetector.getName(),
159 name_in_raft=name,
160 purpose=purpose,
161 raft=group,
162 )
165class LsstComCam(LsstCam):
166 """Gen3 Butler specialization for ComCam data.
167 """
169 filterDefinitions = COMCAM_FILTER_DEFINITIONS
170 instrument = "LSSTComCam"
171 policyName = "comCam"
172 translatorClass = LsstComCamTranslator
174 def getRawFormatter(self, dataId):
175 # local import to prevent circular dependency
176 from .rawFormatter import LsstComCamRawFormatter
177 return LsstComCamRawFormatter
180class LsstCamImSim(LsstCam):
181 """Gen3 Butler specialization for ImSim simulations.
182 """
184 instrument = "LSSTCam-imSim"
185 policyName = "imsim"
186 translatorClass = LsstCamImSimTranslator
187 filterDefinitions = LSSTCAM_IMSIM_FILTER_DEFINITIONS
188 visitSystem = VisitSystem.ONE_TO_ONE
190 def getRawFormatter(self, dataId):
191 # local import to prevent circular dependency
192 from .rawFormatter import LsstCamImSimRawFormatter
193 return LsstCamImSimRawFormatter
196class LsstCamPhoSim(LsstCam):
197 """Gen3 Butler specialization for Phosim simulations.
198 """
200 instrument = "LSSTCam-PhoSim"
201 policyName = "phosim"
202 translatorClass = LsstCamPhoSimTranslator
203 visitSystem = VisitSystem.ONE_TO_ONE
205 def getRawFormatter(self, dataId):
206 # local import to prevent circular dependency
207 from .rawFormatter import LsstCamPhoSimRawFormatter
208 return LsstCamPhoSimRawFormatter
211class LsstTS8(LsstCam):
212 """Gen3 Butler specialization for raft test stand data.
213 """
215 filterDefinitions = TS8_FILTER_DEFINITIONS
216 instrument = "LSST-TS8"
217 policyName = "ts8"
218 translatorClass = LsstTS8Translator
219 visitSystem = VisitSystem.ONE_TO_ONE
221 def getRawFormatter(self, dataId):
222 # local import to prevent circular dependency
223 from .rawFormatter import LsstTS8RawFormatter
224 return LsstTS8RawFormatter
227class LsstUCDCam(LsstCam):
228 """Gen3 Butler specialization for UCDCam test stand data.
229 """
231 instrument = "LSST-UCDCam"
232 policyName = "ucd"
233 translatorClass = LsstUCDCamTranslator
234 visitSystem = VisitSystem.ONE_TO_ONE
236 def getRawFormatter(self, dataId):
237 # local import to prevent circular dependency
238 from .rawFormatter import LsstUCDCamRawFormatter
239 return LsstUCDCamRawFormatter
242class LsstTS3(LsstCam):
243 """Gen3 Butler specialization for TS3 test stand data.
244 """
246 filterDefinitions = TS3_FILTER_DEFINITIONS
247 instrument = "LSST-TS3"
248 policyName = "ts3"
249 translatorClass = LsstTS3Translator
250 visitSystem = VisitSystem.ONE_TO_ONE
252 def getRawFormatter(self, dataId):
253 # local import to prevent circular dependency
254 from .rawFormatter import LsstTS3RawFormatter
255 return LsstTS3RawFormatter
258class Latiss(LsstCam):
259 """Gen3 Butler specialization for AuxTel LATISS data.
260 """
261 filterDefinitions = LATISS_FILTER_DEFINITIONS
262 instrument = "LATISS"
263 policyName = "latiss"
264 translatorClass = LatissTranslator
266 def extractDetectorRecord(self, camGeomDetector):
267 # Override to remove group (raft) name, because LATISS only has one
268 # detector.
269 record = super().extractDetectorRecord(camGeomDetector)
270 record["raft"] = None
271 record["name_in_raft"] = record["full_name"]
272 return record
274 def getRawFormatter(self, dataId):
275 # local import to prevent circular dependency
276 from .rawFormatter import LatissRawFormatter
277 return LatissRawFormatter