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
@@ -1,456 +1,365 @@
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.layout.array_layout_utils import get_array_elements_from_db_for_layouts
13
+ from simtools.simtel.simtel_io_event_histograms import SimtelIOEventHistograms
14
+ from simtools.visualization import plot_simtel_event_histograms
11
15
 
16
+ _logger = logging.getLogger(__name__)
12
17
 
13
- class LimitCalculator:
18
+
19
+ def generate_corsika_limits_grid(args_dict, db_config=None):
20
+ """
21
+ Generate CORSIKA limits.
22
+
23
+ Parameters
24
+ ----------
25
+ args_dict : dict
26
+ Dictionary containing command line arguments.
27
+ db_config : dict, optional
28
+ Database configuration dictionary.
29
+ """
30
+ if args_dict.get("array_layout_name"):
31
+ telescope_configs = get_array_elements_from_db_for_layouts(
32
+ args_dict["array_layout_name"],
33
+ args_dict.get("site"),
34
+ args_dict.get("model_version"),
35
+ db_config,
36
+ )
37
+ else:
38
+ telescope_configs = ascii_handler.collect_data_from_file(args_dict["telescope_ids"])[
39
+ "telescope_configs"
40
+ ]
41
+
42
+ results = []
43
+ for array_name, telescope_ids in telescope_configs.items():
44
+ _logger.info(
45
+ f"Processing file: {args_dict['event_data_file']} with telescope config: {array_name}"
46
+ )
47
+ result = _process_file(
48
+ args_dict["event_data_file"],
49
+ array_name,
50
+ telescope_ids,
51
+ args_dict["loss_fraction"],
52
+ args_dict["plot_histograms"],
53
+ )
54
+ result["layout"] = array_name
55
+ results.append(result)
56
+
57
+ write_results(results, args_dict)
58
+
59
+
60
+ def _process_file(file_path, array_name, telescope_ids, loss_fraction, plot_histograms):
61
+ """
62
+ Compute limits for a given event data file and telescope configuration.
63
+
64
+ Compute limits for energy, radial distance, and viewcone.
65
+
66
+ Parameters
67
+ ----------
68
+ file_path : str
69
+ Path to the event data file.
70
+ array_name : str
71
+ Name of the telescope array configuration.
72
+ telescope_ids : list[int]
73
+ List of telescope IDs to filter the events.
74
+ loss_fraction : float
75
+ Fraction of events to be lost.
76
+ plot_histograms : bool
77
+ Whether to plot histograms.
78
+
79
+ Returns
80
+ -------
81
+ dict
82
+ Dictionary containing the computed limits and metadata.
14
83
  """
15
- Compute limits for CORSIKA configuration for energy, radial distance, and viewcone.
84
+ histograms = SimtelIOEventHistograms(
85
+ file_path, array_name=array_name, telescope_list=telescope_ids
86
+ )
87
+ histograms.fill()
88
+
89
+ limits = {
90
+ "lower_energy_limit": compute_lower_energy_limit(histograms, loss_fraction),
91
+ "upper_radius_limit": compute_upper_radius_limit(histograms, loss_fraction),
92
+ "viewcone_radius": compute_viewcone(histograms, loss_fraction),
93
+ }
94
+
95
+ if plot_histograms:
96
+ plot_simtel_event_histograms.plot(
97
+ histograms.histograms,
98
+ output_path=io_handler.IOHandler().get_output_directory(),
99
+ limits=limits,
100
+ array_name=array_name,
101
+ )
102
+
103
+ return limits
104
+
16
105
 
17
- Event data is read from the reduced MC event data file.
106
+ def write_results(results, args_dict):
107
+ """
108
+ Write the computed limits as astropy table to file.
18
109
 
19
110
  Parameters
20
111
  ----------
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).
112
+ results : list[dict]
113
+ List of computed limits.
114
+ args_dict : dict
115
+ Dictionary containing command line arguments.
116
+ """
117
+ table = _create_results_table(results, args_dict["loss_fraction"])
118
+
119
+ output_dir = io_handler.IOHandler().get_output_directory("corsika_limits")
120
+ output_file = output_dir / args_dict["output_file"]
121
+
122
+ table.write(output_file, format="ascii.ecsv", overwrite=True)
123
+ _logger.info(f"Results saved to {output_file}")
124
+
125
+ MetadataCollector.dump(args_dict, output_file)
126
+
127
+
128
+ def _create_results_table(results, loss_fraction):
27
129
  """
130
+ Convert list of simulation results to an astropy Table with metadata.
131
+
132
+ Round values to appropriate precision and add metadata.
28
133
 
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,
134
+ Parameters
135
+ ----------
136
+ results : list[dict]
137
+ Computed limits per file and telescope configuration.
138
+ loss_fraction : float
139
+ Fraction of lost events (added to metadata).
140
+
141
+ Returns
142
+ -------
143
+ astropy.table.Table
144
+ Table with computed limits.
145
+ """
146
+ cols = [
147
+ "primary_particle",
148
+ "array_name",
149
+ "telescope_ids",
150
+ "zenith",
151
+ "azimuth",
152
+ "nsb_level",
153
+ "lower_energy_limit",
154
+ "upper_radius_limit",
155
+ "viewcone_radius",
156
+ ]
157
+
158
+ columns = {name: [] for name in cols}
159
+ units = {}
160
+
161
+ for res in results:
162
+ _process_result_row(res, cols, columns, units)
163
+
164
+ table_cols = _create_table_columns(cols, columns, units)
165
+ table = Table(table_cols)
166
+
167
+ table.meta.update(
168
+ {
169
+ "created": datetime.datetime.now().isoformat(),
170
+ "description": "Lookup table for CORSIKA limits computed from simulations.",
171
+ "loss_fraction": loss_fraction,
69
172
  }
173
+ )
174
+
175
+ return table
70
176
 
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
177
+
178
+ def _process_result_row(res, cols, columns, units):
179
+ """Process a single result row and add values to columns."""
180
+ for k in cols:
181
+ val = res.get(k, None)
182
+ if val is not None:
183
+ val = _round_value(k, val)
184
+ _logger.debug(f"Adding {k}: {val} to column data")
185
+
186
+ if hasattr(val, "unit"):
187
+ columns[k].append(val.value)
188
+ units[k] = val.unit
110
189
  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
- )
190
+ columns[k].append(val)
191
+ if k not in units:
192
+ units[k] = None
193
+
194
+
195
+ def _round_value(key, val):
196
+ """Round value based on key type."""
197
+ if key == "lower_energy_limit":
198
+ return np.floor(val * 1e3) / 1e3
199
+ if key == "upper_radius_limit":
200
+ return np.ceil(val / 25) * 25
201
+ if key == "viewcone_radius":
202
+ return np.ceil(val / 0.25) * 0.25
203
+ return val
204
+
205
+
206
+ def _create_table_columns(cols, columns, units):
207
+ """Create table columns with appropriate data types."""
208
+ table_cols = []
209
+ for k in cols:
210
+ col_data = columns[k]
211
+ if any(isinstance(v, list | tuple) for v in col_data):
212
+ col = Column(data=col_data, name=k, unit=units.get(k), dtype=object)
213
+ else:
214
+ col = Column(data=col_data, name=k, unit=units.get(k))
215
+ table_cols.append(col)
216
+ return table_cols
205
217
 
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
218
 
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
- )
219
+ def _compute_limits(hist, bin_edges, loss_fraction, limit_type="lower"):
220
+ """
221
+ Compute the limits based on the loss fraction.
235
222
 
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
- )
223
+ Add or subtract one bin to be on the safe side of the limit.
259
224
 
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
- )
225
+ Parameters
226
+ ----------
227
+ hist : np.ndarray
228
+ 1D histogram array.
229
+ bin_edges : np.ndarray
230
+ Array of bin edges.
231
+ loss_fraction : float
232
+ Fraction of events to be lost.
233
+ limit_type : str, optional
234
+ Type of limit ('lower' or 'upper'). Default is 'lower'.
235
+
236
+ Returns
237
+ -------
238
+ float
239
+ Bin edge value corresponding to the threshold.
240
+ """
241
+ total_events = np.sum(hist)
242
+ threshold = (1 - loss_fraction) * total_events
243
+ if limit_type == "upper":
244
+ cum = np.cumsum(hist)
245
+ idx = np.searchsorted(cum, threshold) + 1
246
+ return bin_edges[min(idx, len(bin_edges) - 1)]
247
+ if limit_type == "lower":
248
+ cum = np.cumsum(hist[::-1])
249
+ idx = np.searchsorted(cum, threshold) + 1
250
+ return bin_edges[max(len(bin_edges) - 1 - idx, 0)]
251
+ raise ValueError("limit_type must be 'lower' or 'upper'")
252
+
253
+
254
+ def compute_lower_energy_limit(histograms, loss_fraction):
255
+ """
256
+ Compute the lower energy limit in TeV based on the event loss fraction.
268
257
 
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
258
+ Parameters
259
+ ----------
260
+ histograms : SimtelIOEventHistograms
261
+ Histograms.
262
+ loss_fraction : float
263
+ Fraction of events to be lost.
264
+
265
+ Returns
266
+ -------
267
+ astropy.units.Quantity
268
+ Lower energy limit.
269
+ """
270
+ energy_min = (
271
+ _compute_limits(
272
+ histograms.histograms["energy"]["histogram"],
273
+ histograms.energy_bins,
274
+ loss_fraction,
275
+ limit_type="lower",
295
276
  )
277
+ * u.TeV
278
+ )
279
+
280
+ return _is_close(
281
+ energy_min,
282
+ histograms.file_info["energy_min"].to("TeV")
283
+ if "energy_min" in histograms.file_info
284
+ else None,
285
+ "Lower energy limit is equal to the minimum energy of",
286
+ )
287
+
288
+
289
+ def _is_close(value, reference, warning_text):
290
+ """Check if the value is close to the reference value and log a warning if so."""
291
+ if reference is not None and np.isclose(value.value, reference.value, rtol=1.0e-2):
292
+ _logger.warning(f"{warning_text} {value}.")
293
+ return value
296
294
 
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
- }
390
295
 
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"),
296
+ def compute_upper_radius_limit(histograms, loss_fraction):
297
+ """
298
+ Compute the upper radial distance based on the event loss fraction.
299
+
300
+ Parameters
301
+ ----------
302
+ histograms : SimtelIOEventHistograms
303
+ Histograms.
304
+ loss_fraction : float
305
+ Fraction of events to be lost.
306
+
307
+ Returns
308
+ -------
309
+ astropy.units.Quantity
310
+ Upper radial distance in m.
311
+ """
312
+ radius_limit = (
313
+ _compute_limits(
314
+ histograms.histograms["core_distance"]["histogram"],
315
+ histograms.core_distance_bins,
316
+ loss_fraction,
317
+ limit_type="upper",
446
318
  )
319
+ * u.m
320
+ )
321
+ return _is_close(
322
+ radius_limit,
323
+ histograms.file_info["core_scatter_max"].to("m")
324
+ if "core_scatter_max" in histograms.file_info
325
+ else None,
326
+ "Upper radius limit is equal to the maximum core scatter distance of",
327
+ )
328
+
329
+
330
+ def compute_viewcone(histograms, loss_fraction):
331
+ """
332
+ Compute the viewcone based on the event loss fraction.
447
333
 
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()
334
+ The shower IDs of triggered events are used to create a mask for the
335
+ azimuth and altitude of the triggered events. A mapping is created
336
+ between the triggered events and the simulated events using the shower IDs.
455
337
 
456
- return fig
338
+ Parameters
339
+ ----------
340
+ histograms : SimtelIOEventHistograms
341
+ Histograms.
342
+ loss_fraction : float
343
+ Fraction of events to be lost.
344
+
345
+ Returns
346
+ -------
347
+ astropy.units.Quantity
348
+ Viewcone radius in degrees.
349
+ """
350
+ viewcone_limit = (
351
+ _compute_limits(
352
+ histograms.histograms["angular_distance"]["histogram"],
353
+ histograms.view_cone_bins,
354
+ loss_fraction,
355
+ limit_type="upper",
356
+ )
357
+ * u.deg
358
+ )
359
+ return _is_close(
360
+ viewcone_limit,
361
+ histograms.file_info["viewcone_max"].to("deg")
362
+ if "viewcone_max" in histograms.file_info
363
+ else None,
364
+ "Upper viewcone limit is equal to the maximum viewcone distance of",
365
+ )