Coverage for hiperta_stream/scripts/reorganizer_dl1hiperta300_stream_to_dl1lstchain063.py: 17%

167 statements  

« prev     ^ index     » next       coverage.py v7.4.3, created at 2024-07-16 10:16 +0000

1# !/usr/bin/env python3 

2 

3# Everything is hardcoded to LST telescopes - because this is just a temporal work that will no longer be used 

4# in the moment lstchain upgrades to V0.8 

5 

6import os 

7import tables 

8import argparse 

9import numpy as np 

10from astropy.table import Table, vstack, join 

11from astropy.io.misc.hdf5 import write_table_hdf5 

12import copy 

13import pandas as pd 

14import astropy.units as u 

15from lstchain.io.io import dl1_params_lstcam_key, dl1_images_lstcam_key, add_column_table 

16from lstchain.reco.disp import disp 

17from lstchain.reco.utils import sky_to_camera 

18import time 

19 

20def add_disp_and_mc_type_to_parameters_table(dl1_file, table_path): 

21 """ 

22 HARDCODED function obtained from `lstchain.reco.dl0_to_dl1` because `mc_alt_tel` and `mc_az_tel` are zipped within 

23 `run_array_direction`. 

24 1. Reconstruct the disp parameters and source position from a DL1 parameters table and write the result in the file. 

25 2. Computes mc_type from the name of the file. 

26 

27 

28 Parameters 

29 ---------- 

30 dl1_file: HDF5 DL1 file containing the required field in `table_path`: 

31 - mc_alt 

32 - mc_az 

33 - mc_alt_tel 

34 - mc_az_tel 

35 

36 table_path: path to the parameters table in the file 

37 

38 Returns 

39 ------- 

40 None 

41 """ 

42 with tables.open_file(dl1_file) as hfile: 

43 run_array_dir = copy.copy(hfile.root.simulation.run_config.col('run_array_direction')[0]) 

44 # Remember that /telescope has been moved previously 

45 focal = copy.copy(hfile.root.instrument.telescope.optics.col('equivalent_focal_length')[0]) 

46 

47 df = pd.read_hdf(dl1_file, key=table_path) 

48 

49 

50 source_pos_in_camera = sky_to_camera(df.mc_alt.values * u.rad, 

51 df.mc_az.values * u.rad, 

52 focal * u.m, 

53 run_array_dir[1] * u.rad, 

54 run_array_dir[0] * u.rad, 

55 ) 

56 

57 disp_parameters = disp(df.x.values * u.m, 

58 df.y.values * u.m, 

59 source_pos_in_camera.x, 

60 source_pos_in_camera.y) 

61 

62 with tables.open_file(dl1_file, mode="a") as file: 

63 tab = file.root[table_path] 

64 add_column_table(tab, tables.Float32Col, 'disp_dx', disp_parameters[0].value) 

65 tab = file.root[table_path] 

66 add_column_table(tab, tables.Float32Col, 'disp_dy', disp_parameters[1].value) 

67 tab = file.root[table_path] 

68 add_column_table(tab, tables.Float32Col, 'disp_norm', disp_parameters[2].value) 

69 tab = file.root[table_path] 

70 add_column_table(tab, tables.Float32Col, 'disp_angle', disp_parameters[3].value) 

71 tab = file.root[table_path] 

72 add_column_table(tab, tables.Float32Col, 'disp_sign', disp_parameters[4]) 

73 tab = file.root[table_path] 

74 add_column_table(tab, tables.Float32Col, 'src_x', source_pos_in_camera.x.value) 

75 tab = file.root[table_path] 

76 add_column_table(tab, tables.Float32Col, 'src_y', source_pos_in_camera.y.value) 

77 tab = file.root[table_path] 

78 add_column_table(tab, tables.Float32Col, 'mc_alt_tel', np.ones(len(df)) * run_array_dir[1]) 

79 tab = file.root[table_path] 

80 add_column_table(tab, tables.Float32Col, 'mc_az_tel', np.ones(len(df)) * run_array_dir[0]) 

81 if 'gamma' in dl1_file: 

82 tab = file.root[table_path] 

83 add_column_table(tab, tables.Float32Col, 'mc_type', np.zeros(len(df))) 

84 if 'electron' in dl1_file: 

85 tab = file.root[table_path] 

86 add_column_table(tab, tables.Float32Col, 'mc_type', np.ones(len(df))) 

87 if 'proton' in dl1_file: 

88 tab = file.root[table_path] 

89 add_column_table(tab, tables.Float32Col, 'mc_type', 101*np.ones(len(df))) 

90 

91 

92def stack_and_write_images_table(input_filename, hfile_out, node_dl1_event): 

93 """ 

94 Stack all the `tel_00X` image tables (in case they exit) and write in the v0.6 file 

95 

96 Parameters 

97 input_filename : [str] input hfile name 

98 hfile_out : output File pointer 

99 node_dl1_event : Output hfile (V0.6) dl1.event node pointer 

100 """ 

101 telescope_node = node_dl1_event.telescope 

102 

103 imag_per_tels = [Table(table_img.read()) for table_img in telescope_node.image] 

104 image_table = vstack(imag_per_tels) 

105 

106 for tab in telescope_node.image: 

107 hfile_out.remove_node(tab) 

108 

109 # Todo change names of column `image_mask` to `` ?? 

110 

111 dump_plus_copy_node_to_create_new_table(input_filename, 

112 hfile_out, 

113 image_table, 

114 hfile_out.root.dl1.event.telescope.image, 

115 newname_pointer='LST_LSTCam', 

116 tmp_name='imgsTable') 

117 

118 

119def stack_and_write_parameters_table(input_filename, hfile_out, node_dl1_event, output_mc_table_pointer): 

120 """ 

121 Stack all the `tel_00X` parameters tables (of v0.8), change names of the columns and write the table in the 

122 V0.6 (lstchain like) format 

123 

124 Parameters 

125 hfile_out : output File pointer 

126 node_dl1_event : Output hfile (V0.6) dl1.event node pointer 

127 output_mc_table_pointer : output subarray node pointer 

128 """ 

129 telescope_node = node_dl1_event.telescope 

130 

131 param_per_tels = [Table(table_param.read()) for table_param in telescope_node.parameters] 

132 parameter_table = vstack(param_per_tels) 

133 

134 for tab in telescope_node.parameters: 

135 hfile_out.remove_node(tab) 

136 

137 parameter_table.rename_column('hillas_intensity', 'intensity') 

138 parameter_table.rename_column('hillas_x', 'x') 

139 parameter_table.rename_column('hillas_y', 'y') 

140 parameter_table.rename_column('hillas_r', 'r') 

141 parameter_table.rename_column('hillas_phi', 'phi') 

142 parameter_table.rename_column('hillas_length', 'length') 

143 parameter_table.rename_column('hillas_width', 'width') 

144 parameter_table.rename_column('hillas_psi', 'psi') 

145 parameter_table.rename_column('hillas_skewness', 'skewness') 

146 parameter_table.rename_column('hillas_kurtosis', 'kurtosis') 

147 parameter_table.rename_column('timing_slope', 'time_gradient') 

148 parameter_table.rename_column('timing_intercept', 'intercept') 

149 parameter_table.rename_column('morphology_num_pixels', 'n_pixels') 

150 parameter_table.rename_column('morphology_num_islands', 'n_islands') 

151 parameter_table.add_column(np.log10(parameter_table['intensity']), name='log_intensity') 

152 parameter_table.add_column(parameter_table['width'] / parameter_table['length'], name='wl') 

153 

154 # Param table is indeed huge - it contains all the mc_events parameters (from v0.6 !!) too 

155 try: 

156 mc_shower_pointer = output_mc_table_pointer.mc_shower 

157 except: 

158 mc_shower_pointer = None 

159 if mc_shower_pointer is not None: 

160 mc_event_table = Table(mc_shower_pointer.read()) 

161 mc_event_table.remove_column('obs_id') 

162 parameter_table = join(parameter_table, mc_event_table, keys='event_id') 

163 parameter_table.add_column(np.log10(parameter_table['mc_energy']), name='log_mc_energy') 

164 

165 dump_plus_copy_node_to_create_new_table(input_filename, 

166 hfile_out, 

167 parameter_table, 

168 hfile_out.root.dl1.event.telescope.parameters, 

169 newname_pointer='LST_LSTCam', 

170 tmp_name='paramsTable') 

171 

172 

173def dump_plus_copy_node_to_create_new_table(input_filename, hfile_out, astropy_table_to_copy, newparent_pointer, 

174 newname_pointer, tmp_name, overwrite=False): 

175 """ 

176 General function to write an astropy table to a temporal file, and immediately after copy it to the 

177 output v0.6 hfile. 

178 

179 Parameters 

180 input_filename : [ste] input hfile name 

181 hfile_out : output File pointer 

182 astropy_table_to_copy : astropy table to be copied 

183 newparent_pointer : newparent copy_node parameter 

184 newname_pointer : newname copy_node parameter 

185 tmp_name : [str] flag to identify the temportal table and make it unique (necessary when simultaneous reorganizers 

186 are run in the same dir) 

187 overwrite : overwrite parameter of the copy_node method 

188 """ 

189 input_filename = input_filename.split('___')[0] 

190 if tmp_name == '': 

191 flag_name = 'UNKNOWN' 

192 else: 

193 flag_name = tmp_name 

194 

195 temp_table_name = f'{input_filename}_tmp_table_reoganizer_{flag_name}.tmp_hdf5_file' 

196 write_table_hdf5(astropy_table_to_copy, temp_table_name, path='/root') 

197 temp_table = tables.open_file(temp_table_name, 'r') 

198 hfile_out.copy_node(temp_table.root.root, newparent=newparent_pointer, newname=newname_pointer, overwrite=overwrite) 

199 temp_table.close() 

200 os.remove(temp_table_name) 

201 

202 

203def rename_mc_shower_colnames(input_filename, hfile_out, event_node, output_mc_table_pointer): 

204 """ 

205 Rename column names of the `mc_shower` table and dump the table to the v0.6 output hfile. 

206 

207 Parameters 

208 input_filename : [ste] input hfile name 

209 hfile_out : output File pointer 

210 event_node : root.dl1.event node (of output hfile, so V0.6) 

211 output_mc_table_pointer : output subarray node pointer 

212 """ 

213 mc_shower_table = Table(event_node.subarray.mc_shower.read()) 

214 mc_shower_table.rename_column('true_energy', 'mc_energy') 

215 mc_shower_table.rename_column('true_alt', 'mc_alt') 

216 mc_shower_table.rename_column('true_az', 'mc_az') 

217 mc_shower_table.rename_column('true_core_x', 'mc_core_x') 

218 mc_shower_table.rename_column('true_core_y', 'mc_core_y') 

219 mc_shower_table.rename_column('true_h_first_int', 'mc_h_first_int') 

220 mc_shower_table.rename_column('true_x_max', 'mc_x_max') 

221 mc_shower_table.rename_column('true_shower_primary_id', 'mc_shower_primary_id') 

222 

223 dump_plus_copy_node_to_create_new_table(input_filename, 

224 hfile_out, 

225 mc_shower_table, 

226 output_mc_table_pointer, 

227 newname_pointer='mc_shower', 

228 tmp_name='mcShowerTable', 

229 overwrite=True) 

230 

231 

232def create_hfile_out(input_filename, outfile_name, sim_pointer08, config_pointer08, dl1_pointer08, filter_pointer08): 

233 """ 

234 Create output hfile (lstchainv0.6 like hdf5 file) 

235 

236 Parameters 

237 input_filename : [ste] input hfile name 

238 outfile_name : [str] output hfile name 

239 sim_pointer08 : dl1-file_v0.8_simulation pointer 

240 config_pointer08 : dl1-file_v.08_configuration pointer 

241 dl1_pointer08 : dl1-file_v0.8_dl1 pointer 

242 filter_pointer08 : dl1-file_v0.8 filters pointer 

243 """ 

244 hfile_out = tables.open_file(outfile_name, 'w') 

245 hfile_out.create_group('/', 'simulation') 

246 hfile_out.create_group('/', 'dl1') 

247 

248 if sim_pointer08 is not None: 

249 # Simulation node V0.6 

250 # /simulation (Group) 'Simulation information of the run' 

251 # children := ['mc_event' (Table), 'run_config' (Table), 'thrown_event_distribution' (Table)] 

252 hfile_out.copy_node(sim_pointer08.service.shower_distribution, 

253 newparent=hfile_out.root.simulation, 

254 newname='thrown_event_distribution', 

255 recursive=True, 

256 filters=filter_pointer08) 

257 hfile_out.copy_node(config_pointer08.simulation.run, 

258 newparent=hfile_out.root.simulation, 

259 newname='run_config', 

260 recursive=True, 

261 filters=filter_pointer08) 

262 

263 # Instrument node V0.6 

264 # --instrument (Group) 

265 # +--telescope (Group) 

266 # | +--camera (Group) 

267 # +--readout_LSTCam --> copied free, it can be erase. 

268 # +--geometry_LSTCAM --> To be renamed to LSTCam 

269 # | `--optics (Table) 

270 # `--subarray (Group) 

271 # `--layout (Table) 

272 instrument_node = hfile_out.copy_node(config_pointer08.instrument, 

273 newparent=hfile_out.root, 

274 recursive=True, 

275 filters=filter_pointer08) 

276 hfile_out.rename_node(instrument_node.telescope.camera.geometry_LSTCam, newname='LSTCam') 

277 

278 # dl1 node V0.6 

279 # +--dl1 (Group) 

280 # `--event (Group) 

281 # +--telescope (Group) 

282 # +--image (Group) 

283 # `--parameters (Group) 

284 # `--subarray (Group) 

285 # +--mc_shower (Table) 

286 # `--trigger (Table) 

287 dl1_event_node06 = hfile_out.copy_node(dl1_pointer08.event, 

288 newparent=hfile_out.root.dl1, 

289 recursive=True, 

290 filters=filter_pointer08) 

291 # This will only happen on ctapipe, not RTA 

292 # hfile_out.remove_node(dl1_event_node06.telescope.trigger) # Table stored twice, remove to avoid problems. 

293 try: 

294 hfile_out.rename_node(dl1_event_node06.telescope.images, newname='image') 

295 except tables.exceptions.NoSuchNodeError as e: 

296 print(f' ** {e} Exception: No images group in the file in dl1/event/telescope/. \n' 

297 f' Check the merging configuration, indeed.') 

298 

299 try: 

300 subarray_pointer = hfile_out.root.dl1.event.subarray 

301 # root.dl1.event.subarray.trigger 

302 except tables.exceptions.NoSuchNodeError as e: 

303 print(f' ** {e} Exception: No subarray pointer in dl1/event.') 

304 subarray_pointer = None 

305 

306 if sim_pointer08 is not None: 

307 hfile_out.copy_node(sim_pointer08.event.subarray.shower, 

308 newparent=subarray_pointer, 

309 newname="mc_shower", 

310 recursive=True, 

311 filters=filter_pointer08) 

312 if subarray_pointer is not None and sim_pointer08 is not None: 

313 rename_mc_shower_colnames(input_filename, 

314 hfile_out, 

315 dl1_event_node06, 

316 subarray_pointer 

317 ) 

318 

319 stack_and_write_parameters_table(input_filename, 

320 hfile_out, 

321 dl1_event_node06, 

322 subarray_pointer 

323 ) 

324 

325 if 'image' in dl1_event_node06.telescope: 

326 stack_and_write_images_table(input_filename, 

327 hfile_out, 

328 dl1_event_node06 

329 ) 

330 

331 hfile_out.close() 

332 

333 

334def reorganizer_dl1hiperta_stream_to_dl1lstchain063(infile, outfile, nb_tries=100, timeout=0.1): 

335 """Main function to run the reorganiser""" 

336 

337 for i in range(nb_tries): 

338 try: 

339 hfile = tables.open_file(infile, 'r') 

340 break 

341 except Exception as e: 

342 time.sleep(timeout) 

343 print("retry "+str(i)) 

344 else: 

345 # try 1 last time, let tables error raise if failing 

346 hfile = tables.open_file(infile, 'r') 

347 

348 # dl1 v0.8 Pointers 

349 try: 

350 simulation_v08 = hfile.root.simulation 

351 except tables.exceptions.NoSuchNodeError as e: 

352 print(f' ** {e} exception: No Simulation group found in the root group of the file.') 

353 simulation_v08 = None 

354 

355 configuration_v08 = hfile.root.configuration 

356 dl1_v08 = hfile.root.dl1 

357 filter_v08 = hfile.filters 

358 

359 create_hfile_out(infile, outfile, simulation_v08, configuration_v08, dl1_v08, filter_v08) 

360 

361 # Add disp_* and mc_type to the parameters table. 

362 if simulation_v08 is not None: 

363 add_disp_and_mc_type_to_parameters_table(outfile, 'dl1/event/telescope/parameters/LST_LSTCam') 

364 

365 hfile.close() 

366 

367 

368def main(): 

369 """ 

370 Conversion from dl1 data model (ctapipe and hiper(CTA)RTA) data model, and convert it to lstchain_v0.6 data mode. 

371 """ 

372 parser = argparse.ArgumentParser(description="Re-organize the dl1 `standard` output file from either the " 

373 "hiptecta_r1_to_dl1 or hiperta_r1_dl1 to the lstchain DL1 structure") 

374 

375 parser.add_argument('--infile', '-i', 

376 type=str, 

377 dest='infile', 

378 help='dl1 output file of `hiperta_r0_dl1` to be converted to dl1lstchain_v060', 

379 default=None 

380 ) 

381 

382 parser.add_argument('--outfile', '-o', 

383 type=str, 

384 dest='outfile', 

385 help='Output filename. dl1_reorganized.h5 by default.', 

386 default='./dl1v0.6_reorganized.h5' 

387 ) 

388 parser.add_argument('--nb-file-open-tries', '-n', 

389 type=int, 

390 dest='nb_file_tries', 

391 help="Number of time the script should try to open a file (which can fail due to filesystem)", 

392 default=100 

393 ) 

394 parser.add_argument('--open-file-timeout', '-t', 

395 type=float, 

396 dest='file_open_timeout', 

397 help="Time to wait between two attempts opening a file, in second", 

398 default=0.1 

399 ) 

400 

401 args = parser.parse_args() 

402 

403 reorganizer_dl1hiperta_stream_to_dl1lstchain063(args.infile, args.outfile, args.nb_file_tries, args.file_open_timeout) 

404 

405 

406if __name__ == '__main__': 

407 main()