Coverage for python/lsst/obs/lsst/_instrument.py: 66%

112 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-06-09 03:52 -0700

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", "LsstCamImSim", "LsstCamPhoSim", "LsstTS8", 

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

24 

25import os.path 

26 

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 lsst.obs.base.gen2to3 import TranslatorFactory 

32from .filters import (LSSTCAM_FILTER_DEFINITIONS, LATISS_FILTER_DEFINITIONS, 

33 LSSTCAM_IMSIM_FILTER_DEFINITIONS, TS3_FILTER_DEFINITIONS, 

34 TS8_FILTER_DEFINITIONS, COMCAM_FILTER_DEFINITIONS, 

35 ) 

36 

37from .translators import LatissTranslator, LsstCamTranslator, \ 

38 LsstUCDCamTranslator, LsstTS3Translator, LsstComCamTranslator, \ 

39 LsstCamPhoSimTranslator, LsstTS8Translator, LsstCamImSimTranslator 

40 

41PACKAGE_DIR = getPackageDir("obs_lsst") 

42 

43 

44class LsstCam(Instrument): 

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

46 

47 Parameters 

48 ---------- 

49 camera : `lsst.cameraGeom.Camera` 

50 Camera object from which to extract detector information. 

51 filters : `list` of `FilterDefinition` 

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

53 associated with this instrument in the registry. 

54 

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

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

57 representations defined by an Instrument do not. Instead: 

58 

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

60 camera, which should be static information that actually reflects 

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

62 the distinction between physical sensors and slots is unimportant in 

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

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

65 the future this distinction between static and time-dependent 

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

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

68 carries static content). 

69 

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

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

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

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

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

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

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

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

78 future. 

79 """ 

80 filterDefinitions = LSSTCAM_FILTER_DEFINITIONS 

81 instrument = "LSSTCam" 

82 policyName = "lsstCam" 

83 translatorClass = LsstCamTranslator 

84 obsDataPackage = "obs_lsst_data" 

85 visitSystem = VisitSystem.BY_SEQ_START_END 

86 

87 @property 

88 def configPaths(self): 

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

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

91 

92 @classmethod 

93 def getName(cls): 

94 # Docstring inherited from Instrument.getName 

95 return cls.instrument 

96 

97 @classmethod 

98 def getCamera(cls): 

99 # Constructing a YAML camera takes a long time but we rely on 

100 # yamlCamera to cache for us. 

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

102 camera = yamlCamera.makeCamera(cameraYamlFile) 

103 if camera.getName() != cls.getName(): 

104 raise RuntimeError(f"Expected to read camera geometry for {cls.instrument}" 

105 f" but instead got geometry for {camera.getName()}") 

106 return camera 

107 

108 def getRawFormatter(self, dataId): 

109 # Docstring inherited from Instrument.getRawFormatter 

110 # local import to prevent circular dependency 

111 from .rawFormatter import LsstCamRawFormatter 

112 return LsstCamRawFormatter 

113 

114 def register(self, registry, update=False): 

115 # Docstring inherited from Instrument.register 

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

117 # outputs that match Gen2's ccdExposureId. 

118 obsMax = self.translatorClass.max_exposure_id() 

119 with registry.transaction(): 

120 registry.syncDimensionData( 

121 "instrument", 

122 { 

123 "name": self.getName(), 

124 "detector_max": self.translatorClass.DETECTOR_MAX, 

125 "visit_max": obsMax, 

126 "exposure_max": obsMax, 

127 "class_name": get_full_type_name(self), 

128 "visit_system": self.visitSystem.value, 

129 }, 

130 update=update 

131 ) 

132 for detector in self.getCamera(): 

133 registry.syncDimensionData("detector", self.extractDetectorRecord(detector), update=update) 

134 

135 self._registerFilters(registry, update=update) 

136 

137 def extractDetectorRecord(self, camGeomDetector): 

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

139 """ 

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

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

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

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

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

145 # They are separate in ObservationInfo 

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

147 

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

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

150 # prefixed by the enum type name). 

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

152 

153 return dict( 

154 instrument=self.getName(), 

155 id=camGeomDetector.getId(), 

156 full_name=camGeomDetector.getName(), 

157 name_in_raft=name, 

158 purpose=purpose, 

159 raft=group, 

160 ) 

161 

162 def makeDataIdTranslatorFactory(self) -> TranslatorFactory: 

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

164 factory = TranslatorFactory() 

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

166 return factory 

167 

168 

169class LsstComCam(LsstCam): 

170 """Gen3 Butler specialization for ComCam data. 

171 """ 

172 

173 filterDefinitions = COMCAM_FILTER_DEFINITIONS 

174 instrument = "LSSTComCam" 

175 policyName = "comCam" 

176 translatorClass = LsstComCamTranslator 

177 

178 def getRawFormatter(self, dataId): 

179 # local import to prevent circular dependency 

180 from .rawFormatter import LsstComCamRawFormatter 

181 return LsstComCamRawFormatter 

182 

183 

184class LsstCamImSim(LsstCam): 

185 """Gen3 Butler specialization for ImSim simulations. 

186 """ 

187 

188 instrument = "LSSTCam-imSim" 

189 policyName = "imsim" 

190 translatorClass = LsstCamImSimTranslator 

191 filterDefinitions = LSSTCAM_IMSIM_FILTER_DEFINITIONS 

192 visitSystem = VisitSystem.ONE_TO_ONE 

193 

194 def getRawFormatter(self, dataId): 

195 # local import to prevent circular dependency 

196 from .rawFormatter import LsstCamImSimRawFormatter 

197 return LsstCamImSimRawFormatter 

198 

199 

200class LsstCamPhoSim(LsstCam): 

201 """Gen3 Butler specialization for Phosim simulations. 

202 """ 

203 

204 instrument = "LSSTCam-PhoSim" 

205 policyName = "phosim" 

206 translatorClass = LsstCamPhoSimTranslator 

207 visitSystem = VisitSystem.ONE_TO_ONE 

208 

209 def getRawFormatter(self, dataId): 

210 # local import to prevent circular dependency 

211 from .rawFormatter import LsstCamPhoSimRawFormatter 

212 return LsstCamPhoSimRawFormatter 

213 

214 

215class LsstTS8(LsstCam): 

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

217 """ 

218 

219 filterDefinitions = TS8_FILTER_DEFINITIONS 

220 instrument = "LSST-TS8" 

221 policyName = "ts8" 

222 translatorClass = LsstTS8Translator 

223 visitSystem = VisitSystem.ONE_TO_ONE 

224 

225 def getRawFormatter(self, dataId): 

226 # local import to prevent circular dependency 

227 from .rawFormatter import LsstTS8RawFormatter 

228 return LsstTS8RawFormatter 

229 

230 

231class LsstUCDCam(LsstCam): 

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

233 """ 

234 

235 instrument = "LSST-UCDCam" 

236 policyName = "ucd" 

237 translatorClass = LsstUCDCamTranslator 

238 visitSystem = VisitSystem.ONE_TO_ONE 

239 

240 def getRawFormatter(self, dataId): 

241 # local import to prevent circular dependency 

242 from .rawFormatter import LsstUCDCamRawFormatter 

243 return LsstUCDCamRawFormatter 

244 

245 

246class LsstTS3(LsstCam): 

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

248 """ 

249 

250 filterDefinitions = TS3_FILTER_DEFINITIONS 

251 instrument = "LSST-TS3" 

252 policyName = "ts3" 

253 translatorClass = LsstTS3Translator 

254 visitSystem = VisitSystem.ONE_TO_ONE 

255 

256 def getRawFormatter(self, dataId): 

257 # local import to prevent circular dependency 

258 from .rawFormatter import LsstTS3RawFormatter 

259 return LsstTS3RawFormatter 

260 

261 

262class Latiss(LsstCam): 

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

264 """ 

265 filterDefinitions = LATISS_FILTER_DEFINITIONS 

266 instrument = "LATISS" 

267 policyName = "latiss" 

268 translatorClass = LatissTranslator 

269 

270 def extractDetectorRecord(self, camGeomDetector): 

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

272 # detector. 

273 record = super().extractDetectorRecord(camGeomDetector) 

274 record["raft"] = None 

275 record["name_in_raft"] = record["full_name"] 

276 return record 

277 

278 def getRawFormatter(self, dataId): 

279 # local import to prevent circular dependency 

280 from .rawFormatter import LatissRawFormatter 

281 return LatissRawFormatter