Coverage for rta_reconstruction/utils/optics.py: 85%

39 statements  

« prev     ^ index     » next       coverage.py v7.6.4, created at 2024-11-02 09:59 +0000

1from enum import Enum, StrEnum, unique 

2 

3import astropy.units as u 

4import numpy as np 

5 

6 

7@unique 

8class SizeType(StrEnum): 

9 """ 

10 Enumeration of different telescope sizes (LST, MST, SST) 

11 """ 

12 

13 #: Unkown 

14 UNKNOWN = "UNKNOWN" 

15 #: A telescope with a mirror diameter larger than 16m 

16 LST = "LST" 

17 #: A telescope with a mirror diameter larger than 8m 

18 MST = "MST" 

19 #: Telescopes with a mirror diameter smaller than 8m 

20 SST = "SST" 

21 

22 

23@unique 

24class ReflectorShape(Enum): 

25 """ 

26 Enumeration of the different reflector shapes 

27 """ 

28 

29 #: Unkown 

30 UNKNOWN = "UNKNOWN" 

31 #: A telescope with a parabolic dish 

32 PARABOLIC = "PARABOLIC" 

33 #: A telescope with a Davies--Cotton dish 

34 DAVIES_COTTON = "DAVIES_COTTON" 

35 #: A telescope with a hybrid between parabolic and Davies--Cotton dish 

36 HYBRID = "HYBRID" 

37 #: A dual mirror Schwarzschild-Couder reflector 

38 SCHWARZSCHILD_COUDER = "SCHWARZSCHILD_COUDER" 

39 

40 

41class OpticsDescription: 

42 """ 

43 Describes the optics of a Cherenkov Telescope mirror 

44 

45 The string representation of an `OpticsDescription` will be a combination 

46 of the telescope-type and sub-type as follows: "type-subtype". You can 

47 also get each individually. 

48 

49 Parameters 

50 ---------- 

51 name : str 

52 Name of this optical system 

53 n_mirrors : int 

54 Number of mirrors, i. e. 2 for Schwarzschild-Couder else 1 

55 equivalent_focal_length : astropy.units.Quantity[length] 

56 Equivalent focal-length of telescope, independent of which type of 

57 optics (as in the Monte-Carlo). This is the nominal focal length 

58 for single mirror telescopes and the equivalent focal length for dual 

59 mirror telescopes. 

60 effective_focal_length : astropy.units.Quantity[length] 

61 The effective_focal_length is the focal length estimated from 

62 ray tracing to correct for coma aberration. It is thus not automatically 

63 available for all simulations, but only if it was set beforehand 

64 in the simtel configuration. This is the focal length that should be 

65 used for transforming from camera frame to telescope frame for all 

66 reconstruction tasks to correct for the mean aberration. 

67 mirror_area : astropy.units.Quantity[area] 

68 total reflective surface area of the optical system (in m^2) 

69 n_mirror_tiles : int 

70 number of mirror facets 

71 

72 Raises 

73 ------ 

74 ValueError: 

75 if tel_type or mirror_type are not one of the accepted values 

76 TypeError, astropy.units.UnitsError: 

77 if the units of one of the inputs are missing or incompatible 

78 """ 

79 

80 CURRENT_TAB_VERSION = "4.0" 

81 COMPATIBLE_VERSIONS = {"4.0"} 

82 

83 __slots__ = ( 

84 "name", 

85 "size_type", 

86 "effective_focal_length", 

87 "equivalent_focal_length", 

88 "mirror_area", 

89 "n_mirrors", 

90 "n_mirror_tiles", 

91 "reflector_shape", 

92 ) 

93 

94 @u.quantity_input( 

95 mirror_area=u.m**2, 

96 equivalent_focal_length=u.m, 

97 effective_focal_length=u.m, 

98 ) 

99 def __init__( 

100 self, 

101 name, 

102 size_type, 

103 n_mirrors, 

104 equivalent_focal_length, 

105 effective_focal_length, 

106 mirror_area, 

107 n_mirror_tiles, 

108 reflector_shape, 

109 ): 

110 self.name = name 

111 self.size_type = SizeType(size_type) 

112 self.reflector_shape = ReflectorShape(reflector_shape) 

113 self.equivalent_focal_length = equivalent_focal_length.to(u.m) 

114 self.effective_focal_length = effective_focal_length.to(u.m) 

115 self.mirror_area = mirror_area 

116 self.n_mirrors = n_mirrors 

117 self.n_mirror_tiles = n_mirror_tiles 

118 

119 def __hash__(self): 

120 """Make this hashable, so it can be used as dict keys or in sets""" 

121 # From python >= 3.10, hash of nan is random, we want a fixed hash also for 

122 # unknown effective focal length: 

123 if np.isnan(self.effective_focal_length.value): 

124 effective_focal_length = -1 

125 else: 

126 effective_focal_length = self.effective_focal_length.to_value(u.m) 

127 

128 return hash( 

129 ( 

130 round(self.equivalent_focal_length.to_value(u.m), 4), 

131 round(effective_focal_length, 4), 

132 round(self.mirror_area.to_value(u.m**2)), 

133 self.size_type.value, 

134 self.reflector_shape.value, 

135 self.n_mirrors, 

136 self.n_mirror_tiles, 

137 ) 

138 ) 

139 

140 def __eq__(self, other): 

141 """For eq, we just compare equal hash""" 

142 return hash(self) == hash(other) 

143 

144 def __str__(self): 

145 return self.name