Coverage for python/lsst/obs/cfht/_instrument.py: 95%

40 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-14 19:25 +0000

1# This file is part of obs_cfht. 

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 CFHT MegaCam camera. 

23""" 

24 

25__all__ = ("MegaPrime",) 

26 

27import importlib.resources 

28import os 

29from functools import lru_cache 

30 

31from astro_metadata_translator import MegaPrimeTranslator 

32from lsst.afw.cameraGeom import makeCameraFromPath, CameraConfig 

33from lsst.obs.base import Instrument, VisitSystem 

34from .cfhtFilters import MEGAPRIME_FILTER_DEFINITIONS 

35 

36from lsst.utils.introspection import get_full_type_name 

37 

38 

39class MegaPrime(Instrument): 

40 filterDefinitions = MEGAPRIME_FILTER_DEFINITIONS 

41 policyName = "megacam" 

42 obsDataPackage = None 

43 translatorClass = MegaPrimeTranslator 

44 

45 def __init__(self, **kwargs): 

46 super().__init__(**kwargs) 

47 self.configPaths = ["resource://lsst.obs.cfht/resources/config"] 

48 

49 @classmethod 

50 def getName(cls): 

51 return "MegaPrime" 

52 

53 def getCamera(self): 

54 # The camera geometry is a directory of files (camera.py plus per-amp 

55 # FITS) consumed by makeCameraFromPath, so it must be presented as a 

56 # local directory. importlib.resources.as_file yields that path 

57 # without requiring an EUPS environment (unlike getPackageDir). 

58 with importlib.resources.as_file( 

59 importlib.resources.files("lsst.obs.cfht").joinpath( 

60 f"resources/{self.policyName}/camera" 

61 ) 

62 ) as path: 

63 return self._getCameraFromPath(str(path)) 

64 

65 @staticmethod 

66 @lru_cache() 

67 def _getCameraFromPath(path): 

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

69 of that definition.""" 

70 config = CameraConfig() 

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

72 return makeCameraFromPath( 

73 cameraConfig=config, 

74 ampInfoPath=path, 

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

76 ) 

77 

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

79 camera = self.getCamera() 

80 obsMax = 2**31 

81 with registry.transaction(): 

82 registry.syncDimensionData( 

83 "instrument", 

84 { 

85 "name": self.getName(), "detector_max": 36, "visit_max": obsMax, "exposure_max": obsMax, 

86 "class_name": get_full_type_name(self), 

87 # Some schemas support default visit_system 

88 "visit_system": VisitSystem.ONE_TO_ONE.value, 

89 }, 

90 update=update 

91 ) 

92 

93 for detector in camera: 

94 registry.syncDimensionData( 

95 "detector", 

96 { 

97 "instrument": self.getName(), 

98 "id": detector.getId(), 

99 "full_name": detector.getName(), 

100 "name_in_raft": detector.getName(), 

101 "raft": None, # MegaPrime does not have rafts 

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

103 }, 

104 update=update 

105 ) 

106 

107 self._registerFilters(registry, update=update) 

108 

109 def getRawFormatter(self, dataId): 

110 # local import to prevent circular dependency 

111 from .rawFormatter import MegaPrimeRawFormatter 

112 return MegaPrimeRawFormatter