Coverage for python/lsst/obs/lsst/instrument.py : 60%

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 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", "LsstImSim", "LsstPhoSim", "LsstTS8",
23 "Latiss", "LsstTS3", "LsstUCDCam", "LsstComCam")
25import os.path
27import lsst.obs.base.yamlCamera as yamlCamera
28from lsst.utils import getPackageDir
29from lsst.obs.base.instrument import Instrument
30from .filters import LSSTCAM_FILTER_DEFINITIONS, LATISS_FILTER_DEFINITIONS
32from .translators import LatissTranslator, LsstCamTranslator, \
33 LsstUCDCamTranslator, LsstTS3Translator, LsstComCamTranslator, \
34 LsstPhoSimTranslator, LsstTS8Translator, LsstImSimTranslator
36PACKAGE_DIR = getPackageDir("obs_lsst")
39class LsstCam(Instrument):
40 """Gen3 Butler specialization for the LSST Main Camera.
42 Parameters
43 ----------
44 camera : `lsst.cameraGeom.Camera`
45 Camera object from which to extract detector information.
46 filters : `list` of `FilterDefinition`
47 An ordered list of filters to define the set of PhysicalFilters
48 associated with this instrument in the registry.
50 While both the camera geometry and the set of filters associated with a
51 camera are expected to change with time in general, their Butler Registry
52 representations defined by an Instrument do not. Instead:
54 - We only extract names, IDs, and purposes from the detectors in the
55 camera, which should be static information that actually reflects
56 detector "slots" rather than the physical sensors themselves. Because
57 the distinction between physical sensors and slots is unimportant in
58 the vast majority of Butler use cases, we just use "detector" even
59 though the concept really maps better to "detector slot". Ideally in
60 the future this distinction between static and time-dependent
61 information would be encoded in cameraGeom itself (e.g. by making the
62 time-dependent Detector class inherit from a related class that only
63 carries static content).
65 - The Butler Registry is expected to contain physical_filter entries for
66 all filters an instrument has ever had, because we really only care
67 about which filters were used for particular observations, not which
68 filters were *available* at some point in the past. And changes in
69 individual filters over time will be captured as changes in their
70 TransmissionCurve datasets, not changes in the registry content (which
71 is really just a label). While at present Instrument and Registry
72 do not provide a way to add new physical_filters, they will in the
73 future.
74 """
75 filterDefinitions = LSSTCAM_FILTER_DEFINITIONS
76 instrument = "LSSTCam"
77 policyName = "lsstCam"
78 _camera = None
79 _cameraCachedClass = None
80 translatorClass = LsstCamTranslator
81 obsDataPackage = "obs_lsst_data"
83 @property
84 def configPaths(self):
85 return [os.path.join(PACKAGE_DIR, "config"),
86 os.path.join(PACKAGE_DIR, "config", self.policyName)]
88 @classmethod
89 def getName(cls):
90 # Docstring inherited from Instrument.getName
91 return cls.instrument
93 @classmethod
94 def getCamera(cls):
95 # Constructing a YAML camera takes a long time so cache the result
96 # We have to be careful to ensure we cache at the subclass level
97 # since LsstCam base class will look like a cache to the subclasses
98 if cls._camera is None or cls._cameraCachedClass != cls:
99 cameraYamlFile = os.path.join(PACKAGE_DIR, "policy", f"{cls.policyName}.yaml")
100 cls._camera = yamlCamera.makeCamera(cameraYamlFile)
101 cls._cameraCachedClass = cls
102 return cls._camera
104 def getRawFormatter(self, dataId):
105 # Docstring inherited from Instrument.getRawFormatter
106 # local import to prevent circular dependency
107 from .rawFormatter import LsstCamRawFormatter
108 return LsstCamRawFormatter
110 def register(self, registry):
111 # Docstring inherited from Instrument.register
112 # The maximum values below make Gen3's ObservationDataIdPacker produce
113 # outputs that match Gen2's ccdExposureId.
114 obsMax = self.translatorClass.max_detector_exposure_id()
115 registry.insertDimensionData("instrument",
116 {"name": self.getName(),
117 "detector_max": self.translatorClass.DETECTOR_MAX,
118 "visit_max": obsMax,
119 "exposure_max": obsMax})
121 records = [self.extractDetectorRecord(detector) for detector in self.getCamera()]
122 registry.insertDimensionData("detector", *records)
124 self._registerFilters(registry)
126 def extractDetectorRecord(self, camGeomDetector):
127 """Create a Gen3 Detector entry dict from a cameraGeom.Detector.
128 """
129 # All of the LSST instruments have detector names like R??_S??; we'll
130 # split them up here, and instruments with only one raft can override
131 # to change the group to something else if desired.
132 # Long-term, we should get these fields into cameraGeom separately
133 # so there's no need to specialize at this stage.
134 # They are separate in ObservationInfo
135 group, name = camGeomDetector.getName().split("_")
137 # getType() returns a pybind11-wrapped enum, which unfortunately
138 # has no way to extract the name of just the value (it's always
139 # prefixed by the enum type name).
140 purpose = str(camGeomDetector.getType()).split(".")[-1]
142 return dict(
143 instrument=self.getName(),
144 id=camGeomDetector.getId(),
145 full_name=camGeomDetector.getName(),
146 name_in_raft=name,
147 purpose=purpose,
148 raft=group,
149 )
152class LsstComCam(LsstCam):
153 """Gen3 Butler specialization for ComCam data.
154 """
156 instrument = "LSSTComCam"
157 policyName = "comCam"
158 translatorClass = LsstComCamTranslator
160 def getRawFormatter(self, dataId):
161 # local import to prevent circular dependency
162 from .rawFormatter import LsstComCamRawFormatter
163 return LsstComCamRawFormatter
166class LsstImSim(LsstCam):
167 """Gen3 Butler specialization for ImSim simulations.
168 """
170 instrument = "LSST-ImSim"
171 policyName = "imsim"
172 translatorClass = LsstImSimTranslator
174 def getRawFormatter(self, dataId):
175 # local import to prevent circular dependency
176 from .rawFormatter import LsstImSimRawFormatter
177 return LsstImSimRawFormatter
180class LsstPhoSim(LsstCam):
181 """Gen3 Butler specialization for Phosim simulations.
182 """
184 instrument = "LSST-PhoSim"
185 policyName = "phosim"
186 translatorClass = LsstPhoSimTranslator
188 def getRawFormatter(self, dataId):
189 # local import to prevent circular dependency
190 from .rawFormatter import LsstPhoSimRawFormatter
191 return LsstPhoSimRawFormatter
194class LsstTS8(LsstCam):
195 """Gen3 Butler specialization for raft test stand data.
196 """
198 instrument = "LSST-TS8"
199 policyName = "ts8"
200 translatorClass = LsstTS8Translator
202 def getRawFormatter(self, dataId):
203 # local import to prevent circular dependency
204 from .rawFormatter import LsstTS8RawFormatter
205 return LsstTS8RawFormatter
208class LsstUCDCam(LsstCam):
209 """Gen3 Butler specialization for UCDCam test stand data.
210 """
212 instrument = "LSST-UCDCam"
213 policyName = "ucd"
214 translatorClass = LsstUCDCamTranslator
216 def getRawFormatter(self, dataId):
217 # local import to prevent circular dependency
218 from .rawFormatter import LsstUCDCamRawFormatter
219 return LsstUCDCamRawFormatter
222class LsstTS3(LsstCam):
223 """Gen3 Butler specialization for TS3 test stand data.
224 """
226 instrument = "LSST-TS3"
227 policyName = "ts3"
228 translatorClass = LsstTS3Translator
230 def getRawFormatter(self, dataId):
231 # local import to prevent circular dependency
232 from .rawFormatter import LsstTS3RawFormatter
233 return LsstTS3RawFormatter
236class Latiss(LsstCam):
237 """Gen3 Butler specialization for AuxTel LATISS data.
238 """
239 filterDefinitions = LATISS_FILTER_DEFINITIONS
240 instrument = "LATISS"
241 policyName = "latiss"
242 translatorClass = LatissTranslator
244 def extractDetectorRecord(self, camGeomDetector):
245 # Override to remove group (raft) name, because LATISS only has one
246 # detector.
247 record = super().extractDetectorRecord(camGeomDetector)
248 record["raft"] = None
249 record["name_in_raft"] = record["full_name"]
250 return record
252 def getRawFormatter(self, dataId):
253 # local import to prevent circular dependency
254 from .rawFormatter import LatissRawFormatter
255 return LatissRawFormatter