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 _cameraCachedClass = None 

82 translatorClass = LsstCamTranslator 

83 obsDataPackage = "obs_lsst_data" 

84 

85 @property 

86 def configPaths(self): 

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

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

89 

90 @classmethod 

91 def getName(cls): 

92 # Docstring inherited from Instrument.getName 

93 return cls.instrument 

94 

95 @classmethod 

96 def getCamera(cls): 

97 # Constructing a YAML camera takes a long time so cache the result 

98 # We have to be careful to ensure we cache at the subclass level 

99 # since LsstCam base class will look like a cache to the subclasses 

100 if cls._camera is None or cls._cameraCachedClass != cls: 

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

102 cls._camera = yamlCamera.makeCamera(cameraYamlFile) 

103 cls._cameraCachedClass = cls 

104 return cls._camera 

105 

106 def getRawFormatter(self, dataId): 

107 # Docstring inherited from Instrument.getRawFormatter 

108 # local import to prevent circular dependency 

109 from .rawFormatter import LsstCamRawFormatter 

110 return LsstCamRawFormatter 

111 

112 def register(self, registry): 

113 # Docstring inherited from Instrument.register 

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

115 # outputs that match Gen2's ccdExposureId. 

116 obsMax = self.translatorClass.max_detector_exposure_id() 

117 registry.insertDimensionData("instrument", 

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

119 "detector_max": self.translatorClass.DETECTOR_MAX, 

120 "visit_max": obsMax, 

121 "exposure_max": obsMax, 

122 "class_name": getFullTypeName(self), 

123 }) 

124 

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

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

127 

128 self._registerFilters(registry) 

129 

130 def extractDetectorRecord(self, camGeomDetector): 

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

132 """ 

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

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

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

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

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

138 # They are separate in ObservationInfo 

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

140 

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

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

143 # prefixed by the enum type name). 

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

145 

146 return dict( 

147 instrument=self.getName(), 

148 id=camGeomDetector.getId(), 

149 full_name=camGeomDetector.getName(), 

150 name_in_raft=name, 

151 purpose=purpose, 

152 raft=group, 

153 ) 

154 

155 def makeDataIdTranslatorFactory(self) -> TranslatorFactory: 

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

157 factory = TranslatorFactory() 

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

159 return factory 

160 

161 

162class LsstComCam(LsstCam): 

163 """Gen3 Butler specialization for ComCam data. 

164 """ 

165 

166 instrument = "LSSTComCam" 

167 policyName = "comCam" 

168 translatorClass = LsstComCamTranslator 

169 

170 def getRawFormatter(self, dataId): 

171 # local import to prevent circular dependency 

172 from .rawFormatter import LsstComCamRawFormatter 

173 return LsstComCamRawFormatter 

174 

175 

176class LsstImSim(LsstCam): 

177 """Gen3 Butler specialization for ImSim simulations. 

178 """ 

179 

180 instrument = "LSST-ImSim" 

181 policyName = "imsim" 

182 translatorClass = LsstImSimTranslator 

183 

184 def getRawFormatter(self, dataId): 

185 # local import to prevent circular dependency 

186 from .rawFormatter import LsstImSimRawFormatter 

187 return LsstImSimRawFormatter 

188 

189 

190class LsstPhoSim(LsstCam): 

191 """Gen3 Butler specialization for Phosim simulations. 

192 """ 

193 

194 instrument = "LSST-PhoSim" 

195 policyName = "phosim" 

196 translatorClass = LsstPhoSimTranslator 

197 

198 def getRawFormatter(self, dataId): 

199 # local import to prevent circular dependency 

200 from .rawFormatter import LsstPhoSimRawFormatter 

201 return LsstPhoSimRawFormatter 

202 

203 

204class LsstTS8(LsstCam): 

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

206 """ 

207 

208 instrument = "LSST-TS8" 

209 policyName = "ts8" 

210 translatorClass = LsstTS8Translator 

211 

212 def getRawFormatter(self, dataId): 

213 # local import to prevent circular dependency 

214 from .rawFormatter import LsstTS8RawFormatter 

215 return LsstTS8RawFormatter 

216 

217 

218class LsstUCDCam(LsstCam): 

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

220 """ 

221 

222 instrument = "LSST-UCDCam" 

223 policyName = "ucd" 

224 translatorClass = LsstUCDCamTranslator 

225 

226 def getRawFormatter(self, dataId): 

227 # local import to prevent circular dependency 

228 from .rawFormatter import LsstUCDCamRawFormatter 

229 return LsstUCDCamRawFormatter 

230 

231 

232class LsstTS3(LsstCam): 

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

234 """ 

235 

236 instrument = "LSST-TS3" 

237 policyName = "ts3" 

238 translatorClass = LsstTS3Translator 

239 

240 def getRawFormatter(self, dataId): 

241 # local import to prevent circular dependency 

242 from .rawFormatter import LsstTS3RawFormatter 

243 return LsstTS3RawFormatter 

244 

245 

246class Latiss(LsstCam): 

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

248 """ 

249 filterDefinitions = LATISS_FILTER_DEFINITIONS 

250 instrument = "LATISS" 

251 policyName = "latiss" 

252 translatorClass = LatissTranslator 

253 

254 def extractDetectorRecord(self, camGeomDetector): 

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

256 # detector. 

257 record = super().extractDetectorRecord(camGeomDetector) 

258 record["raft"] = None 

259 record["name_in_raft"] = record["full_name"] 

260 return record 

261 

262 def getRawFormatter(self, dataId): 

263 # local import to prevent circular dependency 

264 from .rawFormatter import LatissRawFormatter 

265 return LatissRawFormatter