gammasimtools 0.18.0__py3-none-any.whl → 0.19.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 (358) hide show
  1. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/METADATA +26 -69
  2. gammasimtools-0.19.0.dist-info/RECORD +393 -0
  3. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/entry_points.txt +9 -2
  4. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/licenses/LICENSE +1 -1
  5. simtools/_version.py +16 -3
  6. simtools/applications/calculate_trigger_rate.py +1 -1
  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_value_from_json_to_db.py +2 -1
  10. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +8 -13
  11. simtools/applications/db_generate_compound_indexes.py +61 -0
  12. simtools/applications/db_get_file_from_db.py +1 -1
  13. simtools/applications/db_get_parameter_from_db.py +4 -4
  14. simtools/applications/db_inspect_databases.py +20 -10
  15. simtools/applications/derive_mirror_rnda.py +17 -11
  16. simtools/applications/derive_psf_parameters.py +59 -309
  17. simtools/applications/docs_produce_array_element_report.py +1 -1
  18. simtools/applications/docs_produce_calibration_reports.py +1 -1
  19. simtools/applications/docs_produce_model_parameter_reports.py +1 -1
  20. simtools/applications/docs_produce_simulation_configuration_report.py +1 -1
  21. simtools/applications/generate_corsika_histograms.py +1 -1
  22. simtools/applications/generate_default_metadata.py +8 -24
  23. simtools/applications/generate_sim_telarray_histograms.py +1 -1
  24. simtools/applications/generate_simtel_event_data.py +11 -11
  25. simtools/applications/maintain_simulation_model_add_production_table.py +71 -0
  26. simtools/applications/maintain_simulation_model_compare_productions.py +98 -0
  27. simtools/applications/{verify_simulation_model_production_tables.py → maintain_simulation_model_verify_production_tables.py} +9 -1
  28. simtools/applications/merge_tables.py +2 -2
  29. simtools/applications/plot_array_layout.py +3 -3
  30. simtools/applications/plot_simtel_events.py +379 -0
  31. simtools/applications/plot_tabular_data.py +9 -2
  32. simtools/applications/plot_tabular_data_for_model_parameter.py +2 -1
  33. simtools/applications/print_version.py +8 -9
  34. simtools/applications/production_derive_corsika_limits.py +6 -7
  35. simtools/applications/production_derive_statistics.py +1 -1
  36. simtools/applications/production_generate_grid.py +2 -2
  37. simtools/applications/production_merge_corsika_limits.py +214 -0
  38. simtools/applications/run_application.py +47 -113
  39. simtools/applications/simulate_calibration_events.py +166 -0
  40. simtools/applications/simulate_flasher.py +141 -0
  41. simtools/applications/{simulate_light_emission.py → simulate_illuminator.py} +35 -99
  42. simtools/applications/simulate_prod.py +6 -24
  43. simtools/applications/simulate_prod_htcondor_generator.py +7 -0
  44. simtools/applications/submit_array_layouts.py +2 -1
  45. simtools/applications/submit_model_parameter_from_external.py +1 -1
  46. simtools/applications/validate_camera_efficiency.py +30 -12
  47. simtools/applications/validate_camera_fov.py +1 -1
  48. simtools/applications/validate_cumulative_psf.py +1 -1
  49. simtools/applications/validate_file_using_schema.py +2 -1
  50. simtools/applications/validate_optics.py +1 -1
  51. simtools/camera/camera_efficiency.py +61 -45
  52. simtools/camera/single_photon_electron_spectrum.py +1 -1
  53. simtools/configuration/commandline_parser.py +29 -0
  54. simtools/configuration/configurator.py +4 -4
  55. simtools/corsika/corsika_config.py +45 -25
  56. simtools/corsika/corsika_histograms.py +6 -5
  57. simtools/data_model/data_reader.py +2 -3
  58. simtools/data_model/metadata_collector.py +32 -36
  59. simtools/data_model/metadata_model.py +15 -12
  60. simtools/data_model/model_data_writer.py +13 -32
  61. simtools/data_model/schema.py +74 -24
  62. simtools/data_model/validate_data.py +34 -9
  63. simtools/db/db_handler.py +43 -37
  64. simtools/db/db_model_upload.py +3 -3
  65. simtools/dependencies.py +88 -25
  66. simtools/io/ascii_handler.py +279 -0
  67. simtools/{io_operations → io}/io_handler.py +25 -3
  68. simtools/job_execution/htcondor_script_generator.py +15 -4
  69. simtools/layout/array_layout.py +1 -1
  70. simtools/layout/array_layout_utils.py +14 -7
  71. simtools/model/array_model.py +23 -4
  72. simtools/model/flasher_model.py +106 -0
  73. simtools/model/model_parameter.py +4 -4
  74. simtools/model/model_repository.py +197 -2
  75. simtools/model/telescope_model.py +3 -1
  76. simtools/production_configuration/derive_corsika_limits.py +361 -427
  77. simtools/production_configuration/derive_production_statistics_handler.py +7 -6
  78. simtools/production_configuration/generate_production_grid.py +9 -11
  79. simtools/production_configuration/merge_corsika_limits.py +528 -0
  80. simtools/ray_tracing/mirror_panel_psf.py +1 -0
  81. simtools/ray_tracing/psf_parameter_optimisation.py +792 -0
  82. simtools/ray_tracing/ray_tracing.py +6 -2
  83. simtools/reporting/docs_read_parameters.py +150 -62
  84. simtools/runners/corsika_runner.py +1 -1
  85. simtools/runners/corsika_simtel_runner.py +14 -5
  86. simtools/runners/runner_services.py +10 -5
  87. simtools/runners/simtools_runner.py +267 -0
  88. simtools/schemas/application_workflow.metaschema.yml +101 -68
  89. simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +1 -1
  90. simtools/schemas/input/single_pe_spectrum.schema.yml +1 -1
  91. simtools/schemas/metadata.metaschema.yml +577 -3
  92. simtools/schemas/model_parameter.metaschema.yml +6 -6
  93. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +2 -2
  94. simtools/schemas/model_parameters/adjust_gain.schema.yml +1 -1
  95. simtools/schemas/model_parameters/altitude.schema.yml +1 -1
  96. simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
  97. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +1 -1
  98. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +1 -1
  99. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
  100. simtools/schemas/model_parameters/array_layouts.schema.yml +1 -1
  101. simtools/schemas/model_parameters/array_triggers.schema.yml +1 -1
  102. simtools/schemas/model_parameters/array_window.schema.yml +1 -1
  103. simtools/schemas/model_parameters/asum_clipping.schema.yml +1 -1
  104. simtools/schemas/model_parameters/asum_offset.schema.yml +1 -1
  105. simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
  106. simtools/schemas/model_parameters/asum_threshold.schema.yml +1 -1
  107. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +1 -1
  108. simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +1 -1
  109. simtools/schemas/model_parameters/axes_offsets.schema.yml +1 -1
  110. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +1 -1
  111. simtools/schemas/model_parameters/camera_body_shape.schema.yml +1 -1
  112. simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
  113. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +1 -1
  114. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +1 -1
  115. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
  116. simtools/schemas/model_parameters/camera_depth.schema.yml +1 -1
  117. simtools/schemas/model_parameters/camera_filter.schema.yml +1 -1
  118. simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +1 -1
  119. simtools/schemas/model_parameters/camera_pixels.schema.yml +1 -1
  120. simtools/schemas/model_parameters/camera_transmission.schema.yml +1 -1
  121. simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
  122. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +1 -1
  123. simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +1 -1
  124. simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +1 -1
  125. simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +1 -1
  126. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +1 -1
  127. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +1 -1
  128. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +1 -1
  129. simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +1 -1
  130. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +1 -1
  131. simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +1 -1
  132. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +3 -3
  133. simtools/schemas/model_parameters/dark_events.schema.yml +1 -1
  134. simtools/schemas/model_parameters/default_trigger.schema.yml +1 -1
  135. simtools/schemas/model_parameters/design_model.schema.yml +1 -1
  136. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +1 -1
  137. simtools/schemas/model_parameters/disc_bins.schema.yml +1 -1
  138. simtools/schemas/model_parameters/disc_start.schema.yml +1 -1
  139. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +1 -1
  140. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +1 -1
  141. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +1 -1
  142. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +1 -1
  143. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +1 -1
  144. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +1 -1
  145. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +1 -1
  146. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +1 -1
  147. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +1 -1
  148. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +1 -1
  149. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +1 -1
  150. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -1
  151. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +1 -1
  152. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +1 -1
  153. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +1 -1
  154. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +1 -1
  155. simtools/schemas/model_parameters/dish_shape_length.schema.yml +1 -1
  156. simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -1
  157. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +1 -1
  158. simtools/schemas/model_parameters/dsum_offset.schema.yml +1 -1
  159. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +1 -1
  160. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +1 -1
  161. simtools/schemas/model_parameters/dsum_prescale.schema.yml +1 -1
  162. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +1 -1
  163. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +1 -1
  164. simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
  165. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +1 -1
  166. simtools/schemas/model_parameters/dsum_threshold.schema.yml +2 -2
  167. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +1 -1
  168. simtools/schemas/model_parameters/effective_focal_length.schema.yml +1 -1
  169. simtools/schemas/model_parameters/epsg_code.schema.yml +1 -1
  170. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +1 -1
  171. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +1 -1
  172. simtools/schemas/model_parameters/fadc_bins.schema.yml +1 -1
  173. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
  174. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
  175. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +1 -1
  176. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +1 -1
  177. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +1 -1
  178. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
  179. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
  180. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +1 -1
  181. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +1 -1
  182. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +1 -1
  183. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +1 -1
  184. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +1 -1
  185. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +1 -1
  186. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +1 -1
  187. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +1 -1
  188. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +1 -1
  189. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +1 -1
  190. simtools/schemas/model_parameters/fadc_long_event_threshold.schema.yml +35 -0
  191. simtools/schemas/model_parameters/fadc_long_sum_bins.schema.yml +41 -0
  192. simtools/schemas/model_parameters/fadc_long_sum_offset.schema.yml +38 -0
  193. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +1 -1
  194. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +1 -1
  195. simtools/schemas/model_parameters/fadc_mhz.schema.yml +1 -1
  196. simtools/schemas/model_parameters/fadc_noise.schema.yml +1 -1
  197. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +1 -1
  198. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +1 -1
  199. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +1 -1
  200. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +1 -1
  201. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +1 -1
  202. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +1 -1
  203. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +1 -1
  204. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +1 -1
  205. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  206. simtools/schemas/model_parameters/flatfielding.schema.yml +1 -1
  207. simtools/schemas/model_parameters/focal_length.schema.yml +1 -1
  208. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +1 -1
  209. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +1 -1
  210. simtools/schemas/model_parameters/focus_offset.schema.yml +1 -1
  211. simtools/schemas/model_parameters/gain_variation.schema.yml +1 -1
  212. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +1 -1
  213. simtools/schemas/model_parameters/geomag_rotation.schema.yml +1 -1
  214. simtools/schemas/model_parameters/geomag_vertical.schema.yml +1 -1
  215. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +1 -1
  216. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
  217. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
  218. simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
  219. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +1 -1
  220. simtools/schemas/model_parameters/laser_photons.schema.yml +1 -1
  221. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +1 -1
  222. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +1 -1
  223. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +1 -1
  224. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +1 -1
  225. simtools/schemas/model_parameters/laser_var_photons.schema.yml +1 -1
  226. simtools/schemas/model_parameters/laser_wavelength.schema.yml +1 -1
  227. simtools/schemas/model_parameters/led_events.schema.yml +1 -1
  228. simtools/schemas/model_parameters/led_photons.schema.yml +1 -1
  229. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +1 -1
  230. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +1 -1
  231. simtools/schemas/model_parameters/led_var_photons.schema.yml +1 -1
  232. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
  233. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +50 -1
  234. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
  235. simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
  236. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +1 -1
  237. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +1 -1
  238. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +1 -1
  239. simtools/schemas/model_parameters/mirror_class.schema.yml +1 -1
  240. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +1 -1
  241. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +1 -1
  242. simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
  243. simtools/schemas/model_parameters/mirror_offset.schema.yml +1 -1
  244. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +1 -1
  245. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +1 -1
  246. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +1 -1
  247. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +1 -1
  248. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +1 -1
  249. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +1 -1
  250. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +1 -1
  251. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +1 -1
  252. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +1 -1
  253. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
  254. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +1 -1
  255. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +1 -1
  256. simtools/schemas/model_parameters/nsb_sky_map.schema.yml +1 -1
  257. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +1 -1
  258. simtools/schemas/model_parameters/num_gains.schema.yml +1 -1
  259. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +1 -1
  260. simtools/schemas/model_parameters/optics_properties.schema.yml +1 -1
  261. simtools/schemas/model_parameters/parabolic_dish.schema.yml +1 -1
  262. simtools/schemas/model_parameters/pedestal_events.schema.yml +1 -1
  263. simtools/schemas/model_parameters/photon_delay.schema.yml +1 -1
  264. simtools/schemas/model_parameters/photons_per_run.schema.yml +1 -1
  265. simtools/schemas/model_parameters/pixel_cells.schema.yml +1 -1
  266. simtools/schemas/model_parameters/pixels_parallel.schema.yml +1 -1
  267. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +1 -1
  268. simtools/schemas/model_parameters/pm_average_gain.schema.yml +1 -1
  269. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +1 -1
  270. simtools/schemas/model_parameters/pm_gain_index.schema.yml +1 -1
  271. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +1 -1
  272. simtools/schemas/model_parameters/pm_transit_time.schema.yml +1 -1
  273. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +1 -1
  274. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +1 -1
  275. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +1 -1
  276. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +1 -1
  277. simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +11 -1
  278. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +1 -1
  279. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +1 -1
  280. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
  281. simtools/schemas/model_parameters/qe_variation.schema.yml +1 -1
  282. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +1 -1
  283. simtools/schemas/model_parameters/random_focal_length.schema.yml +1 -1
  284. simtools/schemas/model_parameters/random_generator.schema.yml +1 -1
  285. simtools/schemas/model_parameters/random_mono_probability.schema.yml +1 -1
  286. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +1 -1
  287. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +1 -1
  288. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +1 -1
  289. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +1 -1
  290. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +1 -1
  291. simtools/schemas/model_parameters/sampled_output.schema.yml +1 -1
  292. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +1 -1
  293. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +1 -1
  294. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
  295. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
  296. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +1 -1
  297. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +1 -1
  298. simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +11 -1
  299. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +1 -1
  300. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +1 -1
  301. simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +11 -1
  302. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
  303. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +1 -1
  304. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +1 -1
  305. simtools/schemas/model_parameters/stars.schema.yml +1 -1
  306. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
  307. simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
  308. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +1 -1
  309. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +1 -1
  310. simtools/schemas/model_parameters/telescope_random_error.schema.yml +1 -1
  311. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +1 -1
  312. simtools/schemas/model_parameters/telescope_transmission.schema.yml +1 -1
  313. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +1 -1
  314. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +1 -1
  315. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +1 -1
  316. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +1 -1
  317. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +1 -1
  318. simtools/schemas/model_parameters/transit_time_error.schema.yml +1 -1
  319. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +1 -1
  320. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +1 -1
  321. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +1 -1
  322. simtools/schemas/model_parameters/trigger_pixels.schema.yml +1 -1
  323. simtools/schemas/plot_configuration.metaschema.yml +5 -2
  324. simtools/schemas/production_configuration_metrics.schema.yml +12 -2
  325. simtools/schemas/production_tables.schema.yml +2 -2
  326. simtools/simtel/simtel_config_reader.py +2 -2
  327. simtools/simtel/simtel_config_writer.py +16 -4
  328. simtools/simtel/simtel_io_event_histograms.py +746 -0
  329. simtools/simtel/simtel_io_event_reader.py +15 -42
  330. simtools/simtel/simtel_io_event_writer.py +9 -9
  331. simtools/simtel/simtel_io_histogram.py +3 -1
  332. simtools/simtel/simtel_io_histograms.py +7 -3
  333. simtools/simtel/simtel_table_reader.py +92 -10
  334. simtools/simtel/simulator_array.py +138 -10
  335. simtools/simtel/simulator_camera_efficiency.py +32 -23
  336. simtools/simtel/simulator_light_emission.py +437 -271
  337. simtools/simtel/simulator_ray_tracing.py +1 -1
  338. simtools/simulator.py +105 -147
  339. simtools/testing/configuration.py +24 -26
  340. simtools/testing/helpers.py +2 -2
  341. simtools/testing/log_inspector.py +50 -0
  342. simtools/testing/validate_output.py +87 -37
  343. simtools/utils/general.py +125 -255
  344. simtools/utils/geometry.py +36 -0
  345. simtools/utils/names.py +1 -1
  346. simtools/visualization/legend_handlers.py +180 -264
  347. simtools/visualization/plot_array_layout.py +20 -8
  348. simtools/visualization/plot_pixels.py +1 -1
  349. simtools/visualization/plot_tables.py +133 -37
  350. simtools/visualization/simtel_event_plots.py +816 -0
  351. simtools/visualization/visualize.py +4 -101
  352. gammasimtools-0.18.0.dist-info/RECORD +0 -376
  353. simtools/production_configuration/derive_corsika_limits_grid.py +0 -232
  354. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/WHEEL +0 -0
  355. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/top_level.txt +0 -0
  356. /simtools/{io_operations → io}/hdf5_handler.py +0 -0
  357. /simtools/{io_operations → io}/legacy_data_handler.py +0 -0
  358. /simtools/{io_operations/io_table_handler.py → io/table_handler.py} +0 -0
@@ -1,456 +1,390 @@
1
- """Calculate CORSIKA thresholds for energy, radial distance, and viewcone."""
1
+ """Derive CORSIKA limits from a reduced event data file."""
2
2
 
3
+ import datetime
3
4
  import logging
4
5
 
5
6
  import astropy.units as u
6
- import matplotlib.pyplot as plt
7
7
  import numpy as np
8
- from matplotlib.colors import LogNorm
8
+ from astropy.table import Column, Table
9
9
 
10
- from simtools.simtel.simtel_io_event_reader import SimtelIOEventDataReader
10
+ from simtools.data_model.metadata_collector import MetadataCollector
11
+ from simtools.io import ascii_handler, io_handler
12
+ from simtools.model.site_model import SiteModel
13
+ from simtools.simtel.simtel_io_event_histograms import SimtelIOEventHistograms
11
14
 
15
+ _logger = logging.getLogger(__name__)
12
16
 
13
- class LimitCalculator:
17
+
18
+ def generate_corsika_limits_grid(args_dict, db_config=None):
19
+ """
20
+ Generate CORSIKA limits.
21
+
22
+ Parameters
23
+ ----------
24
+ args_dict : dict
25
+ Dictionary containing command line arguments.
26
+ db_config : dict, optional
27
+ Database configuration dictionary.
28
+ """
29
+ if args_dict.get("array_layout_name"):
30
+ telescope_configs = _read_array_layouts_from_db(
31
+ args_dict["array_layout_name"],
32
+ args_dict.get("site"),
33
+ args_dict.get("model_version"),
34
+ db_config,
35
+ )
36
+ else:
37
+ telescope_configs = ascii_handler.collect_data_from_file(args_dict["telescope_ids"])[
38
+ "telescope_configs"
39
+ ]
40
+
41
+ results = []
42
+ for array_name, telescope_ids in telescope_configs.items():
43
+ _logger.info(
44
+ f"Processing file: {args_dict['event_data_file']} with telescope config: {array_name}"
45
+ )
46
+ result = _process_file(
47
+ args_dict["event_data_file"],
48
+ array_name,
49
+ telescope_ids,
50
+ args_dict["loss_fraction"],
51
+ args_dict["plot_histograms"],
52
+ )
53
+ result["layout"] = array_name
54
+ results.append(result)
55
+
56
+ write_results(results, args_dict)
57
+
58
+
59
+ def _process_file(file_path, array_name, telescope_ids, loss_fraction, plot_histograms):
14
60
  """
15
- Compute limits for CORSIKA configuration for energy, radial distance, and viewcone.
61
+ Compute limits for a given event data file and telescope configuration.
16
62
 
17
- Event data is read from the reduced MC event data file.
63
+ Compute limits for energy, radial distance, and viewcone.
18
64
 
19
65
  Parameters
20
66
  ----------
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).
67
+ file_path : str
68
+ Path to the event data file.
69
+ array_name : str
70
+ Name of the telescope array configuration.
71
+ telescope_ids : list[int]
72
+ List of telescope IDs to filter the events.
73
+ loss_fraction : float
74
+ Fraction of events to be lost.
75
+ plot_histograms : bool
76
+ Whether to plot histograms.
77
+
78
+ Returns
79
+ -------
80
+ dict
81
+ Dictionary containing the computed limits and metadata.
27
82
  """
83
+ histograms = SimtelIOEventHistograms(
84
+ file_path, array_name=array_name, telescope_list=telescope_ids
85
+ )
86
+ histograms.fill()
87
+
88
+ limits = {
89
+ "lower_energy_limit": compute_lower_energy_limit(histograms, loss_fraction),
90
+ "upper_radius_limit": compute_upper_radius_limit(histograms, loss_fraction),
91
+ "viewcone_radius": compute_viewcone(histograms, loss_fraction),
92
+ }
93
+
94
+ if plot_histograms:
95
+ histograms.plot_data(
96
+ output_path=io_handler.IOHandler().get_output_directory(),
97
+ limits=limits,
98
+ )
99
+
100
+ return limits
28
101
 
29
- def __init__(self, event_data_file, array_name=None, telescope_list=None):
30
- """Initialize the LimitCalculator with the given event data file."""
31
- self._logger = logging.getLogger(__name__)
32
- self.event_data_file = event_data_file
33
- self.array_name = array_name
34
- self.telescope_list = telescope_list
35
-
36
- self.limits = None
37
- self.histograms = {}
38
- self.file_info = {}
39
-
40
- self.reader = SimtelIOEventDataReader(event_data_file, telescope_list=telescope_list)
41
-
42
- def _prepare_limit_data(self, file_info_table):
43
- """
44
- Prepare result data structure for limit calculation.
45
-
46
- Contains both the point in parameter space and the limits derived for that point.
47
-
48
- Parameters
49
- ----------
50
- file_info_table : astropy.table.Table
51
- Table containing file information.
52
-
53
- Returns
54
- -------
55
- dict
56
- Dictionary containing limits (not yet calculated) and parameter space information.
57
- """
58
- self.file_info = self.reader.get_reduced_simulation_file_info(file_info_table)
59
- return {
60
- "primary_particle": self.file_info["primary_particle"],
61
- "zenith": self.file_info["zenith"],
62
- "azimuth": self.file_info["azimuth"],
63
- "nsb_level": self.file_info["nsb_level"],
64
- "array_name": self.array_name,
65
- "telescope_ids": self.telescope_list,
66
- "lower_energy_limit": None,
67
- "upper_radius_limit": None,
68
- "viewcone_radius": None,
102
+
103
+ def write_results(results, args_dict):
104
+ """
105
+ Write the computed limits as astropy table to file.
106
+
107
+ Parameters
108
+ ----------
109
+ results : list[dict]
110
+ List of computed limits.
111
+ args_dict : dict
112
+ Dictionary containing command line arguments.
113
+ """
114
+ table = _create_results_table(results, args_dict["loss_fraction"])
115
+
116
+ output_dir = io_handler.IOHandler().get_output_directory("corsika_limits")
117
+ output_file = output_dir / args_dict["output_file"]
118
+
119
+ table.write(output_file, format="ascii.ecsv", overwrite=True)
120
+ _logger.info(f"Results saved to {output_file}")
121
+
122
+ MetadataCollector.dump(args_dict, output_file)
123
+
124
+
125
+ def _create_results_table(results, loss_fraction):
126
+ """
127
+ Convert list of simulation results to an astropy Table with metadata.
128
+
129
+ Round values to appropriate precision and add metadata.
130
+
131
+ Parameters
132
+ ----------
133
+ results : list[dict]
134
+ Computed limits per file and telescope configuration.
135
+ loss_fraction : float
136
+ Fraction of lost events (added to metadata).
137
+
138
+ Returns
139
+ -------
140
+ astropy.table.Table
141
+ Table with computed limits.
142
+ """
143
+ cols = [
144
+ "primary_particle",
145
+ "array_name",
146
+ "telescope_ids",
147
+ "zenith",
148
+ "azimuth",
149
+ "nsb_level",
150
+ "lower_energy_limit",
151
+ "upper_radius_limit",
152
+ "viewcone_radius",
153
+ ]
154
+
155
+ columns = {name: [] for name in cols}
156
+ units = {}
157
+
158
+ for res in results:
159
+ _process_result_row(res, cols, columns, units)
160
+
161
+ table_cols = _create_table_columns(cols, columns, units)
162
+ table = Table(table_cols)
163
+
164
+ table.meta.update(
165
+ {
166
+ "created": datetime.datetime.now().isoformat(),
167
+ "description": "Lookup table for CORSIKA limits computed from simulations.",
168
+ "loss_fraction": loss_fraction,
69
169
  }
170
+ )
70
171
 
71
- def compute_limits(self, loss_fraction):
72
- """
73
- Compute the limits for energy, radial distance, and viewcone.
74
-
75
- Parameters
76
- ----------
77
- loss_fraction : float
78
- Fraction of events to be lost.
79
-
80
- Returns
81
- -------
82
- dict
83
- Dictionary containing the computed limits.
84
- """
85
- self._fill_histograms()
86
-
87
- self.limits["lower_energy_limit"] = self.compute_lower_energy_limit(loss_fraction)
88
- self.limits["upper_radius_limit"] = self.compute_upper_radius_limit(loss_fraction)
89
- self.limits["viewcone_radius"] = self.compute_viewcone(loss_fraction)
90
-
91
- return self.limits
92
-
93
- def _fill_histogram_and_bin_edges(self, name, data, bins, hist1d=True):
94
- """
95
- Fill histogram and bin edges and it both to histogram dictionary.
96
-
97
- Adds histogram to existing histogram if it exists, otherwise initializes it.
98
-
99
- """
100
- if name in self.histograms:
101
- if hist1d:
102
- bins = self.histograms[f"{name}_bin_edges"]
103
- hist, _ = np.histogram(data, bins=bins)
104
- self.histograms[name] += hist
105
- else:
106
- x_bins = self.histograms[f"{name}_bin_x_edges"]
107
- y_bins = self.histograms[f"{name}_bin_y_edges"]
108
- hist, _, _ = np.histogram2d(data[0], data[1], bins=[x_bins, y_bins])
109
- self.histograms[name] += hist
172
+ return table
173
+
174
+
175
+ def _process_result_row(res, cols, columns, units):
176
+ """Process a single result row and add values to columns."""
177
+ for k in cols:
178
+ val = res.get(k, None)
179
+ if val is not None:
180
+ val = _round_value(k, val)
181
+ _logger.debug(f"Adding {k}: {val} to column data")
182
+
183
+ if hasattr(val, "unit"):
184
+ columns[k].append(val.value)
185
+ units[k] = val.unit
110
186
  else:
111
- if hist1d:
112
- hist, bin_edges = np.histogram(data, bins=bins)
113
- self.histograms[name] = hist
114
- self.histograms[f"{name}_bin_edges"] = bin_edges
115
- else:
116
- hist, x_edges, y_edges = np.histogram2d(data[0], data[1], bins=bins)
117
- self.histograms[name] = hist
118
- self.histograms[f"{name}_bin_x_edges"] = x_edges
119
- self.histograms[f"{name}_bin_y_edges"] = y_edges
120
-
121
- def _fill_histograms(self):
122
- """
123
- Fill histograms with event data.
124
-
125
- Involves looping over all event data, and therefore is the slowest part of the
126
- limit calculation. Adds the histograms to the histogram dictionary.
127
- """
128
- for data_set in self.reader.data_sets:
129
- self._logger.info(f"Reading event data from {self.event_data_file} for {data_set}")
130
- file_info, _, event_data, triggered_data = self.reader.read_event_data(
131
- self.event_data_file, table_name_map=data_set
132
- )
133
- self.limits = self.limits if self.limits else self._prepare_limit_data(file_info)
134
-
135
- self._fill_histogram_and_bin_edges(
136
- "energy", event_data.simulated_energy, self.energy_bins
137
- )
138
- self._fill_histogram_and_bin_edges(
139
- "core_distance", event_data.core_distance_shower, self.core_distance_bins
140
- )
141
- self._fill_histogram_and_bin_edges(
142
- "angular_distance", triggered_data.angular_distance, self.view_cone_bins
143
- )
144
-
145
- xy_bins = np.linspace(
146
- -1.0 * self.core_distance_bins.max(),
147
- self.core_distance_bins.max(),
148
- len(self.core_distance_bins),
149
- )
150
- self._fill_histogram_and_bin_edges(
151
- "shower_cores",
152
- (event_data.x_core_shower, event_data.y_core_shower),
153
- [xy_bins, xy_bins],
154
- hist1d=False,
155
- )
156
- self._fill_histogram_and_bin_edges(
157
- "core_vs_energy",
158
- (event_data.core_distance_shower, event_data.simulated_energy),
159
- [self.core_distance_bins, self.energy_bins],
160
- hist1d=False,
161
- )
162
-
163
- def _compute_limits(self, hist, bin_edges, loss_fraction, limit_type="lower"):
164
- """
165
- Compute the limits based on the loss fraction.
166
-
167
- Add or subtract one bin to be on the safe side of the limit.
168
-
169
- Parameters
170
- ----------
171
- hist : np.ndarray
172
- 1D histogram array.
173
- bin_edges : np.ndarray
174
- Array of bin edges.
175
- loss_fraction : float
176
- Fraction of events to be lost.
177
- limit_type : str, optional
178
- Type of limit ('lower' or 'upper'). Default is 'lower'.
179
-
180
- Returns
181
- -------
182
- float
183
- Bin edge value corresponding to the threshold.
184
- """
185
- total_events = np.sum(hist)
186
- threshold = (1 - loss_fraction) * total_events
187
- if limit_type == "upper":
188
- cum = np.cumsum(hist)
189
- idx = np.searchsorted(cum, threshold) + 1
190
- return bin_edges[min(idx, len(bin_edges) - 1)]
191
- if limit_type == "lower":
192
- cum = np.cumsum(hist[::-1])
193
- idx = np.searchsorted(cum, threshold) + 1
194
- return bin_edges[max(len(bin_edges) - 1 - idx, 0)]
195
- raise ValueError("limit_type must be 'lower' or 'upper'")
196
-
197
- @property
198
- def energy_bins(self):
199
- """Return bins for the energy histogram."""
200
- return np.logspace(
201
- np.log10(self.file_info.get("energy_min", 1.0e-3 * u.TeV).to("TeV").value),
202
- np.log10(self.file_info.get("energy_max", 1.0e3 * u.TeV).to("TeV").value),
203
- 100,
204
- )
187
+ columns[k].append(val)
188
+ if k not in units:
189
+ units[k] = None
190
+
191
+
192
+ def _round_value(key, val):
193
+ """Round value based on key type."""
194
+ if key == "lower_energy_limit":
195
+ return np.floor(val * 1e3) / 1e3
196
+ if key == "upper_radius_limit":
197
+ return np.ceil(val / 25) * 25
198
+ if key == "viewcone_radius":
199
+ return np.ceil(val / 0.25) * 0.25
200
+ return val
201
+
202
+
203
+ def _create_table_columns(cols, columns, units):
204
+ """Create table columns with appropriate data types."""
205
+ table_cols = []
206
+ for k in cols:
207
+ col_data = columns[k]
208
+ if any(isinstance(v, list | tuple) for v in col_data):
209
+ col = Column(data=col_data, name=k, unit=units.get(k), dtype=object)
210
+ else:
211
+ col = Column(data=col_data, name=k, unit=units.get(k))
212
+ table_cols.append(col)
213
+ return table_cols
205
214
 
206
- def compute_lower_energy_limit(self, loss_fraction):
207
- """
208
- Compute the lower energy limit in TeV based on the event loss fraction.
209
-
210
- Parameters
211
- ----------
212
- loss_fraction : float
213
- Fraction of events to be lost.
214
-
215
- Returns
216
- -------
217
- astropy.units.Quantity
218
- Lower energy limit.
219
- """
220
- return (
221
- self._compute_limits(
222
- self.histograms.get("energy"), self.energy_bins, loss_fraction, limit_type="lower"
223
- )
224
- * u.TeV
225
- )
226
215
 
227
- @property
228
- def core_distance_bins(self):
229
- """Return bins for the core distance histogram."""
230
- return np.linspace(
231
- self.file_info.get("core_scatter_min", 0.0 * u.m).to("m").value,
232
- self.file_info.get("core_scatter_max", 1.0e5 * u.m).to("m").value,
233
- 100,
234
- )
216
+ def _read_array_layouts_from_db(layouts, site, model_version, db_config):
217
+ """
218
+ Read array layouts from the database.
235
219
 
236
- def compute_upper_radius_limit(self, loss_fraction):
237
- """
238
- Compute the upper radial distance based on the event loss fraction.
239
-
240
- Parameters
241
- ----------
242
- loss_fraction : float
243
- Fraction of events to be lost.
244
-
245
- Returns
246
- -------
247
- astropy.units.Quantity
248
- Upper radial distance in m.
249
- """
250
- return (
251
- self._compute_limits(
252
- self.histograms.get("core_distance"),
253
- self.core_distance_bins,
254
- loss_fraction,
255
- limit_type="upper",
256
- )
257
- * u.m
258
- )
220
+ Parameters
221
+ ----------
222
+ layouts : list[str]
223
+ List of layout names to read. If "all", read all available layouts.
224
+ site : str
225
+ Site name for the array layouts.
226
+ model_version : str
227
+ Model version for the array layouts.
228
+ db_config : dict
229
+ Database configuration dictionary.
230
+
231
+ Returns
232
+ -------
233
+ dict
234
+ Dictionary mapping layout names to telescope IDs.
235
+ """
236
+ site_model = SiteModel(site=site, model_version=model_version, mongo_db_config=db_config)
237
+ layout_names = site_model.get_list_of_array_layouts() if layouts == ["all"] else layouts
238
+ layout_dict = {}
239
+ for layout_name in layout_names:
240
+ layout_dict[layout_name] = site_model.get_array_elements_for_layout(layout_name)
241
+ return layout_dict
259
242
 
260
- @property
261
- def view_cone_bins(self):
262
- """Return bins for the viewcone histogram."""
263
- return np.linspace(
264
- self.file_info.get("viewcone_min", 0.0 * u.deg).to("deg").value,
265
- self.file_info.get("viewcone_max", 20.0 * u.deg).to("deg").value,
266
- 100,
267
- )
268
243
 
269
- def compute_viewcone(self, loss_fraction):
270
- """
271
- Compute the viewcone based on the event loss fraction.
272
-
273
- The shower IDs of triggered events are used to create a mask for the
274
- azimuth and altitude of the triggered events. A mapping is created
275
- between the triggered events and the simulated events using the shower IDs.
276
-
277
- Parameters
278
- ----------
279
- loss_fraction : float
280
- Fraction of events to be lost.
281
-
282
- Returns
283
- -------
284
- astropy.units.Quantity
285
- Viewcone radius in degrees.
286
- """
287
- return (
288
- self._compute_limits(
289
- self.histograms.get("angular_distance"),
290
- self.view_cone_bins,
291
- loss_fraction,
292
- limit_type="upper",
293
- )
294
- * u.deg
244
+ def _compute_limits(hist, bin_edges, loss_fraction, limit_type="lower"):
245
+ """
246
+ Compute the limits based on the loss fraction.
247
+
248
+ Add or subtract one bin to be on the safe side of the limit.
249
+
250
+ Parameters
251
+ ----------
252
+ hist : np.ndarray
253
+ 1D histogram array.
254
+ bin_edges : np.ndarray
255
+ Array of bin edges.
256
+ loss_fraction : float
257
+ Fraction of events to be lost.
258
+ limit_type : str, optional
259
+ Type of limit ('lower' or 'upper'). Default is 'lower'.
260
+
261
+ Returns
262
+ -------
263
+ float
264
+ Bin edge value corresponding to the threshold.
265
+ """
266
+ total_events = np.sum(hist)
267
+ threshold = (1 - loss_fraction) * total_events
268
+ if limit_type == "upper":
269
+ cum = np.cumsum(hist)
270
+ idx = np.searchsorted(cum, threshold) + 1
271
+ return bin_edges[min(idx, len(bin_edges) - 1)]
272
+ if limit_type == "lower":
273
+ cum = np.cumsum(hist[::-1])
274
+ idx = np.searchsorted(cum, threshold) + 1
275
+ return bin_edges[max(len(bin_edges) - 1 - idx, 0)]
276
+ raise ValueError("limit_type must be 'lower' or 'upper'")
277
+
278
+
279
+ def compute_lower_energy_limit(histograms, loss_fraction):
280
+ """
281
+ Compute the lower energy limit in TeV based on the event loss fraction.
282
+
283
+ Parameters
284
+ ----------
285
+ histograms : SimtelIOEventHistograms
286
+ Histograms.
287
+ loss_fraction : float
288
+ Fraction of events to be lost.
289
+
290
+ Returns
291
+ -------
292
+ astropy.units.Quantity
293
+ Lower energy limit.
294
+ """
295
+ energy_min = (
296
+ _compute_limits(
297
+ histograms.histograms.get("energy"),
298
+ histograms.energy_bins,
299
+ loss_fraction,
300
+ limit_type="lower",
295
301
  )
302
+ * u.TeV
303
+ )
296
304
 
297
- def plot_data(self, output_path=None):
298
- """
299
- Histogram plotting.
300
-
301
- Parameters
302
- ----------
303
- output_path: Path or str, optional
304
- Directory to save plots. If None, plots will be displayed.
305
- """
306
- self._logger.info(f"Plotting histograms written to {output_path}")
307
- event_counts = "Event Count"
308
- plots = {
309
- "core_vs_energy": {
310
- "data": self.histograms.get("core_vs_energy"),
311
- "bins": [
312
- self.histograms.get("core_vs_energy_bin_x_edges"),
313
- self.histograms.get("core_vs_energy_bin_y_edges"),
314
- ],
315
- "plot_type": "histogram2d",
316
- "plot_params": {"norm": "log", "cmap": "viridis"},
317
- "labels": {
318
- "x": "Core Distance [m]",
319
- "y": "Energy [TeV]",
320
- "title": "Triggered events: core distance vs energy",
321
- },
322
- "lines": {
323
- "x": self.limits["upper_radius_limit"].value,
324
- "y": self.limits["lower_energy_limit"].value,
325
- },
326
- "scales": {"y": "log"},
327
- "colorbar_label": event_counts,
328
- "filename": "core_vs_energy_distribution",
329
- },
330
- "energy_distribution": {
331
- "data": self.histograms.get("energy"),
332
- "bins": self.histograms.get("energy_bin_edges"),
333
- "plot_type": "histogram",
334
- "plot_params": {"color": "g", "edgecolor": "g", "lw": 1},
335
- "labels": {
336
- "x": "Energy [TeV]",
337
- "y": event_counts,
338
- "title": "Triggered events: energy distribution",
339
- },
340
- "scales": {"x": "log", "y": "log"},
341
- "lines": {"x": self.limits["lower_energy_limit"].value},
342
- "filename": "energy_distribution",
343
- },
344
- "core_distance": {
345
- "data": self.histograms.get("core_distance"),
346
- "bins": self.histograms.get("core_distance_bin_edges"),
347
- "plot_type": "histogram",
348
- "plot_params": {"color": "g", "edgecolor": "g", "lw": 1},
349
- "labels": {
350
- "x": "Core Distance [m]",
351
- "y": event_counts,
352
- "title": "Triggered events: core distance distribution",
353
- },
354
- "lines": {"x": self.limits["upper_radius_limit"].value},
355
- "filename": "core_distance_distribution",
356
- },
357
- "core_xy": {
358
- "data": self.histograms.get("shower_cores"),
359
- "bins": [
360
- self.histograms.get("shower_cores_bin_x_edges"),
361
- self.histograms.get("shower_cores_bin_y_edges"),
362
- ],
363
- "plot_type": "histogram2d",
364
- "plot_params": {"norm": "log", "cmap": "viridis", "aspect": "equal"},
365
- "labels": {
366
- "x": "Core X [m]",
367
- "y": "Core Y [m]",
368
- "title": "Triggered events: core x vs core y",
369
- },
370
- "colorbar_label": event_counts,
371
- "lines": {
372
- "r": self.limits["upper_radius_limit"].value,
373
- },
374
- "filename": "core_xy_distribution",
375
- },
376
- "angular_distance": {
377
- "data": self.histograms.get("angular_distance"),
378
- "bins": self.histograms.get("angular_distance_bin_edges"),
379
- "plot_type": "histogram",
380
- "plot_params": {"color": "g", "edgecolor": "g", "lw": 1},
381
- "labels": {
382
- "x": "Distance to pointing direction [deg]",
383
- "y": event_counts,
384
- "title": "Triggered events: angular distance distribution",
385
- },
386
- "lines": {"x": self.limits["viewcone_radius"].value},
387
- "filename": "angular_distance_distribution",
388
- },
389
- }
305
+ return _is_close(
306
+ energy_min,
307
+ histograms.file_info["energy_min"].to("TeV")
308
+ if "energy_min" in histograms.file_info
309
+ else None,
310
+ "Lower energy limit is equal to the minimum energy of",
311
+ )
312
+
313
+
314
+ def _is_close(value, reference, warning_text):
315
+ """Check if the value is close to the reference value and log a warning if so."""
316
+ if reference is not None and np.isclose(value.value, reference.value, rtol=1.0e-2):
317
+ _logger.warning(f"{warning_text} {value}.")
318
+ return value
390
319
 
391
- for _, plot_args in plots.items():
392
- filename = plot_args.pop("filename")
393
- if self.array_name:
394
- if plot_args.get("labels", {}).get("title"):
395
- plot_args["labels"]["title"] += f" ({self.array_name} array)"
396
- filename = f"{filename}_{self.array_name}.png"
397
- else:
398
- filename = f"{filename}.png"
399
- output_file = output_path / filename if output_path else None
400
- self._create_plot(**plot_args, output_file=output_file)
401
-
402
- def _create_plot(
403
- self,
404
- data,
405
- bins=None,
406
- plot_type="histogram",
407
- plot_params=None,
408
- labels=None,
409
- scales=None,
410
- colorbar_label=None,
411
- output_file=None,
412
- lines=None,
413
- ):
414
- """Create and save a plot with the given parameters."""
415
- plot_params = plot_params or {}
416
- labels = labels or {}
417
- scales = scales or {}
418
- lines = lines or {}
419
-
420
- fig, ax = plt.subplots(figsize=(8, 6))
421
-
422
- if plot_type == "histogram":
423
- plt.bar(bins[:-1], data, width=np.diff(bins), **plot_params)
424
- elif plot_type == "histogram2d":
425
- pcm = plt.pcolormesh(
426
- bins[0], bins[1], data.T, norm=LogNorm(vmin=1, vmax=data.max()), cmap="viridis"
427
- )
428
- plt.colorbar(pcm, label=colorbar_label)
429
-
430
- if "x" in lines:
431
- plt.axvline(lines["x"], color="r", linestyle="--", linewidth=0.5)
432
- if "y" in lines:
433
- plt.axhline(lines["y"], color="r", linestyle="--", linewidth=0.5)
434
- if "r" in lines:
435
- circle = plt.Circle(
436
- (0, 0), lines["r"], color="r", fill=False, linestyle="--", linewidth=0.5
437
- )
438
- plt.gca().add_artist(circle)
439
-
440
- ax.set(
441
- xlabel=labels.get("x", ""),
442
- ylabel=labels.get("y", ""),
443
- title=labels.get("title", ""),
444
- xscale=scales.get("x", "linear"),
445
- yscale=scales.get("y", "linear"),
320
+
321
+ def compute_upper_radius_limit(histograms, loss_fraction):
322
+ """
323
+ Compute the upper radial distance based on the event loss fraction.
324
+
325
+ Parameters
326
+ ----------
327
+ histograms : SimtelIOEventHistograms
328
+ Histograms.
329
+ loss_fraction : float
330
+ Fraction of events to be lost.
331
+
332
+ Returns
333
+ -------
334
+ astropy.units.Quantity
335
+ Upper radial distance in m.
336
+ """
337
+ radius_limit = (
338
+ _compute_limits(
339
+ histograms.histograms.get("core_distance"),
340
+ histograms.core_distance_bins,
341
+ loss_fraction,
342
+ limit_type="upper",
446
343
  )
344
+ * u.m
345
+ )
346
+ return _is_close(
347
+ radius_limit,
348
+ histograms.file_info["core_scatter_max"].to("m")
349
+ if "core_scatter_max" in histograms.file_info
350
+ else None,
351
+ "Upper radius limit is equal to the maximum core scatter distance of",
352
+ )
353
+
354
+
355
+ def compute_viewcone(histograms, loss_fraction):
356
+ """
357
+ Compute the viewcone based on the event loss fraction.
447
358
 
448
- if output_file:
449
- self._logger.info(f"Saving plot to {output_file}")
450
- plt.savefig(output_file, dpi=300, bbox_inches="tight")
451
- plt.close()
452
- else:
453
- plt.tight_layout()
454
- plt.show()
359
+ The shower IDs of triggered events are used to create a mask for the
360
+ azimuth and altitude of the triggered events. A mapping is created
361
+ between the triggered events and the simulated events using the shower IDs.
455
362
 
456
- return fig
363
+ Parameters
364
+ ----------
365
+ histograms : SimtelIOEventHistograms
366
+ Histograms.
367
+ loss_fraction : float
368
+ Fraction of events to be lost.
369
+
370
+ Returns
371
+ -------
372
+ astropy.units.Quantity
373
+ Viewcone radius in degrees.
374
+ """
375
+ viewcone_limit = (
376
+ _compute_limits(
377
+ histograms.histograms.get("angular_distance"),
378
+ histograms.view_cone_bins,
379
+ loss_fraction,
380
+ limit_type="upper",
381
+ )
382
+ * u.deg
383
+ )
384
+ return _is_close(
385
+ viewcone_limit,
386
+ histograms.file_info["viewcone_max"].to("deg")
387
+ if "viewcone_max" in histograms.file_info
388
+ else None,
389
+ "Upper viewcone limit is equal to the maximum viewcone distance of",
390
+ )