gammasimtools 0.18.0__py3-none-any.whl → 0.20.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/METADATA +24 -69
  2. gammasimtools-0.20.0.dist-info/RECORD +395 -0
  3. {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/entry_points.txt +11 -4
  4. {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/licenses/LICENSE +1 -1
  5. simtools/_version.py +16 -3
  6. simtools/applications/calculate_incident_angles.py +182 -0
  7. simtools/applications/convert_all_model_parameters_from_simtel.py +4 -3
  8. simtools/applications/convert_geo_coordinates_of_array_elements.py +3 -3
  9. simtools/applications/db_add_simulation_model_from_repository_to_db.py +17 -14
  10. simtools/applications/db_add_value_from_json_to_db.py +8 -10
  11. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +8 -13
  12. simtools/applications/db_generate_compound_indexes.py +65 -0
  13. simtools/applications/db_get_file_from_db.py +12 -24
  14. simtools/applications/db_get_parameter_from_db.py +4 -4
  15. simtools/applications/db_inspect_databases.py +20 -10
  16. simtools/applications/derive_mirror_rnda.py +17 -11
  17. simtools/applications/derive_psf_parameters.py +59 -309
  18. simtools/applications/derive_trigger_rates.py +91 -0
  19. simtools/applications/docs_produce_array_element_report.py +1 -1
  20. simtools/applications/docs_produce_calibration_reports.py +1 -1
  21. simtools/applications/docs_produce_model_parameter_reports.py +1 -1
  22. simtools/applications/docs_produce_simulation_configuration_report.py +1 -1
  23. simtools/applications/generate_corsika_histograms.py +1 -1
  24. simtools/applications/generate_default_metadata.py +8 -24
  25. simtools/applications/generate_simtel_event_data.py +11 -11
  26. simtools/applications/maintain_simulation_model_add_production_table.py +71 -0
  27. simtools/applications/maintain_simulation_model_compare_productions.py +98 -0
  28. simtools/applications/{verify_simulation_model_production_tables.py → maintain_simulation_model_verify_production_tables.py} +9 -1
  29. simtools/applications/merge_tables.py +2 -2
  30. simtools/applications/plot_array_layout.py +3 -3
  31. simtools/applications/plot_simtel_events.py +421 -0
  32. simtools/applications/plot_tabular_data.py +9 -2
  33. simtools/applications/plot_tabular_data_for_model_parameter.py +2 -1
  34. simtools/applications/print_version.py +8 -9
  35. simtools/applications/production_derive_corsika_limits.py +6 -7
  36. simtools/applications/production_derive_statistics.py +1 -1
  37. simtools/applications/production_generate_grid.py +2 -2
  38. simtools/applications/production_merge_corsika_limits.py +214 -0
  39. simtools/applications/run_application.py +47 -113
  40. simtools/applications/simulate_calibration_events.py +166 -0
  41. simtools/applications/simulate_flasher.py +141 -0
  42. simtools/applications/{simulate_light_emission.py → simulate_illuminator.py} +35 -99
  43. simtools/applications/simulate_prod.py +6 -24
  44. simtools/applications/simulate_prod_htcondor_generator.py +7 -0
  45. simtools/applications/submit_array_layouts.py +2 -1
  46. simtools/applications/submit_model_parameter_from_external.py +1 -1
  47. simtools/applications/validate_camera_efficiency.py +30 -12
  48. simtools/applications/validate_camera_fov.py +1 -1
  49. simtools/applications/validate_cumulative_psf.py +1 -1
  50. simtools/applications/validate_file_using_schema.py +9 -5
  51. simtools/applications/validate_optics.py +1 -1
  52. simtools/camera/camera_efficiency.py +61 -45
  53. simtools/camera/single_photon_electron_spectrum.py +1 -1
  54. simtools/configuration/commandline_parser.py +46 -11
  55. simtools/configuration/configurator.py +4 -4
  56. simtools/corsika/corsika_config.py +45 -25
  57. simtools/corsika/corsika_histograms.py +6 -5
  58. simtools/data_model/data_reader.py +2 -3
  59. simtools/data_model/metadata_collector.py +32 -36
  60. simtools/data_model/metadata_model.py +15 -12
  61. simtools/data_model/model_data_writer.py +13 -32
  62. simtools/data_model/schema.py +74 -24
  63. simtools/data_model/validate_data.py +42 -12
  64. simtools/db/db_handler.py +125 -62
  65. simtools/db/db_model_upload.py +14 -19
  66. simtools/dependencies.py +98 -30
  67. simtools/io/ascii_handler.py +279 -0
  68. simtools/{io_operations → io}/io_handler.py +25 -3
  69. simtools/job_execution/htcondor_script_generator.py +15 -4
  70. simtools/layout/array_layout.py +1 -1
  71. simtools/layout/array_layout_utils.py +51 -12
  72. simtools/model/array_model.py +41 -5
  73. simtools/model/flasher_model.py +106 -0
  74. simtools/model/model_parameter.py +4 -4
  75. simtools/model/model_repository.py +197 -2
  76. simtools/model/site_model.py +25 -0
  77. simtools/model/telescope_model.py +3 -1
  78. simtools/production_configuration/derive_corsika_limits.py +336 -427
  79. simtools/production_configuration/derive_production_statistics_handler.py +7 -6
  80. simtools/production_configuration/generate_production_grid.py +9 -11
  81. simtools/production_configuration/merge_corsika_limits.py +528 -0
  82. simtools/ray_tracing/incident_angles.py +706 -0
  83. simtools/ray_tracing/mirror_panel_psf.py +1 -0
  84. simtools/ray_tracing/psf_parameter_optimisation.py +792 -0
  85. simtools/ray_tracing/ray_tracing.py +6 -2
  86. simtools/reporting/docs_read_parameters.py +150 -62
  87. simtools/runners/corsika_runner.py +1 -1
  88. simtools/runners/corsika_simtel_runner.py +14 -5
  89. simtools/runners/runner_services.py +10 -5
  90. simtools/runners/simtools_runner.py +267 -0
  91. simtools/schemas/application_workflow.metaschema.yml +101 -68
  92. simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +1 -1
  93. simtools/schemas/input/single_pe_spectrum.schema.yml +1 -1
  94. simtools/schemas/metadata.metaschema.yml +577 -3
  95. simtools/schemas/model_parameter.metaschema.yml +6 -6
  96. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +4 -4
  97. simtools/schemas/model_parameters/adjust_gain.schema.yml +1 -1
  98. simtools/schemas/model_parameters/altitude.schema.yml +1 -1
  99. simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
  100. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +1 -1
  101. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +1 -1
  102. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
  103. simtools/schemas/model_parameters/array_layouts.schema.yml +1 -1
  104. simtools/schemas/model_parameters/array_triggers.schema.yml +1 -1
  105. simtools/schemas/model_parameters/array_window.schema.yml +1 -1
  106. simtools/schemas/model_parameters/asum_clipping.schema.yml +1 -1
  107. simtools/schemas/model_parameters/asum_offset.schema.yml +1 -1
  108. simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
  109. simtools/schemas/model_parameters/asum_threshold.schema.yml +1 -1
  110. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +1 -1
  111. simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +1 -1
  112. simtools/schemas/model_parameters/axes_offsets.schema.yml +1 -1
  113. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +1 -1
  114. simtools/schemas/model_parameters/camera_body_shape.schema.yml +1 -1
  115. simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
  116. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +1 -1
  117. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +1 -1
  118. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
  119. simtools/schemas/model_parameters/camera_depth.schema.yml +1 -1
  120. simtools/schemas/model_parameters/camera_filter.schema.yml +1 -1
  121. simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +1 -1
  122. simtools/schemas/model_parameters/camera_pixels.schema.yml +1 -1
  123. simtools/schemas/model_parameters/camera_transmission.schema.yml +1 -1
  124. simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
  125. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +1 -1
  126. simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +1 -1
  127. simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +1 -1
  128. simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +1 -1
  129. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +1 -1
  130. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +1 -1
  131. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +1 -1
  132. simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +1 -1
  133. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +1 -1
  134. simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +1 -1
  135. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +3 -3
  136. simtools/schemas/model_parameters/dark_events.schema.yml +1 -1
  137. simtools/schemas/model_parameters/default_trigger.schema.yml +1 -1
  138. simtools/schemas/model_parameters/design_model.schema.yml +1 -1
  139. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +1 -1
  140. simtools/schemas/model_parameters/disc_bins.schema.yml +1 -1
  141. simtools/schemas/model_parameters/disc_start.schema.yml +1 -1
  142. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +1 -1
  143. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +1 -1
  144. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +1 -1
  145. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +1 -1
  146. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +1 -1
  147. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +1 -1
  148. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +1 -1
  149. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +1 -1
  150. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +1 -1
  151. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +1 -1
  152. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +1 -1
  153. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -1
  154. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +1 -1
  155. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +1 -1
  156. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +1 -1
  157. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +1 -1
  158. simtools/schemas/model_parameters/dish_shape_length.schema.yml +1 -1
  159. simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -1
  160. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +1 -1
  161. simtools/schemas/model_parameters/dsum_offset.schema.yml +1 -1
  162. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +1 -1
  163. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +1 -1
  164. simtools/schemas/model_parameters/dsum_prescale.schema.yml +1 -1
  165. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +1 -1
  166. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +1 -1
  167. simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
  168. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +1 -1
  169. simtools/schemas/model_parameters/dsum_threshold.schema.yml +2 -2
  170. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +1 -1
  171. simtools/schemas/model_parameters/effective_focal_length.schema.yml +1 -1
  172. simtools/schemas/model_parameters/epsg_code.schema.yml +1 -1
  173. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +1 -1
  174. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +1 -1
  175. simtools/schemas/model_parameters/fadc_bins.schema.yml +1 -1
  176. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
  177. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
  178. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +1 -1
  179. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +1 -1
  180. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +1 -1
  181. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
  182. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
  183. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +1 -1
  184. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +1 -1
  185. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +1 -1
  186. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +1 -1
  187. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +1 -1
  188. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +1 -1
  189. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +1 -1
  190. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +1 -1
  191. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +1 -1
  192. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +1 -1
  193. simtools/schemas/model_parameters/fadc_long_event_threshold.schema.yml +35 -0
  194. simtools/schemas/model_parameters/fadc_long_sum_bins.schema.yml +41 -0
  195. simtools/schemas/model_parameters/fadc_long_sum_offset.schema.yml +38 -0
  196. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +1 -1
  197. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +1 -1
  198. simtools/schemas/model_parameters/fadc_mhz.schema.yml +1 -1
  199. simtools/schemas/model_parameters/fadc_noise.schema.yml +1 -1
  200. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +1 -1
  201. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +1 -1
  202. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +1 -1
  203. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +1 -1
  204. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +1 -1
  205. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +1 -1
  206. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +1 -1
  207. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +1 -1
  208. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  209. simtools/schemas/model_parameters/flatfielding.schema.yml +1 -1
  210. simtools/schemas/model_parameters/focal_length.schema.yml +1 -1
  211. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +1 -1
  212. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +1 -1
  213. simtools/schemas/model_parameters/focus_offset.schema.yml +1 -1
  214. simtools/schemas/model_parameters/gain_variation.schema.yml +1 -1
  215. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +1 -1
  216. simtools/schemas/model_parameters/geomag_rotation.schema.yml +1 -1
  217. simtools/schemas/model_parameters/geomag_vertical.schema.yml +1 -1
  218. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +1 -1
  219. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
  220. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
  221. simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
  222. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +1 -1
  223. simtools/schemas/model_parameters/laser_photons.schema.yml +1 -1
  224. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +1 -1
  225. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +1 -1
  226. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +1 -1
  227. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +1 -1
  228. simtools/schemas/model_parameters/laser_var_photons.schema.yml +1 -1
  229. simtools/schemas/model_parameters/laser_wavelength.schema.yml +1 -1
  230. simtools/schemas/model_parameters/led_events.schema.yml +1 -1
  231. simtools/schemas/model_parameters/led_photons.schema.yml +1 -1
  232. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +1 -1
  233. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +1 -1
  234. simtools/schemas/model_parameters/led_var_photons.schema.yml +1 -1
  235. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
  236. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +50 -1
  237. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
  238. simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
  239. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +1 -1
  240. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +1 -1
  241. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +1 -1
  242. simtools/schemas/model_parameters/mirror_class.schema.yml +1 -1
  243. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +1 -1
  244. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +1 -1
  245. simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
  246. simtools/schemas/model_parameters/mirror_offset.schema.yml +1 -1
  247. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +1 -1
  248. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +1 -1
  249. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +1 -1
  250. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +1 -1
  251. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +1 -1
  252. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +1 -1
  253. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +1 -1
  254. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +1 -1
  255. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +1 -1
  256. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +2 -2
  257. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +1 -1
  258. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +1 -1
  259. simtools/schemas/model_parameters/nsb_sky_map.schema.yml +1 -1
  260. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +23 -30
  261. simtools/schemas/model_parameters/num_gains.schema.yml +1 -1
  262. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +1 -1
  263. simtools/schemas/model_parameters/optics_properties.schema.yml +1 -1
  264. simtools/schemas/model_parameters/parabolic_dish.schema.yml +1 -1
  265. simtools/schemas/model_parameters/pedestal_events.schema.yml +1 -1
  266. simtools/schemas/model_parameters/photon_delay.schema.yml +1 -1
  267. simtools/schemas/model_parameters/photons_per_run.schema.yml +1 -1
  268. simtools/schemas/model_parameters/pixel_cells.schema.yml +1 -1
  269. simtools/schemas/model_parameters/pixels_parallel.schema.yml +1 -1
  270. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +1 -1
  271. simtools/schemas/model_parameters/pm_average_gain.schema.yml +1 -1
  272. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +1 -1
  273. simtools/schemas/model_parameters/pm_gain_index.schema.yml +1 -1
  274. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +1 -1
  275. simtools/schemas/model_parameters/pm_transit_time.schema.yml +1 -1
  276. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +1 -1
  277. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +1 -1
  278. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +1 -1
  279. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +1 -1
  280. simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +11 -1
  281. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +1 -1
  282. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +1 -1
  283. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
  284. simtools/schemas/model_parameters/qe_variation.schema.yml +1 -1
  285. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +1 -1
  286. simtools/schemas/model_parameters/random_focal_length.schema.yml +1 -1
  287. simtools/schemas/model_parameters/random_generator.schema.yml +1 -1
  288. simtools/schemas/model_parameters/random_mono_probability.schema.yml +1 -1
  289. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +1 -1
  290. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +1 -1
  291. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +1 -1
  292. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +1 -1
  293. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +1 -1
  294. simtools/schemas/model_parameters/sampled_output.schema.yml +1 -1
  295. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +1 -1
  296. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +1 -1
  297. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
  298. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
  299. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +1 -1
  300. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +1 -1
  301. simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +11 -1
  302. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +1 -1
  303. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +1 -1
  304. simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +11 -1
  305. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
  306. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +1 -1
  307. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +1 -1
  308. simtools/schemas/model_parameters/stars.schema.yml +2 -2
  309. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
  310. simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
  311. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +1 -1
  312. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +1 -1
  313. simtools/schemas/model_parameters/telescope_random_error.schema.yml +1 -1
  314. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +1 -1
  315. simtools/schemas/model_parameters/telescope_transmission.schema.yml +1 -1
  316. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +1 -1
  317. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +1 -1
  318. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +1 -1
  319. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +1 -1
  320. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +1 -1
  321. simtools/schemas/model_parameters/transit_time_error.schema.yml +1 -1
  322. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +1 -1
  323. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +1 -1
  324. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +1 -1
  325. simtools/schemas/model_parameters/trigger_pixels.schema.yml +1 -1
  326. simtools/schemas/plot_configuration.metaschema.yml +5 -2
  327. simtools/schemas/production_configuration_metrics.schema.yml +12 -2
  328. simtools/schemas/production_tables.schema.yml +7 -2
  329. simtools/simtel/simtel_config_reader.py +2 -2
  330. simtools/simtel/simtel_config_writer.py +33 -23
  331. simtools/simtel/simtel_io_event_histograms.py +483 -0
  332. simtools/simtel/simtel_io_event_reader.py +65 -43
  333. simtools/simtel/simtel_io_event_writer.py +40 -20
  334. simtools/simtel/simtel_io_metadata.py +1 -1
  335. simtools/simtel/simtel_table_reader.py +95 -13
  336. simtools/simtel/simulator_array.py +138 -10
  337. simtools/simtel/simulator_camera_efficiency.py +32 -23
  338. simtools/simtel/simulator_light_emission.py +437 -271
  339. simtools/simtel/simulator_ray_tracing.py +1 -1
  340. simtools/simulator.py +105 -147
  341. simtools/telescope_trigger_rates.py +119 -0
  342. simtools/testing/configuration.py +24 -26
  343. simtools/testing/helpers.py +2 -2
  344. simtools/testing/log_inspector.py +52 -0
  345. simtools/testing/validate_output.py +87 -37
  346. simtools/utils/general.py +125 -255
  347. simtools/utils/geometry.py +56 -0
  348. simtools/utils/names.py +1 -1
  349. simtools/visualization/legend_handlers.py +180 -264
  350. simtools/visualization/plot_array_layout.py +20 -8
  351. simtools/visualization/plot_incident_angles.py +431 -0
  352. simtools/visualization/plot_pixels.py +1 -1
  353. simtools/visualization/plot_simtel_event_histograms.py +376 -0
  354. simtools/visualization/plot_simtel_events.py +816 -0
  355. simtools/visualization/plot_tables.py +133 -37
  356. simtools/visualization/visualize.py +1 -100
  357. gammasimtools-0.18.0.dist-info/RECORD +0 -376
  358. simtools/applications/calculate_trigger_rate.py +0 -187
  359. simtools/applications/generate_sim_telarray_histograms.py +0 -196
  360. simtools/production_configuration/derive_corsika_limits_grid.py +0 -232
  361. simtools/simtel/simtel_io_histogram.py +0 -621
  362. simtools/simtel/simtel_io_histograms.py +0 -552
  363. {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/WHEEL +0 -0
  364. {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/top_level.txt +0 -0
  365. /simtools/{io_operations → io}/hdf5_handler.py +0 -0
  366. /simtools/{io_operations → io}/legacy_data_handler.py +0 -0
  367. /simtools/{io_operations/io_table_handler.py → io/table_handler.py} +0 -0
@@ -0,0 +1,483 @@
1
+ """Histograms for shower and triggered events."""
2
+
3
+ import copy
4
+ import logging
5
+
6
+ import astropy.units as u
7
+ import numpy as np
8
+
9
+ from simtools.simtel.simtel_io_event_reader import SimtelIOEventDataReader
10
+
11
+
12
+ class SimtelIOEventHistograms:
13
+ """
14
+ Generate and fill histograms for shower and triggered events.
15
+
16
+ Event data is read from the reduced MC event data file.
17
+ Calculate cumulative and relative (efficiency) distributions.
18
+
19
+ Parameters
20
+ ----------
21
+ event_data_file : str
22
+ Path to the event-data file.
23
+ array_name : str, optional
24
+ Name of the telescope array configuration (default is None).
25
+ telescope_list : list, optional
26
+ List of telescope IDs to filter the events (default is None).
27
+ """
28
+
29
+ def __init__(self, event_data_file, array_name=None, telescope_list=None):
30
+ """Initialize."""
31
+ self._logger = logging.getLogger(__name__)
32
+ self.event_data_file = event_data_file
33
+ self.array_name = array_name
34
+
35
+ self.histograms = {}
36
+ self.file_info = {}
37
+
38
+ self.reader = SimtelIOEventDataReader(event_data_file, telescope_list=telescope_list)
39
+
40
+ def fill(self):
41
+ """
42
+ Fill histograms with event data.
43
+
44
+ Involves looping over all event data, and therefore is the slowest part of the
45
+ histogram module. Adds the histograms to the histogram dictionary.
46
+
47
+ Assume that all event data files are generated with similar configurations
48
+ (self.file_info contains the file info of the last file).
49
+ """
50
+ for data_set in self.reader.data_sets:
51
+ self._logger.info(f"Reading event data from {self.event_data_file} for {data_set}")
52
+ _file_info_table, shower_data, event_data, triggered_data = self.reader.read_event_data(
53
+ self.event_data_file, table_name_map=data_set
54
+ )
55
+ _file_info_table = self.reader.get_reduced_simulation_file_info(_file_info_table)
56
+ self.file_info = {
57
+ "energy_min": _file_info_table["energy_min"].to("TeV"),
58
+ "core_scatter_max": _file_info_table["core_scatter_max"].to("m"),
59
+ "viewcone_max": _file_info_table["viewcone_max"].to("deg"),
60
+ "solid_angle": _file_info_table["solid_angle"].to("sr"),
61
+ "scatter_area": _file_info_table["scatter_area"].to("cm2"),
62
+ }
63
+
64
+ self.histograms = self._define_histograms(event_data, triggered_data, shower_data)
65
+
66
+ for name, data in self.histograms.items():
67
+ self._logger.debug(f"Filling histogram {name}")
68
+ self._fill_histogram_and_bin_edges(data)
69
+
70
+ self.print_summary()
71
+
72
+ self.calculate_efficiency_data()
73
+ self.calculate_cumulative_data()
74
+
75
+ def _define_histograms(self, event_data, triggered_data, shower_data):
76
+ """
77
+ Define histograms including event data, binning, naming, and labels.
78
+
79
+ All histograms are defined for simulated and triggered events (note
80
+ the subtlety of triggered events being read from event_data and triggered_data).
81
+
82
+ Parameters
83
+ ----------
84
+ event_data : EventData
85
+ The event data to use for filling the histograms.
86
+ triggered_data : TriggeredData
87
+ The triggered data to use for filling the histograms.
88
+ shower_data : ShowerData
89
+ The shower data to use for filling the histograms.
90
+
91
+ Returns
92
+ -------
93
+ dict
94
+ Dictionary with histogram definitions.
95
+ """
96
+ xy_bins = np.linspace(
97
+ -1.0 * self.core_distance_bins.max(),
98
+ self.core_distance_bins.max(),
99
+ len(self.core_distance_bins),
100
+ )
101
+ hists = {}
102
+
103
+ energy_axis_title = "Energy (TeV)"
104
+ event_count_axis_title = "Event Count"
105
+
106
+ definitions = {
107
+ "energy": {
108
+ "event_data_column": "simulated_energy",
109
+ "event_data": event_data,
110
+ "bin_edges": self.energy_bins,
111
+ "axis_titles": [energy_axis_title, event_count_axis_title],
112
+ "plot_scales": {"x": "log", "y": "log"},
113
+ },
114
+ "core_distance": {
115
+ "event_data_column": "core_distance_shower",
116
+ "event_data": event_data,
117
+ "bin_edges": self.core_distance_bins,
118
+ "axis_titles": ["Core Distance (m)", event_count_axis_title],
119
+ },
120
+ "angular_distance": {
121
+ "event_data_column": "angular_distance",
122
+ "event_data": triggered_data,
123
+ "bin_edges": self.view_cone_bins,
124
+ "axis_titles": ["Angular Distance (deg)", event_count_axis_title],
125
+ },
126
+ "x_core_shower_vs_y_core_shower": {
127
+ "event_data_column": ("x_core_shower", "y_core_shower"),
128
+ "event_data": (event_data, event_data),
129
+ "bin_edges": (xy_bins, xy_bins),
130
+ "is_1d": False,
131
+ "axis_titles": ["Core X (m)", "Core Y (m)", event_count_axis_title],
132
+ },
133
+ "core_vs_energy": {
134
+ "event_data_column": ("core_distance_shower", "simulated_energy"),
135
+ "event_data": (event_data, event_data),
136
+ "bin_edges": (self.core_distance_bins, self.energy_bins),
137
+ "is_1d": False,
138
+ "axis_titles": ["Core Distance (m)", energy_axis_title, event_count_axis_title],
139
+ "plot_scales": {"y": "log"},
140
+ },
141
+ "angular_distance_vs_energy": {
142
+ "event_data_column": ("angular_distance", "simulated_energy"),
143
+ "event_data": (triggered_data, event_data),
144
+ "bin_edges": (self.view_cone_bins, self.energy_bins),
145
+ "is_1d": False,
146
+ "axis_titles": [
147
+ "Angular Distance (deg)",
148
+ energy_axis_title,
149
+ event_count_axis_title,
150
+ ],
151
+ "plot_scales": {"y": "log"},
152
+ },
153
+ }
154
+
155
+ hists = {
156
+ name: self.get_histogram_definition(**cfg) | {"suffix": "", "title": "Triggered Events"}
157
+ for name, cfg in definitions.items()
158
+ }
159
+
160
+ hists_mc = {}
161
+ for key, hist in hists.items():
162
+ key_mc = f"{key}_mc"
163
+ hists_mc[key_mc] = copy.copy(hist)
164
+ hists_mc[key_mc]["suffix"] = "_mc"
165
+ hists_mc[key_mc]["title"] = "Simulated Events"
166
+ hists_mc[key_mc]["event_data"] = (
167
+ shower_data if hist["1d"] else (shower_data, shower_data)
168
+ )
169
+
170
+ hists.update(hists_mc)
171
+ return hists
172
+
173
+ def get_histogram_definition(
174
+ self,
175
+ event_data_column=None,
176
+ event_data=None,
177
+ histogram=None,
178
+ bin_edges=None,
179
+ title=None,
180
+ axis_titles=None,
181
+ suffix=None,
182
+ is_1d=True,
183
+ plot_scales=None,
184
+ ):
185
+ """Return a single histogram definition."""
186
+ return {
187
+ "histogram": histogram,
188
+ "event_data_column": event_data_column,
189
+ "event_data": event_data,
190
+ "1d": is_1d,
191
+ "bin_edges": bin_edges,
192
+ "title": title,
193
+ "axis_titles": axis_titles,
194
+ "suffix": suffix,
195
+ "plot_scales": plot_scales,
196
+ }
197
+
198
+ def _fill_histogram_and_bin_edges(self, data):
199
+ """
200
+ Fill histogram and bin edges into the histogram dictionary.
201
+
202
+ Adds to existing histogram if present, otherwise initializes it.
203
+ """
204
+ if data["1d"]:
205
+ hist, _ = np.histogram(
206
+ getattr(data["event_data"], data["event_data_column"]),
207
+ bins=data["bin_edges"],
208
+ )
209
+ else:
210
+ hist, _, _ = np.histogram2d(
211
+ getattr(data["event_data"][0], data["event_data_column"][0]),
212
+ getattr(data["event_data"][1], data["event_data_column"][1]),
213
+ bins=[data["bin_edges"][0], data["bin_edges"][1]],
214
+ )
215
+
216
+ data["histogram"] = hist if data["histogram"] is None else data["histogram"] + hist
217
+
218
+ def calculate_efficiency_data(self):
219
+ """
220
+ Calculate efficiency histograms (triggered divided by simulated).
221
+
222
+ Assumes that for each histogram with simulated events, there is a
223
+ corresponding histogram with triggered events.
224
+
225
+ Returns
226
+ -------
227
+ dict
228
+ Dictionary containing the efficiency histograms.
229
+ """
230
+
231
+ def calculate_efficiency(trig_hist, mc_hist):
232
+ with np.errstate(divide="ignore", invalid="ignore"):
233
+ return np.divide(
234
+ trig_hist,
235
+ mc_hist,
236
+ out=np.zeros_like(trig_hist, dtype=float),
237
+ where=mc_hist > 0,
238
+ )
239
+
240
+ eff_histograms = {}
241
+ for name, mc_hist in self.histograms.items():
242
+ if not name.endswith("_mc"):
243
+ continue
244
+
245
+ base_name = name[:-3]
246
+ trig_hist = self.histograms.get(base_name)
247
+ if trig_hist is None:
248
+ continue
249
+
250
+ if mc_hist["histogram"].shape != trig_hist["histogram"].shape:
251
+ self._logger.warning(
252
+ f"Shape mismatch for {base_name} and {name}, skipping efficiency calculation."
253
+ )
254
+ continue
255
+
256
+ eff = copy.copy(mc_hist)
257
+ eff.update(
258
+ {
259
+ "histogram": calculate_efficiency(trig_hist["histogram"], mc_hist["histogram"]),
260
+ "suffix": "_eff",
261
+ "title": "Efficiency",
262
+ }
263
+ )
264
+ eff["axis_titles"] = copy.copy(mc_hist["axis_titles"])
265
+ eff["axis_titles"][-1] = "Efficiency"
266
+ eff_histograms[f"{base_name}_eff"] = eff
267
+
268
+ self.histograms.update(eff_histograms)
269
+ return eff_histograms
270
+
271
+ @property
272
+ def energy_bins(self):
273
+ """Return bins for the energy histogram."""
274
+ if "energy_bin_edges" in self.histograms:
275
+ return self.histograms["energy_bin_edges"]
276
+ return np.logspace(
277
+ np.log10(self.file_info.get("energy_min", 1.0e-3 * u.TeV).to("TeV").value),
278
+ np.log10(self.file_info.get("energy_max", 1.0e3 * u.TeV).to("TeV").value),
279
+ 100,
280
+ )
281
+
282
+ @property
283
+ def core_distance_bins(self):
284
+ """Return bins for the core distance histogram."""
285
+ if "core_distance_bin_edges" in self.histograms:
286
+ return self.histograms["core_distance_bin_edges"]
287
+ return np.linspace(
288
+ self.file_info.get("core_scatter_min", 0.0 * u.m).to("m").value,
289
+ self.file_info.get("core_scatter_max", 1.0e5 * u.m).to("m").value,
290
+ 100,
291
+ )
292
+
293
+ @property
294
+ def view_cone_bins(self):
295
+ """Return bins for the viewcone histogram."""
296
+ if "viewcone_bin_edges" in self.histograms:
297
+ return self.histograms["viewcone_bin_edges"]
298
+ return np.linspace(
299
+ self.file_info.get("viewcone_min", 0.0 * u.deg).to("deg").value,
300
+ self.file_info.get("viewcone_max", 20.0 * u.deg).to("deg").value,
301
+ 100,
302
+ )
303
+
304
+ def calculate_cumulative_data(self):
305
+ """
306
+ Calculate cumulative distributions for triggered histograms.
307
+
308
+ Returns
309
+ -------
310
+ dict
311
+ Dictionary containing the cumulative histograms.
312
+ """
313
+ cumulative_data = {}
314
+ suffix = "_cumulative"
315
+
316
+ def add_cumulative(name, hist, **kwargs):
317
+ new = copy.copy(hist)
318
+ new["histogram"] = self._calculate_cumulative_histogram(hist["histogram"], **kwargs)
319
+ new["axis_titles"] = copy.copy(hist["axis_titles"])
320
+ new.update(
321
+ {
322
+ "suffix": suffix,
323
+ "title": "Cumulative triggered events",
324
+ }
325
+ )
326
+ new["axis_titles"][-1] = "Fraction of Events"
327
+ cumulative_data[f"{name}{suffix}"] = new
328
+
329
+ # 2D histograms vs energy
330
+ for name, hist in self.histograms.items():
331
+ if name.endswith("_vs_energy") and not name.endswith("_mc"):
332
+ add_cumulative(name, hist, axis=0, normalize=True)
333
+
334
+ # 1D histograms
335
+ for name in ["energy", "core_distance", "angular_distance"]:
336
+ if (hist := self.histograms.get(name)) is not None:
337
+ add_cumulative(name, hist, reverse=name == "energy")
338
+
339
+ self.histograms.update(cumulative_data)
340
+ return cumulative_data
341
+
342
+ def _calculate_cumulative_histogram(self, hist, reverse=False, axis=None, normalize=False):
343
+ """
344
+ Calculate cumulative distribution of a histogram.
345
+
346
+ Works with both 1D and 2D histograms.
347
+
348
+ Parameters
349
+ ----------
350
+ hist : np.ndarray
351
+ Histogram (1D or 2D)
352
+ reverse : bool, optional
353
+ If True, sum from high to low values
354
+ axis : int, optional
355
+ For 2D histograms, axis along which to compute cumulative sum
356
+ None means default behavior: for 1D just cumsum, for 2D along rows
357
+ normalize : bool, optional
358
+ If True, normalize by the total sum for each slice along the specified axis
359
+ For 1D histograms, normalizes by the total sum
360
+
361
+ Returns
362
+ -------
363
+ np.ndarray
364
+ Histogram with cumulative counts, optionally normalized
365
+ """
366
+ if hist is None:
367
+ return None
368
+
369
+ if hist.ndim == 1:
370
+ result = self._calculate_cumulative_1d(hist, reverse)
371
+ if normalize and np.sum(hist) > 0:
372
+ result = result / np.sum(hist)
373
+ return result
374
+
375
+ axis = axis if axis is not None else 1
376
+ result = self._apply_cumsum_along_axis(hist.copy(), axis, reverse)
377
+
378
+ if normalize:
379
+ # Ensure floating dtype to allow in-place normalization without casting errors
380
+ if not np.issubdtype(result.dtype, np.floating):
381
+ result = result.astype(float)
382
+ self._normalize_along_axis(result, hist, axis)
383
+
384
+ return result
385
+
386
+ def _normalize_along_axis(self, result, hist, axis):
387
+ """
388
+ Normalize cumulative histogram along the specified axis.
389
+
390
+ Parameters
391
+ ----------
392
+ result : np.ndarray
393
+ Cumulative histogram to normalize (modified in-place)
394
+ hist : np.ndarray
395
+ Original histogram (for calculating totals)
396
+ axis : int
397
+ Axis along which normalization should be applied
398
+ """
399
+ normalized = np.zeros_like(result, dtype=float)
400
+
401
+ if axis == 0:
402
+ for i in range(result.shape[1]):
403
+ col_total = np.sum(hist[:, i])
404
+ if col_total > 0:
405
+ normalized[:, i] = result[:, i] / col_total
406
+ else: # axis == 1
407
+ for i in range(result.shape[0]):
408
+ row_total = np.sum(hist[i, :])
409
+ if row_total > 0:
410
+ normalized[i, :] = result[i, :] / row_total
411
+
412
+ np.copyto(result, normalized)
413
+
414
+ def _calculate_cumulative_1d(self, hist, reverse):
415
+ """Calculate cumulative distribution for 1D histogram."""
416
+ if reverse:
417
+ return np.cumsum(hist[::-1])[::-1]
418
+ return np.cumsum(hist)
419
+
420
+ def _calculate_cumulative_2d(self, hist, reverse, axis=None):
421
+ """Calculate cumulative distribution for 2D histogram."""
422
+ axis = axis if axis is not None else 1
423
+ return self._apply_cumsum_along_axis(hist, axis, reverse)
424
+
425
+ def _apply_cumsum_along_axis(self, hist, axis, reverse):
426
+ """Apply cumulative sum along the specified axis of a 2D histogram."""
427
+
428
+ def cumsum_func(arr):
429
+ return np.cumsum(arr[::-1])[::-1] if reverse else np.cumsum(arr)
430
+
431
+ return np.apply_along_axis(cumsum_func, axis, hist)
432
+
433
+ @staticmethod
434
+ def rebin_2d_histogram(hist, x_bins, y_bins, rebin_factor=2):
435
+ """
436
+ Rebin a 2D histogram by merging neighboring bins along the energy dimension (y-axis) only.
437
+
438
+ Parameters
439
+ ----------
440
+ hist : np.ndarray
441
+ Original 2D histogram data
442
+ x_bins : np.ndarray
443
+ Original x-axis bin edges (preserved)
444
+ y_bins : np.ndarray
445
+ Original y-axis (energy) bin edges
446
+ rebin_factor : int, optional
447
+ Factor by which to reduce the number of bins in the energy dimension
448
+ Default is 2 (merge every 2 bins)
449
+
450
+ Returns
451
+ -------
452
+ tuple
453
+ (re-binned_hist, x_bins, re-binned_y_bins)
454
+ """
455
+ if rebin_factor <= 1:
456
+ return hist, x_bins, y_bins
457
+
458
+ x_size = hist.shape[0]
459
+ new_y_size = hist.shape[1] // rebin_factor
460
+
461
+ new_hist = np.zeros((x_size, new_y_size), dtype=float)
462
+
463
+ for i in range(x_size):
464
+ for j in range(new_y_size):
465
+ y_start = j * rebin_factor
466
+ y_end = (j + 1) * rebin_factor
467
+ new_hist[i, j] = np.sum(hist[i, y_start:y_end])
468
+
469
+ new_y_bins = y_bins[::rebin_factor]
470
+
471
+ return new_hist, x_bins, new_y_bins
472
+
473
+ def print_summary(self):
474
+ """
475
+ Print a summary of the histogram statistics.
476
+
477
+ Total number of events is retrieved from the 'energy' histograms.
478
+ """
479
+ total_simulated = np.sum(self.histograms.get("energy_mc", {}).get("histogram", []))
480
+ total_triggered = np.sum(self.histograms.get("energy", {}).get("histogram", []))
481
+
482
+ self._logger.info(f"Total simulated events: {total_simulated}")
483
+ self._logger.info(f"Total triggered events: {total_triggered}")
@@ -5,11 +5,11 @@ from dataclasses import dataclass, field
5
5
 
6
6
  import astropy.units as u
7
7
  import numpy as np
8
- from astropy.coordinates import AltAz, angular_separation
9
- from ctapipe.coordinates import GroundFrame, TiltedGroundFrame
8
+ from astropy.coordinates import angular_separation
10
9
 
11
10
  from simtools.corsika.primary_particle import PrimaryParticle
12
- from simtools.io_operations import io_table_handler
11
+ from simtools.io import table_handler
12
+ from simtools.utils.geometry import solid_angle, transform_ground_to_shower_coordinates
13
13
 
14
14
 
15
15
  @dataclass
@@ -28,6 +28,7 @@ class ShowerEventData:
28
28
  x_core_shower: list[np.float64] = field(default_factory=list)
29
29
  y_core_shower: list[np.float64] = field(default_factory=list)
30
30
  core_distance_shower: list[np.float64] = field(default_factory=list)
31
+ angular_distance: list[float] = field(default_factory=list)
31
32
 
32
33
 
33
34
  @dataclass
@@ -52,6 +53,7 @@ class SimtelIOEventDataReader:
52
53
  self.telescope_list = telescope_list
53
54
 
54
55
  self.data_sets = self.read_table_list(event_data_file)
56
+ self.reduced_file_info = None
55
57
 
56
58
  def read_table_list(self, event_data_file):
57
59
  """
@@ -71,14 +73,21 @@ class SimtelIOEventDataReader:
71
73
  list
72
74
  List of dictionaries containing the data from the tables.
73
75
  """
74
- dataset_dict = io_table_handler.read_table_list(
76
+ dataset_dict = table_handler.read_table_list(
75
77
  event_data_file,
76
78
  ["SHOWERS", "TRIGGERS", "FILE_INFO"],
77
79
  include_indexed_tables=True,
78
80
  )
79
81
 
80
82
  data_sets = []
81
- for i in range(len(dataset_dict["SHOWERS"])):
83
+ try:
84
+ sorted_indices = sorted(
85
+ range(len(dataset_dict["SHOWERS"])),
86
+ key=lambda i: int(dataset_dict["SHOWERS"][i].split("_")[-1]),
87
+ )
88
+ except (ValueError, AttributeError):
89
+ sorted_indices = [0] # Handle the case where the key is only "SHOWERS"
90
+ for i in sorted_indices:
82
91
  data_sets.append(
83
92
  {
84
93
  "SHOWERS": dataset_dict["SHOWERS"][i],
@@ -110,16 +119,27 @@ class SimtelIOEventDataReader:
110
119
  if table[col].unit:
111
120
  setattr(shower_data, f"{col}_unit", table[col].unit)
112
121
 
113
- shower_data.x_core_shower, shower_data.y_core_shower = (
114
- self._transform_to_shower_coordinates(
122
+ shower_data.x_core_shower, shower_data.y_core_shower, _ = (
123
+ transform_ground_to_shower_coordinates(
115
124
  shower_data.x_core,
116
125
  shower_data.y_core,
126
+ 0.0,
117
127
  shower_data.shower_azimuth,
118
128
  shower_data.shower_altitude,
119
129
  )
120
130
  )
121
- shower_data.core_distance_shower = np.sqrt(
122
- shower_data.x_core_shower**2 + shower_data.y_core_shower**2
131
+ shower_data.core_distance_shower = np.hypot(
132
+ shower_data.x_core_shower, shower_data.y_core_shower
133
+ )
134
+ shower_data.angular_distance = (
135
+ angular_separation(
136
+ shower_data.shower_azimuth * u.deg,
137
+ shower_data.shower_altitude * u.deg,
138
+ self.reduced_file_info["azimuth"],
139
+ (90.0 * u.deg - self.reduced_file_info["zenith"]),
140
+ )
141
+ .to(u.deg)
142
+ .value
123
143
  )
124
144
 
125
145
  return shower_data
@@ -191,7 +211,7 @@ class SimtelIOEventDataReader:
191
211
  & (shower_data.event_id == tr_event_id)
192
212
  & (shower_data.file_id == tr_file_id)
193
213
  )
194
- matched_idx = np.where(mask)[0]
214
+ matched_idx = np.nonzero(mask)[0]
195
215
  if len(matched_idx) == 1:
196
216
  matched_indices.append(matched_idx[0])
197
217
  else:
@@ -233,10 +253,13 @@ class SimtelIOEventDataReader:
233
253
  def get_name(key):
234
254
  return table_name_map.get(key, key)
235
255
 
236
- tables = io_table_handler.read_tables(
256
+ tables = table_handler.read_tables(
237
257
  event_data_file,
238
258
  table_names=[get_name(k) for k in ("SHOWERS", "TRIGGERS", "FILE_INFO")],
239
259
  )
260
+ self.reduced_file_info = self.get_reduced_simulation_file_info(
261
+ tables[get_name("FILE_INFO")]
262
+ )
240
263
 
241
264
  shower_data = self._table_to_shower_data(tables[get_name("SHOWERS")])
242
265
  triggered_data = self._table_to_triggered_data(tables[get_name("TRIGGERS")])
@@ -249,10 +272,10 @@ class SimtelIOEventDataReader:
249
272
 
250
273
  triggered_data.angular_distance = (
251
274
  angular_separation(
252
- triggered_shower.shower_azimuth * u.rad,
253
- triggered_shower.shower_altitude * u.rad,
254
- triggered_data.array_azimuth * u.rad,
255
- triggered_data.array_altitude * u.rad,
275
+ triggered_shower.shower_azimuth * u.deg,
276
+ triggered_shower.shower_altitude * u.deg,
277
+ triggered_data.array_azimuth * u.deg,
278
+ triggered_data.array_altitude * u.deg,
256
279
  )
257
280
  .to(u.deg)
258
281
  .value
@@ -298,34 +321,6 @@ class SimtelIOEventDataReader:
298
321
 
299
322
  return filtered_triggered_data, filtered_triggered_shower_data
300
323
 
301
- def _transform_to_shower_coordinates(self, x_core, y_core, shower_azimuth, shower_altitude):
302
- """
303
- Transform core positions from ground coordinates to shower coordinates.
304
-
305
- Parameters
306
- ----------
307
- x_core : np.ndarray
308
- Core x positions in ground coordinates.
309
- y_core : np.ndarray
310
- Core y positions in ground coordinates.
311
- shower_azimuth : np.ndarray
312
- Shower azimuth angles.
313
- shower_altitude : np.ndarray
314
- Shower altitude angles.
315
-
316
- Returns
317
- -------
318
- tuple
319
- Core positions in shower coordinates (x, y).
320
- """
321
- ground = GroundFrame(x=x_core * u.m, y=y_core * u.m, z=np.zeros_like(x_core) * u.m)
322
- shower_frame = ground.transform_to(
323
- TiltedGroundFrame(
324
- pointing_direction=AltAz(az=shower_azimuth * u.rad, alt=shower_altitude * u.rad)
325
- )
326
- )
327
- return shower_frame.x.value, shower_frame.y.value
328
-
329
324
  def get_reduced_simulation_file_info(self, simulation_file_info):
330
325
  """
331
326
  Return reduced simulation file info assuming single-valued parameters.
@@ -382,4 +377,31 @@ class SimtelIOEventDataReader:
382
377
  value = value * simulation_file_info[key].unit
383
378
  reduced_info[key] = value
384
379
 
380
+ reduced_info["solid_angle"] = solid_angle(
381
+ angle_min=reduced_info.get("viewcone_min", 0.0 * u.rad),
382
+ angle_max=reduced_info.get("viewcone_max", 0.0 * u.rad),
383
+ )
384
+ reduced_info["scatter_area"] = self.scatter_area(
385
+ core_scatter_min=reduced_info.get("core_scatter_min", 0.0 * u.m),
386
+ core_scatter_max=reduced_info.get("core_scatter_max", 0.0 * u.m),
387
+ )
388
+
385
389
  return reduced_info
390
+
391
+ def scatter_area(self, core_scatter_min, core_scatter_max):
392
+ """
393
+ Calculate the scatter area of the core.
394
+
395
+ Parameters
396
+ ----------
397
+ core_scatter_min : astropy.units.Quantity
398
+ Minimum core scatter radius.
399
+ core_scatter_max : astropy.units.Quantity
400
+ Maximum core scatter radius.
401
+
402
+ Returns
403
+ -------
404
+ astropy.units.Quantity
405
+ Scatter area.
406
+ """
407
+ return np.pi * (core_scatter_max**2 - core_scatter_min**2)