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

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"""Butler instrument description for the Dark Energy Camera. 

23""" 

24 

25__all__ = ("DarkEnergyCamera",) 

26 

27import os 

28from functools import lru_cache 

29 

30from lsst.afw.cameraGeom import makeCameraFromPath, CameraConfig 

31from lsst.obs.base import Instrument 

32from lsst.obs.base.gen2to3 import BandToPhysicalFilterKeyHandler, TranslatorFactory 

33from lsst.obs.decam.decamFilters import DECAM_FILTER_DEFINITIONS 

34 

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

36from lsst.utils import getPackageDir 

37 

38 

39class DarkEnergyCamera(Instrument): 

40 filterDefinitions = DECAM_FILTER_DEFINITIONS 

41 policyName = "decam" 

42 obsDataPackage = "obs_decam_data" 

43 

44 def __init__(self, **kwargs): 

45 super().__init__(**kwargs) 

46 packageDir = getPackageDir("obs_decam") 

47 self.configPaths = [os.path.join(packageDir, "config")] 

48 

49 @classmethod 

50 def getName(cls): 

51 return "DECam" 

52 

53 def getCamera(self): 

54 path = os.path.join(getPackageDir("obs_decam"), self.policyName, "camGeom") 

55 return self._getCameraFromPath(path) 

56 

57 @staticmethod 

58 @lru_cache() 

59 def _getCameraFromPath(path): 

60 """Return the camera geometry given solely the path to the location 

61 of that definition.""" 

62 config = CameraConfig() 

63 config.load(os.path.join(path, "camera.py")) 

64 return makeCameraFromPath( 

65 cameraConfig=config, 

66 ampInfoPath=path, 

67 shortNameFunc=lambda name: name.replace(" ", "_"), 

68 ) 

69 

70 def register(self, registry): 

71 camera = self.getCamera() 

72 # Combined with detector_max=100 (below), obsMax=2**25 causes the 

73 # number of bits in packed IDs to match the Gen2 ones. 

74 obsMax = 2**25 

75 with registry.transaction(): 

76 # Note that detector_max here is really only used for packing 

77 # detector and visit/exposure IDs together into a single integer, 

78 # so it's rounded up to the nearest power of ten to make that 

79 # encoding decodable by humans (and consistent with its previous 

80 # Gen2 definition). There are other checks (database constraints) 

81 # that ensure any ingested raws have "real" detector values, and 

82 # those are based on the detector records added in the loop below. 

83 registry.syncDimensionData( 

84 "instrument", 

85 { 

86 "name": self.getName(), "detector_max": 100, "visit_max": obsMax, "exposure_max": obsMax, 

87 "class_name": getFullTypeName(self), 

88 } 

89 ) 

90 

91 for detector in camera: 

92 registry.syncDimensionData( 

93 "detector", 

94 { 

95 "instrument": self.getName(), 

96 "id": detector.getId(), 

97 "full_name": detector.getName(), 

98 "name_in_raft": detector.getName()[1:], 

99 "raft": detector.getName()[0], 

100 "purpose": str(detector.getType()).split(".")[-1], 

101 } 

102 ) 

103 

104 self._registerFilters(registry) 

105 

106 def getRawFormatter(self, dataId): 

107 # local import to prevent circular dependency 

108 from .rawFormatter import DarkEnergyCameraRawFormatter 

109 return DarkEnergyCameraRawFormatter 

110 

111 def makeDataIdTranslatorFactory(self) -> TranslatorFactory: 

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

113 factory = TranslatorFactory() 

114 factory.addGenericInstrumentRules(self.getName(), calibFilterType="band", 

115 detectorKey="ccdnum") 

116 # DECam calibRegistry entries are bands, but we need physical_filter 

117 # in the gen3 registry. 

118 factory.addRule(BandToPhysicalFilterKeyHandler(self.filterDefinitions), 

119 instrument=self.getName(), 

120 gen2keys=("filter",), 

121 consume=("filter",), 

122 datasetTypeName="cpFlat") 

123 return factory