Hide keyboard shortcuts

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/>. 

21 

22__all__ = ("LsstCam", "LsstImSim", "LsstPhoSim", "LsstTS8", 

23 "Latiss", "LsstTS3", "LsstUCDCam", "LsstComCam") 

24 

25import os.path 

26 

27import lsst.obs.base.yamlCamera as yamlCamera 

28from lsst.daf.butler.core.utils import getFullTypeName 

29from lsst.utils import getPackageDir 

30from lsst.obs.base import Instrument 

31from lsst.obs.base.gen2to3 import TranslatorFactory 

32from .filters import LSSTCAM_FILTER_DEFINITIONS, LATISS_FILTER_DEFINITIONS 

33 

34from .translators import LatissTranslator, LsstCamTranslator, \ 

35 LsstUCDCamTranslator, LsstTS3Translator, LsstComCamTranslator, \ 

36 LsstPhoSimTranslator, LsstTS8Translator, LsstImSimTranslator 

37 

38PACKAGE_DIR = getPackageDir("obs_lsst") 

39 

40 

41class LsstCam(Instrument): 

42 """Gen3 Butler specialization for the LSST Main Camera. 

43 

44 Parameters 

45 ---------- 

46 camera : `lsst.cameraGeom.Camera` 

47 Camera object from which to extract detector information. 

48 filters : `list` of `FilterDefinition` 

49 An ordered list of filters to define the set of PhysicalFilters 

50 associated with this instrument in the registry. 

51 

52 While both the camera geometry and the set of filters associated with a 

53 camera are expected to change with time in general, their Butler Registry 

54 representations defined by an Instrument do not. Instead: 

55 

56 - We only extract names, IDs, and purposes from the detectors in the 

57 camera, which should be static information that actually reflects 

58 detector "slots" rather than the physical sensors themselves. Because 

59 the distinction between physical sensors and slots is unimportant in 

60 the vast majority of Butler use cases, we just use "detector" even 

61 though the concept really maps better to "detector slot". Ideally in 

62 the future this distinction between static and time-dependent 

63 information would be encoded in cameraGeom itself (e.g. by making the 

64 time-dependent Detector class inherit from a related class that only 

65 carries static content). 

66 

67 - The Butler Registry is expected to contain physical_filter entries for 

68 all filters an instrument has ever had, because we really only care 

69 about which filters were used for particular observations, not which 

70 filters were *available* at some point in the past. And changes in 

71 individual filters over time will be captured as changes in their 

72 TransmissionCurve datasets, not changes in the registry content (which 

73 is really just a label). While at present Instrument and Registry 

74 do not provide a way to add new physical_filters, they will in the 

75 future. 

76 """ 

77 filterDefinitions = LSSTCAM_FILTER_DEFINITIONS 

78 instrument = "LSSTCam" 

79 policyName = "lsstCam" 

80 _camera = None 

81 translatorClass = LsstCamTranslator 

82 obsDataPackage = "obs_lsst_data" 

83 

84 @property 

85 def configPaths(self): 

86 return [os.path.join(PACKAGE_DIR, "config"), 

87 os.path.join(PACKAGE_DIR, "config", self.policyName)] 

88 

89 @classmethod 

90 def getName(cls): 

91 # Docstring inherited from Instrument.getName 

92 return cls.instrument 

93 

94 @classmethod 

95 def getCamera(cls): 

96 # Constructing a YAML camera takes a long time so defer reading 

97 # until we need to. We rely on caching in yaml camera itself. 

98 if cls._camera is None: 

99 cameraYamlFile = os.path.join(PACKAGE_DIR, "policy", f"{cls.policyName}.yaml") 

100 cls._camera = yamlCamera.makeCamera(cameraYamlFile) 

101 return cls._camera 

102 

103 def getRawFormatter(self, dataId): 

104 # Docstring inherited from Instrument.getRawFormatter 

105 # local import to prevent circular dependency 

106 from .rawFormatter import LsstCamRawFormatter 

107 return LsstCamRawFormatter 

108 

109 def register(self, registry): 

110 # Docstring inherited from Instrument.register 

111 # The maximum values below make Gen3's ObservationDataIdPacker produce 

112 # outputs that match Gen2's ccdExposureId. 

113 obsMax = self.translatorClass.max_detector_exposure_id() 

114 registry.insertDimensionData("instrument", 

115 {"name": self.getName(), 

116 "detector_max": self.translatorClass.DETECTOR_MAX, 

117 "visit_max": obsMax, 

118 "exposure_max": obsMax, 

119 "class_name": getFullTypeName(self), 

120 }) 

121 

122 records = [self.extractDetectorRecord(detector) for detector in self.getCamera()] 

123 registry.insertDimensionData("detector", *records) 

124 

125 self._registerFilters(registry) 

126 

127 def extractDetectorRecord(self, camGeomDetector): 

128 """Create a Gen3 Detector entry dict from a cameraGeom.Detector. 

129 """ 

130 # All of the LSST instruments have detector names like R??_S??; we'll 

131 # split them up here, and instruments with only one raft can override 

132 # to change the group to something else if desired. 

133 # Long-term, we should get these fields into cameraGeom separately 

134 # so there's no need to specialize at this stage. 

135 # They are separate in ObservationInfo 

136 group, name = camGeomDetector.getName().split("_") 

137 

138 # getType() returns a pybind11-wrapped enum, which unfortunately 

139 # has no way to extract the name of just the value (it's always 

140 # prefixed by the enum type name). 

141 purpose = str(camGeomDetector.getType()).split(".")[-1] 

142 

143 return dict( 

144 instrument=self.getName(), 

145 id=camGeomDetector.getId(), 

146 full_name=camGeomDetector.getName(), 

147 name_in_raft=name, 

148 purpose=purpose, 

149 raft=group, 

150 ) 

151 

152 def makeDataIdTranslatorFactory(self) -> TranslatorFactory: 

153 # Docstring inherited from lsst.obs.base.Instrument. 

154 factory = TranslatorFactory() 

155 factory.addGenericInstrumentRules(self.getName(), detectorKey="detector", exposureKey="expId") 

156 return factory 

157 

158 

159class LsstComCam(LsstCam): 

160 """Gen3 Butler specialization for ComCam data. 

161 """ 

162 

163 instrument = "LSSTComCam" 

164 policyName = "comCam" 

165 translatorClass = LsstComCamTranslator 

166 

167 def getRawFormatter(self, dataId): 

168 # local import to prevent circular dependency 

169 from .rawFormatter import LsstComCamRawFormatter 

170 return LsstComCamRawFormatter 

171 

172 

173class LsstImSim(LsstCam): 

174 """Gen3 Butler specialization for ImSim simulations. 

175 """ 

176 

177 instrument = "LSST-ImSim" 

178 policyName = "imsim" 

179 translatorClass = LsstImSimTranslator 

180 

181 def getRawFormatter(self, dataId): 

182 # local import to prevent circular dependency 

183 from .rawFormatter import LsstImSimRawFormatter 

184 return LsstImSimRawFormatter 

185 

186 

187class LsstPhoSim(LsstCam): 

188 """Gen3 Butler specialization for Phosim simulations. 

189 """ 

190 

191 instrument = "LSST-PhoSim" 

192 policyName = "phosim" 

193 translatorClass = LsstPhoSimTranslator 

194 

195 def getRawFormatter(self, dataId): 

196 # local import to prevent circular dependency 

197 from .rawFormatter import LsstPhoSimRawFormatter 

198 return LsstPhoSimRawFormatter 

199 

200 

201class LsstTS8(LsstCam): 

202 """Gen3 Butler specialization for raft test stand data. 

203 """ 

204 

205 instrument = "LSST-TS8" 

206 policyName = "ts8" 

207 translatorClass = LsstTS8Translator 

208 

209 def getRawFormatter(self, dataId): 

210 # local import to prevent circular dependency 

211 from .rawFormatter import LsstTS8RawFormatter 

212 return LsstTS8RawFormatter 

213 

214 

215class LsstUCDCam(LsstCam): 

216 """Gen3 Butler specialization for UCDCam test stand data. 

217 """ 

218 

219 instrument = "LSST-UCDCam" 

220 policyName = "ucd" 

221 translatorClass = LsstUCDCamTranslator 

222 

223 def getRawFormatter(self, dataId): 

224 # local import to prevent circular dependency 

225 from .rawFormatter import LsstUCDCamRawFormatter 

226 return LsstUCDCamRawFormatter 

227 

228 

229class LsstTS3(LsstCam): 

230 """Gen3 Butler specialization for TS3 test stand data. 

231 """ 

232 

233 instrument = "LSST-TS3" 

234 policyName = "ts3" 

235 translatorClass = LsstTS3Translator 

236 

237 def getRawFormatter(self, dataId): 

238 # local import to prevent circular dependency 

239 from .rawFormatter import LsstTS3RawFormatter 

240 return LsstTS3RawFormatter 

241 

242 

243class Latiss(LsstCam): 

244 """Gen3 Butler specialization for AuxTel LATISS data. 

245 """ 

246 filterDefinitions = LATISS_FILTER_DEFINITIONS 

247 instrument = "LATISS" 

248 policyName = "latiss" 

249 translatorClass = LatissTranslator 

250 

251 def extractDetectorRecord(self, camGeomDetector): 

252 # Override to remove group (raft) name, because LATISS only has one 

253 # detector. 

254 record = super().extractDetectorRecord(camGeomDetector) 

255 record["raft"] = None 

256 record["name_in_raft"] = record["full_name"] 

257 return record 

258 

259 def getRawFormatter(self, dataId): 

260 # local import to prevent circular dependency 

261 from .rawFormatter import LatissRawFormatter 

262 return LatissRawFormatter