Coverage for python/lsst/obs/lsst/translators/lsstCam.py: 41%

43 statements  

« prev     ^ index     » next       coverage.py v7.2.6, created at 2023-05-24 09:52 +0000

1# This file is currently part of obs_lsst but is written to allow it 

2# to be migrated to the astro_metadata_translator package at a later date. 

3# 

4# This product includes software developed by the LSST Project 

5# (http://www.lsst.org). 

6# See the LICENSE file in this directory for details of code ownership. 

7# 

8# Use of this source code is governed by a 3-clause BSD-style 

9# license that can be found in the LICENSE file. 

10 

11"""Metadata translation code for the main LSST Camera""" 

12 

13__all__ = ("LsstCamTranslator", ) 

14 

15import logging 

16import astropy.units as u 

17 

18from astro_metadata_translator.translators.helpers import is_non_science 

19 

20from .lsst import LsstBaseTranslator, SIMONYI_TELESCOPE 

21 

22log = logging.getLogger(__name__) 

23 

24# Normalized name of the LSST Camera 

25LSST_CAM = "LSSTCam" 

26 

27 

28def is_non_science_or_lab(self): 

29 """Pseudo method to determine whether this is a lab or non-science 

30 header. 

31 

32 Raises 

33 ------ 

34 KeyError 

35 If this is a science observation and on the mountain. 

36 """ 

37 # Return without raising if this is not a science observation 

38 # since the defaults are fine. 

39 try: 

40 # This will raise if it is a science observation. 

41 is_non_science(self) 

42 return 

43 except KeyError: 

44 pass 

45 

46 # We are still in the lab, return and use the default. 

47 if not self._is_on_mountain(): 

48 return 

49 

50 # This is a science observation on the mountain so we should not 

51 # use defaults. 

52 raise KeyError(f"{self._log_prefix}: Required key is missing and this is a mountain science observation") 

53 

54 

55class LsstCamTranslator(LsstBaseTranslator): 

56 """Metadata translation for the main LSST Camera.""" 

57 

58 name = LSST_CAM 

59 """Name of this translation class""" 

60 

61 supported_instrument = LSST_CAM 

62 """Supports the lsstCam instrument.""" 

63 

64 _const_map = { 

65 "instrument": LSST_CAM, 

66 "telescope": SIMONYI_TELESCOPE, 

67 # Migrate these to full translations once test data appears that 

68 # includes them 

69 "altaz_begin": None, 

70 "object": "UNKNOWN", 

71 "relative_humidity": None, 

72 "temperature": None, 

73 "pressure": None, 

74 } 

75 

76 _trivial_map = { 

77 "detector_group": "RAFTBAY", 

78 "detector_name": "CCDSLOT", 

79 "observation_id": "OBSID", 

80 "exposure_time": ("EXPTIME", dict(unit=u.s)), 

81 "detector_serial": "LSST_NUM", 

82 "science_program": (["PROGRAM", "RUNNUM"], dict(default="unknown")), 

83 "boresight_rotation_angle": (["ROTPA", "ROTANGLE"], dict(checker=is_non_science_or_lab, 

84 default=0.0, unit=u.deg)), 

85 } 

86 

87 # Use Imsim raft definitions until a true lsstCam definition exists 

88 cameraPolicyFile = "policy/lsstCam.yaml" 

89 

90 @classmethod 

91 def fix_header(cls, header, instrument, obsid, filename=None): 

92 """Fix LSSTCam headers. 

93 

94 Notes 

95 ----- 

96 See `~astro_metadata_translator.fix_header` for details of the general 

97 process. 

98 """ 

99 

100 modified = False 

101 

102 # Calculate the standard label to use for log messages 

103 log_label = cls._construct_log_prefix(obsid, filename) 

104 

105 if "FILTER" not in header and header.get("FILTER2") is not None: 

106 ccdslot = header.get("CCDSLOT", "unknown") 

107 raftbay = header.get("RAFTBAY", "unknown") 

108 

109 log.warning("%s %s_%s: No FILTER key found but FILTER2=\"%s\" (removed)", 

110 log_label, raftbay, ccdslot, header["FILTER2"]) 

111 header["FILTER2"] = None 

112 modified = True 

113 

114 return modified 

115 

116 @classmethod 

117 def can_translate(cls, header, filename=None): 

118 """Indicate whether this translation class can translate the 

119 supplied header. 

120 

121 Parameters 

122 ---------- 

123 header : `dict`-like 

124 Header to convert to standardized form. 

125 filename : `str`, optional 

126 Name of file being translated. 

127 

128 Returns 

129 ------- 

130 can : `bool` 

131 `True` if the header is recognized by this class. `False` 

132 otherwise. 

133 """ 

134 # INSTRUME keyword might be of two types 

135 if "INSTRUME" in header: 

136 instrume = header["INSTRUME"].lower() 

137 if instrume == cls.supported_instrument.lower(): 

138 return True 

139 return False