Coverage for src/susi/base/config/base.py: 98%

45 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2025-06-13 14:15 +0000

1#!/usr/bin/env python3 

2# -*- coding: utf-8 -*- 

3""" 

4Module to specify base configuration 

5 

6@author: hoelken 

7""" 

8import os 

9from dataclasses import dataclass, field 

10 

11from ..globals import IOSpeed 

12from ..header_keys import * 

13from ..exceptions import MissConfigurationException 

14 

15 

16@dataclass 

17class Base: 

18 #: List of Header fields to be copied in any case! 

19 #: This is relevant so far only in blocks D and B. TODO: review 

20 DEFAULT_HEADER_FIELDS = [ 

21 PROJECT_NAME, 

22 CAMERA_NAME, 

23 CAMERA_ID, 

24 DATE_OBS, 

25 TIMESTAMP_US, 

26 TIMESTAMP_MS, 

27 INTEGRATION_TIME, 

28 F2_MECH, 

29 HK_PMU_CUR, 

30 HK_PMU_ANG, 

31 HK_PMU_ANG_ERR, 

32 MOD_STATE, 

33 ADC15_CF_TEMP, 

34 GMTEMP, 

35 TEGMHOUS, 

36 TESMMBAS, 

37 TEPMUCHA, 

38 TEM34BHT, 

39 TESWCPHT, 

40 TESLTWLL, 

41 TEM3, 

42 TEM4, 

43 TEM5, 

44 TEM8, 

45 TEM9, 

46 TEM7, 

47 TEPBSBAS, 

48 TEFWBASE, 

49 TETOCOHT, 

50 TESP12CR, 

51 TESJCRAD, 

52 TEEBXRAD, 

53 TESJCPSP, 

54 TESJFCOF, 

55 TESJCCOF, 

56 TESJFPCB, 

57 TES1CPSP, 

58 TES1FCOF, 

59 TES1CCOF, 

60 TES1FPCB, 

61 TES2CPSP, 

62 TES2FCOF, 

63 TES2CCOF, 

64 TES2FPCB, 

65 SHPX_MODE, 

66 HOTPX_MODE, 

67 DARK_IMAGE, 

68 FLAT_MAP, 

69 FLAT_MAP_MOVING, 

70 FLAT_MAP_SOFT, 

71 DEMOD_MAT, 

72 DEMOD_MODE, 

73 SHEAR_CORR, 

74 ROTATION_ANG, 

75 SLIT_FLAT_OFFSET, 

76 SLIT_FLAT_SLOPE, 

77 SLIT_FLAT_REF_OFFSET, 

78 SLIT_FLAT_REF_FILE, 

79 SLIT_FLAT_REF_SLOPE, 

80 SHIFT_APPLIED, 

81 SHIFT_APPLIED_MOVING_FLAT, 

82 OFFSET_MAP, 

83 WL_CALIBRATED, 

84 MIN_WL_NM, 

85 MIN_WL_PX, 

86 MAX_WL_NM, 

87 MAX_WL_PX, 

88 DISPERSION, 

89 PROCESSOR_NAME, 

90 PROCESSOR_VERS, 

91 PROCESSING_TIME, 

92 PROCESSING_PIPELINE, 

93 BLOCKS_APPLIED, 

94 IMG_RMS, 

95 IMG_MEAN, 

96 IMG_CONTRAST, 

97 IMG_SNR, 

98 SPATIAL_BIN, 

99 TEMPORAL_BIN, 

100 ROI_X0, 

101 ROI_X1, 

102 ROI_Y0, 

103 ROI_Y1, 

104 NAXIS, 

105 NAXIS1, 

106 NAXIS2, 

107 NAXIS3, 

108 NAXIS4, 

109 XSCALE, 

110 XCEN, 

111 YCEN, 

112 COSTHETA, 

113 GPS_TIME, 

114 GPS_LON, 

115 GPS_LAT, 

116 GPS_ALT, 

117 ELEV, 

118 AZIMUTH, 

119 PARANGLE, 

120 P_ANGLE, 

121 SOLAR_B0, 

122 SOLAR_L0, 

123 EARTH_D, 

124 SOLAR_R0, 

125 CW_LOOP, 

126 FLAT_MOD, 

127 PS_STATE, 

128 AP_DOOR, 

129 M2_XPOS, 

130 M2_YPOS, 

131 M2_ZPOS, 

132 M3_POS, 

133 M4_POS, 

134 GMANGU, 

135 GMSTATUS, 

136 GMSTATEX, 

137 SMPOS, 

138 SMEXPOS, 

139 SMSTATUS, 

140 PMUTEMP, 

141 PMUROTSP, 

142 ] 

143 

144 #: The pipeline to use 

145 pipeline: str = 'pipeline_dev' 

146 

147 #: The URL of the SUSI observation log. 

148 obslog_url: str = 'http://10.104.83.191/' 

149 

150 #: Flag to indicate if pipeline results should be pushed to the obslog 

151 publish_results: bool = True 

152 

153 # Obslog id. For internal use 

154 obsid: int = None 

155 

156 # ====== Header keys ====== 

157 #: Header field that provides the timestamp information. For SUSI we use the `us` timestamp. 

158 timestamp_field: str = TIMESTAMP_US 

159 

160 #: The max allowed delta of two consecutively frames in the scale of the timestamp header field. 

161 #: The default for SUSI is `21.4ms` in us. 

162 time_delta: int = 21400 

163 

164 #: The max allowed delta of frames from different cameras in us. 

165 #: The default for SUSI is 0.45 * time_delta 

166 time_delta_cam_sync: float = 0.45 * time_delta 

167 

168 #: Header field that provides the information on the Temperature 

169 #: For SUSI this is the coldfinger tempsensor of the cam(s). 

170 temp_field: str = ADC15_CF_TEMP 

171 

172 #: The max allowed temperature deviation in degree (Default=`0.1`) for all frames 

173 temp_threshold: float = 0.1 

174 

175 #: Header copy information. These header fields will be copied to the generated fits file. 

176 #: fields configured in `equal_header_values` are mandatory here, since this is checked later steps 

177 header_copy_fields: list = field(default_factory=lambda: Base.DEFAULT_HEADER_FIELDS) 

178 

179 #: ROI keys define the Region of Interest in the data. This is provided by the modulation matrix metadata 

180 roi_keys: list = field(default_factory=lambda: [[ROI_X0, ROI_X1], [ROI_Y0, ROI_Y1]]) 

181 

182 #: Define a list of header fields where all files must have the same value, i.e. `Camera ID` 

183 equal_header_values: list = field(default_factory=lambda: [CAMERA_ID, INTEGRATION_TIME]) 

184 

185 # ====== Multi processing ====== 

186 #: Number of workers for MP.simultaneous (multiprocessing) 

187 #: Default = 10% of available CPUs 

188 workers: int = round(os.cpu_count() * 0.2) 

189 

190 #: Configure the IO speed of the data connection 

191 io_speed: IOSpeed = IOSpeed.MEDIUM 

192 

193 #: Default niceness level of the process: +5 

194 #: This value will be added to the nice level of the process (range -20 to 20, default 0). 

195 niceness: int = 5 

196 

197 # ====== Turn Features on and off ====== 

198 #: Set to True if you really do NOT want to apply a dark file 

199 no_dark_correction: bool = False 

200 

201 #: Set to true if you want to prevent images to be automatically cropped to the lid area 

202 no_auto_cropping: bool = False 

203 

204 #: Set to correct for shear distortion (incl.a global rotation) 

205 shear_and_rot_correction: bool = True 

206 

207 #: Set to perform slit flat correction in block F 

208 slit_flat_corr_block_f: bool = False 

209 

210 #: Set to perform slit flat correction in block S 

211 slit_flat_corr_block_s: bool = True 

212 

213 #: Set to perform the slit flat shift analysis 

214 slit_flat_shift_analysis: bool = False 

215 

216 #: prefilter map correction in block f (using amended soft flat Fits, extension 1) 

217 prefilter_correction: bool = True 

218 

219 #: soft flat correction in block f. The soft flat may be provided just for prefilter corr 

220 soft_flat_correction: bool = False 

221 

222 #: Allows to disable sanity header checks 

223 check_header: bool = True 

224 

225 def __repr__(self) -> str: 

226 txt = f'== {self.__class__.__name__} ==\n' 

227 txt += '\n'.join(['{:<21} = {}'.format(k, v) for k, v in self.__dict__.items()]) 

228 return txt 

229 

230 def amend_from_dict(self, data: dict): 

231 """ 

232 Overwrites the parameters with the values from the given dictionary. 

233 All instance variable names are supported as keywords. 

234 All keywords are optional, if the keyword is not present the previous value will be kept. 

235 

236 There is a special key that must follow a specific syntax if given 

237 

238 - 'roi_keys': The Region Of Interest (ROI) keys must be given as a list of lists with length two (2) in 

239 the order of ROI_X, ROI_Y for the 2D image part. (e.g. ROI_X is the ROI in wl direction for SPC cameras) 

240 Example `[['ROI_X0', 'ROI_X1'], ['ROI_Y0', 'ROI_Y1']]` 

241 

242 ### Params 

243 - data: The dictionary to parse. 

244 - c_name: The name of the camera to set defaults for. 

245 

246 ### Returns 

247 the created Config 

248 """ 

249 io_speed = data.pop('io_speed') if 'io_speed' in data else None 

250 for k, v in data.items(): 

251 if not hasattr(self, k): 

252 raise MissConfigurationException(f'{self.__class__.__name__} config has no attribute {k}') 

253 setattr(self, k, v) 

254 if io_speed: 

255 self.io_speed = IOSpeed[io_speed]