gammasimtools 0.6.1__py3-none-any.whl → 0.8.1__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 (353) hide show
  1. gammasimtools-0.8.1.dist-info/METADATA +172 -0
  2. gammasimtools-0.8.1.dist-info/RECORD +346 -0
  3. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.1.dist-info}/WHEEL +1 -1
  4. gammasimtools-0.8.1.dist-info/entry_points.txt +31 -0
  5. simtools/_version.py +2 -2
  6. simtools/applications/calculate_trigger_rate.py +210 -0
  7. simtools/applications/convert_all_model_parameters_from_simtel.py +372 -0
  8. simtools/applications/{print_array_elements.py → convert_geo_coordinates_of_array_elements.py} +58 -63
  9. simtools/applications/convert_model_parameter_from_simtel.py +119 -0
  10. simtools/applications/{add_file_to_db.py → db_add_file_to_db.py} +70 -60
  11. simtools/applications/db_add_model_parameters_from_repository_to_db.py +184 -0
  12. simtools/applications/db_add_value_from_json_to_db.py +105 -0
  13. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +180 -0
  14. simtools/applications/db_get_array_layouts_from_db.py +162 -0
  15. simtools/applications/{get_file_from_db.py → db_get_file_from_db.py} +30 -34
  16. simtools/applications/db_get_parameter_from_db.py +131 -0
  17. simtools/applications/db_inspect_databases.py +52 -0
  18. simtools/applications/derive_mirror_rnda.py +39 -255
  19. simtools/applications/derive_psf_parameters.py +441 -0
  20. simtools/applications/generate_array_config.py +82 -0
  21. simtools/applications/generate_corsika_histograms.py +52 -52
  22. simtools/applications/generate_default_metadata.py +5 -8
  23. simtools/applications/generate_regular_arrays.py +117 -0
  24. simtools/applications/generate_simtel_array_histograms.py +97 -56
  25. simtools/applications/plot_array_layout.py +345 -115
  26. simtools/applications/production_generate_simulation_config.py +158 -0
  27. simtools/applications/production_scale_events.py +168 -0
  28. simtools/applications/simulate_light_emission.py +478 -0
  29. simtools/applications/simulate_prod.py +97 -175
  30. simtools/applications/submit_data_from_external.py +9 -12
  31. simtools/applications/submit_model_parameter_from_external.py +122 -0
  32. simtools/applications/validate_camera_efficiency.py +35 -102
  33. simtools/applications/validate_camera_fov.py +20 -19
  34. simtools/applications/{compare_cumulative_psf.py → validate_cumulative_psf.py} +45 -44
  35. simtools/applications/validate_file_using_schema.py +113 -47
  36. simtools/applications/validate_optics.py +17 -22
  37. simtools/camera_efficiency.py +193 -202
  38. simtools/configuration/commandline_parser.py +384 -96
  39. simtools/configuration/configurator.py +55 -71
  40. simtools/constants.py +5 -5
  41. simtools/corsika/corsika_config.py +482 -342
  42. simtools/corsika/corsika_histograms.py +226 -204
  43. simtools/corsika/corsika_histograms_visualize.py +23 -24
  44. simtools/corsika/primary_particle.py +159 -0
  45. simtools/data_model/data_reader.py +25 -20
  46. simtools/data_model/format_checkers.py +52 -0
  47. simtools/data_model/metadata_collector.py +210 -184
  48. simtools/data_model/metadata_model.py +115 -37
  49. simtools/data_model/model_data_writer.py +335 -26
  50. simtools/data_model/validate_data.py +366 -154
  51. simtools/db/db_array_elements.py +130 -0
  52. simtools/db/db_from_repo_handler.py +106 -0
  53. simtools/db/db_handler.py +1246 -0
  54. simtools/io_operations/hdf5_handler.py +3 -1
  55. simtools/io_operations/io_handler.py +32 -57
  56. simtools/job_execution/job_manager.py +82 -69
  57. simtools/layout/array_layout.py +325 -537
  58. simtools/layout/geo_coordinates.py +8 -11
  59. simtools/layout/telescope_position.py +163 -86
  60. simtools/model/array_model.py +305 -256
  61. simtools/model/calibration_model.py +50 -0
  62. simtools/model/camera.py +233 -493
  63. simtools/model/mirrors.py +61 -44
  64. simtools/model/model_parameter.py +602 -0
  65. simtools/model/model_utils.py +7 -35
  66. simtools/model/site_model.py +161 -0
  67. simtools/model/telescope_model.py +127 -621
  68. simtools/production_configuration/calculate_statistical_errors_grid_point.py +454 -0
  69. simtools/production_configuration/event_scaler.py +146 -0
  70. simtools/production_configuration/generate_simulation_config.py +193 -0
  71. simtools/production_configuration/interpolation_handler.py +197 -0
  72. simtools/ray_tracing/__init__.py +0 -0
  73. simtools/ray_tracing/mirror_panel_psf.py +280 -0
  74. simtools/{psf_analysis.py → ray_tracing/psf_analysis.py} +133 -47
  75. simtools/ray_tracing/ray_tracing.py +646 -0
  76. simtools/runners/__init__.py +0 -0
  77. simtools/runners/corsika_runner.py +240 -0
  78. simtools/runners/corsika_simtel_runner.py +225 -0
  79. simtools/runners/runner_services.py +307 -0
  80. simtools/runners/simtel_runner.py +224 -0
  81. simtools/schemas/array_elements.yml +137 -0
  82. simtools/schemas/integration_tests_config.metaschema.yml +93 -0
  83. simtools/schemas/metadata.metaschema.yml +6 -0
  84. simtools/schemas/model_parameter.metaschema.yml +78 -0
  85. simtools/schemas/{data.metaschema.yml → model_parameter_and_data_schema.metaschema.yml} +27 -44
  86. simtools/schemas/model_parameters/adjust_gain.schema.yml +37 -0
  87. simtools/schemas/model_parameters/altitude.schema.yml +37 -0
  88. simtools/schemas/model_parameters/array_coordinates.schema.yml +33 -0
  89. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +77 -0
  90. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +39 -0
  91. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +39 -0
  92. simtools/schemas/model_parameters/array_layouts.schema.yml +48 -0
  93. simtools/schemas/model_parameters/array_triggers.schema.yml +93 -0
  94. simtools/schemas/model_parameters/asum_clipping.schema.yml +38 -0
  95. simtools/schemas/model_parameters/asum_offset.schema.yml +35 -0
  96. simtools/schemas/model_parameters/asum_shaping.schema.yml +35 -0
  97. simtools/schemas/model_parameters/asum_threshold.schema.yml +38 -0
  98. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +32 -0
  99. simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +35 -0
  100. simtools/schemas/model_parameters/axes_offsets.schema.yml +53 -0
  101. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +40 -0
  102. simtools/schemas/model_parameters/camera_body_shape.schema.yml +45 -0
  103. simtools/schemas/model_parameters/camera_config_file.schema.yml +40 -0
  104. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +36 -0
  105. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +43 -0
  106. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +42 -0
  107. simtools/schemas/model_parameters/camera_depth.schema.yml +42 -0
  108. simtools/schemas/model_parameters/camera_filter.schema.yml +45 -0
  109. simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +29 -0
  110. simtools/schemas/model_parameters/camera_pixels.schema.yml +36 -0
  111. simtools/schemas/model_parameters/camera_transmission.schema.yml +41 -0
  112. simtools/schemas/model_parameters/channels_per_chip.schema.yml +36 -0
  113. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +35 -0
  114. simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +27 -0
  115. simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +38 -0
  116. simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +28 -0
  117. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +23 -0
  118. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +27 -0
  119. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +28 -0
  120. simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +27 -0
  121. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +38 -0
  122. simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +52 -0
  123. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +27 -0
  124. simtools/schemas/model_parameters/dark_events.schema.yml +32 -0
  125. simtools/schemas/model_parameters/default_trigger.schema.yml +35 -0
  126. simtools/schemas/model_parameters/design_model.schema.yml +31 -0
  127. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +32 -0
  128. simtools/schemas/model_parameters/disc_bins.schema.yml +39 -0
  129. simtools/schemas/model_parameters/disc_start.schema.yml +41 -0
  130. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +42 -0
  131. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +41 -0
  132. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +41 -0
  133. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +39 -0
  134. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +40 -0
  135. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +41 -0
  136. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +33 -0
  137. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +42 -0
  138. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +37 -0
  139. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +44 -0
  140. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +36 -0
  141. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +45 -0
  142. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +40 -0
  143. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +41 -0
  144. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +38 -0
  145. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +38 -0
  146. simtools/schemas/model_parameters/dish_shape_length.schema.yml +41 -0
  147. simtools/schemas/model_parameters/dsum_clipping.schema.yml +38 -0
  148. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +38 -0
  149. simtools/schemas/model_parameters/dsum_offset.schema.yml +37 -0
  150. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +33 -0
  151. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +39 -0
  152. simtools/schemas/model_parameters/dsum_prescale.schema.yml +44 -0
  153. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +38 -0
  154. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +45 -0
  155. simtools/schemas/model_parameters/dsum_shaping.schema.yml +44 -0
  156. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +32 -0
  157. simtools/schemas/model_parameters/dsum_threshold.schema.yml +43 -0
  158. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +42 -0
  159. simtools/schemas/model_parameters/effective_focal_length.schema.yml +61 -0
  160. simtools/schemas/model_parameters/epsg_code.schema.yml +37 -0
  161. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +35 -0
  162. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +46 -0
  163. simtools/schemas/model_parameters/fadc_bins.schema.yml +40 -0
  164. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +50 -0
  165. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +38 -0
  166. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +42 -0
  167. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +49 -0
  168. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +47 -0
  169. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +51 -0
  170. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +37 -0
  171. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +43 -0
  172. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +49 -0
  173. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +43 -0
  174. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +39 -0
  175. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +42 -0
  176. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +40 -0
  177. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +50 -0
  178. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +42 -0
  179. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +41 -0
  180. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +42 -0
  181. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +43 -0
  182. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +39 -0
  183. simtools/schemas/model_parameters/fadc_mhz.schema.yml +31 -0
  184. simtools/schemas/model_parameters/fadc_noise.schema.yml +41 -0
  185. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +40 -0
  186. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +39 -0
  187. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +50 -0
  188. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +43 -0
  189. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +43 -0
  190. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +42 -0
  191. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +41 -0
  192. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +42 -0
  193. simtools/schemas/model_parameters/flatfielding.schema.yml +37 -0
  194. simtools/schemas/model_parameters/focal_length.schema.yml +45 -0
  195. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +158 -0
  196. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +29 -0
  197. simtools/schemas/model_parameters/focus_offset.schema.yml +66 -0
  198. simtools/schemas/model_parameters/gain_variation.schema.yml +43 -0
  199. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +34 -0
  200. simtools/schemas/model_parameters/geomag_rotation.schema.yml +37 -0
  201. simtools/schemas/model_parameters/geomag_vertical.schema.yml +34 -0
  202. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +36 -0
  203. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +34 -0
  204. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +34 -0
  205. simtools/schemas/model_parameters/laser_events.schema.yml +36 -0
  206. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +35 -0
  207. simtools/schemas/model_parameters/laser_photons.schema.yml +32 -0
  208. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +34 -0
  209. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +34 -0
  210. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +33 -0
  211. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +33 -0
  212. simtools/schemas/model_parameters/laser_var_photons.schema.yml +33 -0
  213. simtools/schemas/model_parameters/laser_wavelength.schema.yml +33 -0
  214. simtools/schemas/model_parameters/led_events.schema.yml +34 -0
  215. simtools/schemas/model_parameters/led_photons.schema.yml +34 -0
  216. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +32 -0
  217. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +33 -0
  218. simtools/schemas/model_parameters/led_var_photons.schema.yml +34 -0
  219. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +41 -0
  220. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +43 -0
  221. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +35 -0
  222. simtools/schemas/model_parameters/min_photons.schema.yml +32 -0
  223. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +36 -0
  224. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +64 -0
  225. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +64 -0
  226. simtools/schemas/model_parameters/mirror_class.schema.yml +41 -0
  227. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +51 -0
  228. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +42 -0
  229. simtools/schemas/model_parameters/mirror_list.schema.yml +38 -0
  230. simtools/schemas/model_parameters/mirror_offset.schema.yml +41 -0
  231. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +39 -0
  232. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +61 -0
  233. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +40 -0
  234. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +46 -0
  235. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +51 -0
  236. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +37 -0
  237. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +79 -0
  238. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +47 -0
  239. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +34 -0
  240. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +33 -0
  241. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +35 -0
  242. simtools/schemas/model_parameters/nsb_skymap.schema.yml +39 -0
  243. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +50 -0
  244. simtools/schemas/model_parameters/num_gains.schema.yml +34 -0
  245. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +33 -0
  246. simtools/schemas/model_parameters/optics_properties.schema.yml +31 -0
  247. simtools/schemas/model_parameters/parabolic_dish.schema.yml +32 -0
  248. simtools/schemas/model_parameters/pedestal_events.schema.yml +32 -0
  249. simtools/schemas/model_parameters/photon_delay.schema.yml +38 -0
  250. simtools/schemas/model_parameters/photons_per_run.schema.yml +33 -0
  251. simtools/schemas/model_parameters/pixel_cells.schema.yml +35 -0
  252. simtools/schemas/model_parameters/pixels_parallel.schema.yml +54 -0
  253. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +40 -0
  254. simtools/schemas/model_parameters/pm_average_gain.schema.yml +34 -0
  255. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +40 -0
  256. simtools/schemas/model_parameters/pm_gain_index.schema.yml +36 -0
  257. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +41 -0
  258. simtools/schemas/model_parameters/pm_transit_time.schema.yml +63 -0
  259. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +39 -0
  260. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +42 -0
  261. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +33 -0
  262. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +33 -0
  263. simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +29 -0
  264. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +168 -0
  265. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +36 -0
  266. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +34 -0
  267. simtools/schemas/model_parameters/qe_variation.schema.yml +43 -0
  268. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +42 -0
  269. simtools/schemas/model_parameters/random_focal_length.schema.yml +45 -0
  270. simtools/schemas/model_parameters/random_generator.schema.yml +36 -0
  271. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +35 -0
  272. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +36 -0
  273. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +36 -0
  274. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +34 -0
  275. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +34 -0
  276. simtools/schemas/model_parameters/sampled_output.schema.yml +31 -0
  277. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +34 -0
  278. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +79 -0
  279. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +42 -0
  280. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +41 -0
  281. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +33 -0
  282. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +36 -0
  283. simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +29 -0
  284. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +168 -0
  285. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +36 -0
  286. simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +35 -0
  287. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +37 -0
  288. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +40 -0
  289. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +40 -0
  290. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +41 -0
  291. simtools/schemas/model_parameters/tailcut_scale.schema.yml +40 -0
  292. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +31 -0
  293. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +35 -0
  294. simtools/schemas/model_parameters/telescope_random_error.schema.yml +34 -0
  295. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +37 -0
  296. simtools/schemas/model_parameters/telescope_transmission.schema.yml +113 -0
  297. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +41 -0
  298. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +36 -0
  299. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +36 -0
  300. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +37 -0
  301. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +38 -0
  302. simtools/schemas/model_parameters/transit_time_error.schema.yml +45 -0
  303. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +36 -0
  304. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +32 -0
  305. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +53 -0
  306. simtools/schemas/model_parameters/trigger_pixels.schema.yml +40 -0
  307. simtools/simtel/simtel_config_reader.py +353 -0
  308. simtools/simtel/simtel_config_writer.py +244 -63
  309. simtools/simtel/{simtel_events.py → simtel_io_events.py} +26 -25
  310. simtools/simtel/simtel_io_histogram.py +661 -0
  311. simtools/simtel/simtel_io_histograms.py +569 -0
  312. simtools/simtel/simulator_array.py +145 -0
  313. simtools/simtel/{simtel_runner_camera_efficiency.py → simulator_camera_efficiency.py} +76 -52
  314. simtools/simtel/simulator_light_emission.py +473 -0
  315. simtools/simtel/simulator_ray_tracing.py +262 -0
  316. simtools/simulator.py +220 -446
  317. simtools/testing/__init__.py +0 -0
  318. simtools/testing/assertions.py +151 -0
  319. simtools/testing/configuration.py +226 -0
  320. simtools/testing/helpers.py +42 -0
  321. simtools/testing/validate_output.py +240 -0
  322. simtools/utils/general.py +340 -437
  323. simtools/utils/geometry.py +12 -12
  324. simtools/utils/names.py +258 -644
  325. simtools/utils/value_conversion.py +176 -0
  326. simtools/version.py +2 -0
  327. simtools/visualization/legend_handlers.py +135 -152
  328. simtools/visualization/plot_camera.py +379 -0
  329. simtools/visualization/visualize.py +346 -167
  330. gammasimtools-0.6.1.dist-info/METADATA +0 -180
  331. gammasimtools-0.6.1.dist-info/RECORD +0 -91
  332. gammasimtools-0.6.1.dist-info/entry_points.txt +0 -23
  333. simtools/applications/db_development_tools/add_new_parameter_to_db.py +0 -81
  334. simtools/applications/db_development_tools/add_unit_to_parameter_in_db.py +0 -59
  335. simtools/applications/db_development_tools/mark_non_optics_parameters_non_applicable.py +0 -102
  336. simtools/applications/get_parameter.py +0 -92
  337. simtools/applications/make_regular_arrays.py +0 -160
  338. simtools/applications/produce_array_config.py +0 -136
  339. simtools/applications/production.py +0 -313
  340. simtools/applications/sim_showers_for_trigger_rates.py +0 -187
  341. simtools/applications/tune_psf.py +0 -334
  342. simtools/corsika/corsika_default_config.py +0 -282
  343. simtools/corsika/corsika_runner.py +0 -450
  344. simtools/corsika_simtel/corsika_simtel_runner.py +0 -197
  345. simtools/db_handler.py +0 -1480
  346. simtools/ray_tracing.py +0 -525
  347. simtools/simtel/simtel_histograms.py +0 -414
  348. simtools/simtel/simtel_runner.py +0 -244
  349. simtools/simtel/simtel_runner_array.py +0 -293
  350. simtools/simtel/simtel_runner_ray_tracing.py +0 -277
  351. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.1.dist-info}/LICENSE +0 -0
  352. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.1.dist-info}/top_level.txt +0 -0
  353. /simtools/{corsika_simtel → db}/__init__.py +0 -0
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/python3
2
+ """Module for visualization."""
2
3
 
4
+ import copy
3
5
  import logging
4
6
  import re
5
7
  from collections import OrderedDict
@@ -7,14 +9,13 @@ from collections import OrderedDict
7
9
  import astropy.units as u
8
10
  import matplotlib.patches as mpatches
9
11
  import matplotlib.pyplot as plt
10
- from astropy.table import QTable
12
+ from astropy.table import Column, QTable
11
13
  from cycler import cycler
12
14
  from matplotlib import gridspec
13
15
  from matplotlib.collections import PatchCollection
14
16
 
15
17
  from simtools.utils import geometry as transf
16
18
  from simtools.utils import names
17
- from simtools.utils.names import mst, sct
18
19
  from simtools.visualization import legend_handlers as leg_h
19
20
 
20
21
  __all__ = [
@@ -124,11 +125,12 @@ _logger = logging.getLogger(__name__)
124
125
 
125
126
  def _add_unit(title, array):
126
127
  """
127
- A function to add a unit to "title" (presumably an axis title). The unit is extracted from the\
128
- unit field of the array, in case array is an astropy quantity. If a unit is found, it is added \
129
- to title in the form [unit]. If a unit already is present in title (in the same form), a \
130
- warning is printed and no unit is added. The function assumes array not to be empty and returns\
131
- the modified title.
128
+ Add a unit to "title" (presumably an axis title).
129
+
130
+ The unit is extracted from the unit field of the array, in case array is an astropy quantity.
131
+ If a unit is found, it is added to title in the form [unit]. If a unit already is present in
132
+ title (in the same form), a warning is printed and no unit is added. The function assumes
133
+ array not to be empty and returns the modified title.
132
134
 
133
135
  Parameters
134
136
  ----------
@@ -140,7 +142,6 @@ def _add_unit(title, array):
140
142
  str
141
143
  Title with units.
142
144
  """
143
-
144
145
  unit = ""
145
146
  if isinstance(array, u.Quantity):
146
147
  unit = str(array[0].unit)
@@ -161,13 +162,14 @@ def _add_unit(title, array):
161
162
 
162
163
  def set_style(palette="default", big_plot=False):
163
164
  """
164
- A function to set the plotting style as part of an effort to homogenize plot style across the \
165
- framework. The function receives the colour palette name and whether it is a big plot or not.\
165
+ Set the plotting style to homogenize plot style across the framework.
166
+
167
+ The function receives the colour palette name and whether it is a big plot or not.\
166
168
  The latter sets the fonts and marker to be bigger in case it is a big plot. The available \
167
169
  colour palettes are as follows:
168
170
 
169
- - classic (default): A classic colourful palette with strong colours and contrast.
170
- - modified classic: Similar to the classic, with slightly different colours.
171
+ - classic (default): A classic colorful palette with strong colors and contrast.
172
+ - modified classic: Similar to the classic, with slightly different colors.
171
173
  - autumn: A slightly darker autumn style colour palette.
172
174
  - purples: A pseudo sequential purple colour palette (not great for contrast).
173
175
  - greens: A pseudo sequential green colour palette (not great for contrast).
@@ -188,15 +190,12 @@ def set_style(palette="default", big_plot=False):
188
190
  KeyError
189
191
  if provided palette does not exist.
190
192
  """
191
-
192
193
  if palette not in COLORS:
193
194
  raise KeyError(f"palette must be one of {', '.join(COLORS)}")
194
195
 
195
196
  fontsize = {"default": 17, "big_plot": 30}
196
197
  markersize = {"default": 8, "big_plot": 18}
197
- plot_size = "default"
198
- if big_plot:
199
- plot_size = "big_plot"
198
+ plot_size = "big_plot" if big_plot else "default"
200
199
 
201
200
  plt.rc("lines", linewidth=2, markersize=markersize[plot_size])
202
201
  plt.rc(
@@ -204,9 +203,6 @@ def set_style(palette="default", big_plot=False):
204
203
  prop_cycle=(
205
204
  cycler(color=COLORS[palette]) + cycler(linestyle=LINES) + cycler(marker=MARKERS)
206
205
  ),
207
- )
208
- plt.rc(
209
- "axes",
210
206
  titlesize=fontsize[plot_size],
211
207
  labelsize=fontsize[plot_size],
212
208
  labelpad=5,
@@ -221,8 +217,9 @@ def set_style(palette="default", big_plot=False):
221
217
 
222
218
  def get_colors(palette="default"):
223
219
  """
224
- Get the colour list of the palette requested. If no palette is provided, the default is \
225
- returned.
220
+ Get the colour list of the palette requested.
221
+
222
+ If no palette is provided, the default is returned.
226
223
 
227
224
  Parameters
228
225
  ----------
@@ -239,7 +236,6 @@ def get_colors(palette="default"):
239
236
  KeyError
240
237
  if provided palette does not exist.
241
238
  """
242
-
243
239
  if palette not in COLORS:
244
240
  raise KeyError(f"palette must be one of {', '.join(COLORS)}")
245
241
 
@@ -255,7 +251,6 @@ def get_markers():
255
251
  list
256
252
  List with markers.
257
253
  """
258
-
259
254
  return MARKERS
260
255
 
261
256
 
@@ -268,16 +263,42 @@ def get_lines():
268
263
  list
269
264
  List with line styles.
270
265
  """
271
-
272
266
  return LINES
273
267
 
274
268
 
269
+ def filter_plot_kwargs(kwargs):
270
+ """Filter out kwargs that are not valid for plt.plot."""
271
+ valid_keys = {
272
+ "color",
273
+ "linestyle",
274
+ "linewidth",
275
+ "marker",
276
+ "markersize",
277
+ "markerfacecolor",
278
+ "markeredgecolor",
279
+ "markeredgewidth",
280
+ "alpha",
281
+ "label",
282
+ "zorder",
283
+ "dashes",
284
+ "gapcolor",
285
+ "solid_capstyle",
286
+ "solid_joinstyle",
287
+ "dash_capstyle",
288
+ "dash_joinstyle",
289
+ "antialiased",
290
+ }
291
+ return {k: v for k, v in kwargs.items() if k in valid_keys}
292
+
293
+
275
294
  def plot_1d(data, **kwargs):
276
295
  """
277
- Produce a high contrast one dimensional plot from multiple data sets. A ratio plot can be \
278
- added at the bottom to allow easy comparison. Additional options, such as plot title, plot
279
- legend, etc., are given in kwargs. Any option that can be changed after plotting (e.g., axes\
280
- limits, log scale, etc.) should be done using the returned plt instance.
296
+ Produce a high contrast one dimensional plot from multiple data sets.
297
+
298
+ A ratio plot can be added at the bottom to allow easy comparison. Additional options,
299
+ such as plot title, plot legend, etc., are given in kwargs. Any option that can be
300
+ changed after plotting (e.g., axes limits, log scale, etc.) should be done using the
301
+ returned plt instance.
281
302
 
282
303
  Parameters
283
304
  ----------
@@ -291,7 +312,7 @@ def plot_1d(data, **kwargs):
291
312
  Choose a colour palette (see set_style for additional information).
292
313
  * title: string
293
314
  Set a plot title.
294
- * np_legend: bool
315
+ * no_legend: bool
295
316
  Do not print a legend for the plot.
296
317
  * big_plot: bool
297
318
  Increase marker and font sizes (like in a wide light curve).
@@ -319,122 +340,133 @@ def plot_1d(data, **kwargs):
319
340
  ValueError
320
341
  if asked to plot a ratio or difference with just one set of data
321
342
  """
343
+ kwargs = handle_kwargs(kwargs)
344
+ data_dict, plot_ratio, plot_difference = prepare_data(data, kwargs)
345
+ fig, ax1, gs = setup_plot(kwargs, plot_ratio, plot_difference)
346
+ plot_args = filter_plot_kwargs(kwargs)
347
+ plot_main_data(data_dict, kwargs, plot_args)
348
+
349
+ if plot_ratio or plot_difference:
350
+ plot_ratio_difference(ax1, data_dict, plot_ratio, gs, plot_args)
351
+
352
+ if not (plot_ratio or plot_difference):
353
+ plt.tight_layout()
354
+
355
+ return fig
356
+
357
+
358
+ def handle_kwargs(kwargs):
359
+ """Extract and handle keyword arguments."""
360
+ kwargs_defaults = {
361
+ "palette": "default",
362
+ "big_plot": False,
363
+ "title": "",
364
+ "no_legend": False,
365
+ "no_markers": False,
366
+ "empty_markers": False,
367
+ "plot_ratio": False,
368
+ "plot_difference": False,
369
+ }
370
+ for key, default in kwargs_defaults.items():
371
+ kwargs[key] = kwargs.pop(key, default)
322
372
 
323
- palette = kwargs.get("palette", "default")
324
- kwargs.pop("palette", None)
325
- big_plot = kwargs.get("big_plot", False)
326
- kwargs.pop("big_plot", None)
327
- title = kwargs.get("title", "")
328
- kwargs.pop("title", None)
329
- no_legend = kwargs.get("no_legend", False)
330
- kwargs.pop("no_legend", None)
331
- no_markers = kwargs.get("no_markers", False)
332
- kwargs.pop("no_markers", None)
333
- empty_markers = kwargs.get("empty_markers", False)
334
- kwargs.pop("empty_markers", None)
335
-
336
- if no_markers:
373
+ if kwargs["no_markers"]:
337
374
  kwargs["marker"] = "None"
338
375
  kwargs["linewidth"] = 4
339
- if empty_markers:
376
+ if kwargs["empty_markers"]:
340
377
  kwargs["markerfacecolor"] = "None"
341
- kwargs.pop("empty_markers", None)
342
378
 
343
- set_style(palette, big_plot)
379
+ return kwargs
344
380
 
381
+
382
+ def prepare_data(data, kwargs):
383
+ """Prepare data for plotting."""
345
384
  if not isinstance(data, dict):
346
- data_dict = {}
347
- data_dict["_default"] = data
385
+ data_dict = {"_default": data}
348
386
  else:
349
387
  data_dict = data
350
388
 
351
- plot_ratio = kwargs.get("plot_ratio", False)
352
- kwargs.pop("plot_ratio", None)
353
- plot_difference = kwargs.get("plot_difference", False)
354
- kwargs.pop("plot_difference", None)
355
- if plot_ratio or plot_difference:
356
- if len(data_dict) < 2:
357
- raise ValueError("Asked to plot a ratio or difference with just one set of data")
389
+ if (kwargs["plot_ratio"] or kwargs["plot_difference"]) and len(data_dict) < 2:
390
+ raise ValueError("Asked to plot a ratio or difference with just one set of data")
391
+
392
+ return data_dict, kwargs["plot_ratio"], kwargs["plot_difference"]
393
+
394
+
395
+ def setup_plot(kwargs, plot_ratio, plot_difference):
396
+ """Set up the plot style, figure, and gridspec."""
397
+ set_style(kwargs["palette"], kwargs["big_plot"])
358
398
 
359
399
  if plot_ratio or plot_difference:
360
400
  gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1])
361
401
  fig = plt.figure(figsize=(8, 8))
402
+ gs.update(hspace=0.02)
362
403
  else:
363
404
  gs = gridspec.GridSpec(1, 1)
364
405
  fig = plt.figure(figsize=(8, 6))
365
406
 
366
- ##########################################################################################
367
- # Plot the data
368
- ##########################################################################################
369
-
370
407
  plt.subplot(gs[0])
371
408
  ax1 = plt.gca()
372
409
 
410
+ return fig, ax1, gs
411
+
412
+
413
+ def plot_main_data(data_dict, kwargs, plot_args):
414
+ """Plot the main data."""
373
415
  for label, data_now in data_dict.items():
374
416
  assert len(data_now.dtype.names) == 2, "Input array must have two columns with titles."
375
417
  x_title, y_title = data_now.dtype.names[0], data_now.dtype.names[1]
376
418
  x_title_unit = _add_unit(x_title, data_now[x_title])
377
419
  y_title_unit = _add_unit(y_title, data_now[y_title])
378
- plt.plot(data_now[x_title], data_now[y_title], label=label, **kwargs)
420
+ plt.plot(data_now[x_title], data_now[y_title], label=label, **plot_args)
379
421
 
380
- if plot_ratio or plot_difference:
381
- gs.update(hspace=0.02)
382
- else:
383
- plt.xlabel(x_title_unit)
384
422
  plt.ylabel(y_title_unit)
385
-
386
- if len(title) > 0:
387
- plt.title(title, y=1.02)
388
- if "_default" not in list(data_dict.keys()) and not no_legend:
423
+ if not (kwargs["plot_ratio"] or kwargs["plot_difference"]):
424
+ plt.xlabel(x_title_unit)
425
+ if kwargs["title"]:
426
+ plt.title(kwargs["title"], y=1.02)
427
+ if "_default" not in list(data_dict.keys()) and not kwargs["no_legend"]:
389
428
  plt.legend()
390
- if not (plot_ratio or plot_difference):
391
- plt.tight_layout()
392
429
 
393
- ##########################################################################################
394
- # Plot a ratio
395
- ##########################################################################################
396
430
 
397
- if plot_ratio or plot_difference:
398
- plt.subplot(gs[1], sharex=ax1)
399
- # In order to advance the cycler one color/style,
400
- # so the colors stay consistent in the ratio, plot null data first.
401
- plt.plot([], [])
402
-
403
- # Use the first entry as the reference for the ratio.
404
- # If data_dict is not an OrderedDict, the reference will be random.
405
- data_ref_name = next(iter(data_dict))
406
- for label, data_now in data_dict.items():
407
- if label == data_ref_name:
408
- continue
409
- x_title, y_title = data_now.dtype.names[0], data_now.dtype.names[1]
410
- x_title_unit = _add_unit(x_title, data_now[x_title])
411
- if plot_ratio:
412
- y_values = data_now[y_title] / data_dict[data_ref_name][y_title]
413
- else:
414
- y_values = data_now[y_title] - data_dict[data_ref_name][y_title]
415
- plt.plot(data_now[x_title], y_values, **kwargs)
431
+ def plot_ratio_difference(ax1, data_dict, plot_ratio, gs, plot_args):
432
+ """Plot the ratio or difference plot."""
433
+ plt.subplot(gs[1], sharex=ax1)
434
+ plt.plot([], []) # Advance cycler for consistent colors/styles
416
435
 
417
- plt.xlabel(x_title_unit)
418
- y_title_ratio = f"Ratio to {data_ref_name}"
419
- if len(y_title_ratio) > 20:
420
- y_title_ratio = "Ratio"
421
- if plot_difference:
436
+ data_ref_name = next(iter(data_dict))
437
+ for label, data_now in data_dict.items():
438
+ if label == data_ref_name:
439
+ continue
440
+ x_title, y_title = data_now.dtype.names[0], data_now.dtype.names[1]
441
+ x_title_unit = _add_unit(x_title, data_now[x_title])
442
+
443
+ if plot_ratio:
444
+ y_values = data_now[y_title] / data_dict[data_ref_name][y_title]
445
+ y_title_ratio = f"Ratio to {data_ref_name}"
446
+ else:
447
+ y_values = data_now[y_title] - data_dict[data_ref_name][y_title]
422
448
  y_title_ratio = f"Difference to {data_ref_name}"
423
- plt.ylabel(y_title_ratio)
424
449
 
425
- ylim = plt.gca().get_ylim()
426
- nbins = min(int((ylim[1] - ylim[0]) / 0.05 + 1), 6)
427
- plt.locator_params(axis="y", nbins=nbins)
450
+ plt.plot(data_now[x_title], y_values, **plot_args)
428
451
 
429
- return fig
452
+ plt.xlabel(x_title_unit)
453
+
454
+ if len(y_title_ratio) > 20 and plot_ratio:
455
+ y_title_ratio = "Ratio"
456
+
457
+ plt.ylabel(y_title_ratio)
458
+ ylim = plt.gca().get_ylim()
459
+ nbins = min(int((ylim[1] - ylim[0]) / 0.05 + 1), 6)
460
+ plt.locator_params(axis="y", nbins=nbins)
430
461
 
431
462
 
432
463
  def plot_table(table, y_title, **kwargs):
433
464
  """
434
- Produce a high contrast one dimensional plot from the data in an astropy.Table. A ratio plot\
435
- can be added at the bottom to allow easy comparison. Additional options, such as plot title,
436
- plot legend, etc., are given in kwargs. Any option that can be changed after plotting (e.g.,\
437
- axes limits, log scale, etc.) should be done using the returned plt instance.
465
+ Produce a high contrast one dimensional plot from the data in an astropy.Table.
466
+
467
+ A ratio plot can be added at the bottom to allow easy comparison. Additional options, such
468
+ as plot title, plot legend, etc., are given in kwargs. Any option that can be changed after
469
+ plotting (e.g., axes limits, log scale, etc.) should be done using the returned plt instance.
438
470
 
439
471
  Parameters
440
472
  ----------
@@ -472,7 +504,6 @@ def plot_table(table, y_title, **kwargs):
472
504
  ValueError
473
505
  if table has less than two columns.
474
506
  """
475
-
476
507
  if len(table.keys()) < 2:
477
508
  raise ValueError("Table has to have at least two columns")
478
509
 
@@ -486,8 +517,10 @@ def plot_table(table, y_title, **kwargs):
486
517
 
487
518
  def plot_hist_2d(data, **kwargs):
488
519
  """
489
- Produce a two dimensional histogram plot. Any option that can be changed after plotting (e.g.,\
490
- axes limits, log scale, etc.) should be done using the returned plt instance.
520
+ Produce a two dimensional histogram plot.
521
+
522
+ Any option that can be changed after plotting (e.g., axes limits, log scale, etc.)
523
+ should be done using the returned plt instance.
491
524
 
492
525
  Parameters
493
526
  ----------
@@ -503,7 +536,6 @@ def plot_hist_2d(data, **kwargs):
503
536
  Instance of pyplot.figure in which the plot was produced.
504
537
 
505
538
  """
506
-
507
539
  cmap = plt.cm.gist_heat_r
508
540
  if "title" in kwargs:
509
541
  title = kwargs["title"]
@@ -563,22 +595,22 @@ def get_telescope_patch(name, x, y, radius):
563
595
  Instance of mpatches.Circle.
564
596
  """
565
597
  tel_obj = leg_h.TelescopeHandler()
566
- valid_name = names.get_telescope_class(name)
598
+ valid_name = names.get_array_element_type_from_name(name)
567
599
  fill_flag = False
568
600
 
569
601
  x = x.to(u.m)
570
602
  y = y.to(u.m)
571
603
  radius = radius.to(u.m)
572
604
 
573
- if valid_name == mst:
605
+ if valid_name.startswith("MST"):
574
606
  fill_flag = True
575
- if valid_name == sct:
607
+ if valid_name == "SCTS":
576
608
  patch = mpatches.Rectangle(
577
609
  ((x - radius / 2).value, (y - radius / 2).value),
578
610
  width=radius.value,
579
611
  height=radius.value,
580
612
  fill=False,
581
- color=tel_obj.colors_dict[sct],
613
+ color=tel_obj.colors_dict["SCTS"],
582
614
  )
583
615
  else:
584
616
  patch = mpatches.Circle(
@@ -591,10 +623,13 @@ def get_telescope_patch(name, x, y, radius):
591
623
 
592
624
 
593
625
  @u.quantity_input(rotate_angle=u.deg)
594
- def plot_array(telescopes, rotate_angle=0, show_tel_label=False):
626
+ def plot_array(
627
+ telescopes, rotate_angle=0, show_tel_label=False, axes_range=None, marker_scaling=1.0
628
+ ):
595
629
  """
596
- Plot the array of telescopes. The x axis gives the easting direction and y axis gives the
597
- northing direction.
630
+ Plot the array of telescopes.
631
+
632
+ The x axis gives the easting direction and y axis gives the northing direction.
598
633
  Note that in order to convert from the CORSIKA coordinate system to the 'conventional' system
599
634
  of North/East, a 90 degree rotation is always applied.
600
635
  Rotation of the array elements is possible through the 'rotate_angle' given either in degrees,
@@ -604,91 +639,126 @@ def plot_array(telescopes, rotate_angle=0, show_tel_label=False):
604
639
 
605
640
  Parameters
606
641
  ----------
607
- telescopes: dict
608
- Dictionary with the telescope position and names. Coordinates are given in the CORSIKA
609
- coordinate system, i.e., the x positive axis points toward north
610
- and the y positive axis points toward west.
642
+ telescopes: astropy.table
643
+ Table with the telescope position and names. Note the orientation of the axes.
611
644
  rotate_angle:
612
645
  Angle to rotate the plot. For rotate_angle = 0 the resulting plot will have
613
646
  the x-axis pointing towards the east, and the y-axis pointing towards the North.
614
647
  show_tel_label: bool
615
648
  If True it will print the label of the individual telescopes in the plot.
616
649
  While it works well for the smaller arrays, it gets crowded for larger arrays.
650
+ axes_range : float
651
+ Axis range for both axes. Range is from -plot_range to plot_range.
652
+ maker_scaling : float
653
+ Scaling factor for marker size to be plotted.
617
654
 
618
655
  Returns
619
656
  -------
620
657
  plt.figure
621
658
  Instance of plt.figure with the array of telescopes plotted.
622
-
623
659
  """
624
-
625
660
  fig, ax = plt.subplots(1)
626
661
  legend_objects = []
627
662
  legend_labels = []
628
- tel_counters = {one_telescope: 0 for one_telescope in names.all_telescope_class_names}
629
- if rotate_angle != 0:
630
- pos_x_rotated, pos_y_rotated = transf.rotate(
631
- telescopes["position_x"], telescopes["position_y"], rotate_angle
632
- )
633
- else:
634
- pos_x_rotated, pos_y_rotated = telescopes["position_x"], telescopes["position_y"]
663
+ tel_counters = initialize_tel_counters()
664
+
665
+ pos_x_rotated, pos_y_rotated = get_rotated_positions(telescopes, rotate_angle)
666
+ telescopes.add_column(Column(pos_x_rotated, name="pos_x_rotated"))
667
+ telescopes.add_column(Column(pos_y_rotated, name="pos_y_rotated"))
668
+
669
+ fontsize, scale = get_plot_params(len(pos_x_rotated))
670
+ patches = create_patches(
671
+ telescopes, scale, marker_scaling, show_tel_label, ax, fontsize, tel_counters
672
+ )
673
+
674
+ update_legend(ax, tel_counters, legend_objects, legend_labels)
675
+ finalize_plot(ax, patches, x_title="Easting [m]", y_title="Northing [m]", axes_range=axes_range)
676
+
677
+ return fig
635
678
 
636
- pos_x_rotated, pos_y_rotated = transf.rotate(pos_x_rotated, pos_y_rotated, 90 * u.deg)
637
679
 
638
- if len(pos_x_rotated) > 30:
639
- fontsize = 4
640
- scale = 2
680
+ def initialize_tel_counters():
681
+ return {one_telescope: 0 for one_telescope in names.get_list_of_array_element_types()}
682
+
683
+
684
+ def get_rotated_positions(telescopes, rotate_angle):
685
+ pos_x_rotated = pos_y_rotated = None
686
+ if "position_x" in telescopes.colnames and "position_y" in telescopes.colnames:
687
+ pos_x_rotated, pos_y_rotated = telescopes["position_x"], telescopes["position_y"]
688
+ rotate_angle = rotate_angle + 90.0 * u.deg
689
+ elif "utm_east" in telescopes.colnames and "utm_north" in telescopes.colnames:
690
+ pos_x_rotated, pos_y_rotated = telescopes["utm_east"], telescopes["utm_north"]
641
691
  else:
642
- fontsize = 8
643
- scale = 1
692
+ raise ValueError(
693
+ "Telescopes table must contain either 'position_x'/'position_y'"
694
+ "or 'utm_east'/'utm_north' columns"
695
+ )
696
+ if rotate_angle != 0:
697
+ pos_x_rotated, pos_y_rotated = transf.rotate(pos_x_rotated, pos_y_rotated, rotate_angle)
698
+ return pos_x_rotated, pos_y_rotated
699
+
700
+
701
+ def get_plot_params(position_length):
702
+ if position_length > 30:
703
+ return 4, 2
704
+ return 8, 1
644
705
 
706
+
707
+ def create_patches(telescopes, scale, marker_scaling, show_tel_label, ax, fontsize, tel_counters):
645
708
  patches = []
646
- for i_tel, tel_now in enumerate(telescopes):
647
- for tel_type in tel_counters:
648
- if tel_type in tel_now["telescope_name"]:
649
- tel_counters[tel_type] += 1
650
- i_tel_name = names.get_telescope_class(telescopes[i_tel]["telescope_name"])
709
+ for tel_now in telescopes:
710
+ telescope_name = get_telescope_name(tel_now)
711
+ update_tel_counters(tel_counters, telescope_name)
712
+ sphere_radius = get_sphere_radius(tel_now)
713
+ i_tel_name = names.get_array_element_type_from_name(telescope_name)
651
714
  patches.append(
652
715
  get_telescope_patch(
653
716
  i_tel_name,
654
- pos_x_rotated[i_tel],
655
- pos_y_rotated[i_tel],
656
- scale * telescopes[i_tel]["radius"],
717
+ tel_now["pos_x_rotated"],
718
+ tel_now["pos_y_rotated"],
719
+ scale * sphere_radius * marker_scaling,
657
720
  )
658
721
  )
659
722
  if show_tel_label:
660
723
  ax.text(
661
- pos_x_rotated[i_tel].value,
662
- pos_y_rotated[i_tel].value + scale * telescopes[i_tel]["radius"].value,
663
- telescopes[i_tel]["telescope_name"],
724
+ tel_now["pos_x_rotated"].value,
725
+ tel_now["pos_y_rotated"].value + scale * sphere_radius.value,
726
+ telescope_name,
664
727
  horizontalalignment="center",
665
728
  verticalalignment="bottom",
666
729
  fontsize=fontsize,
667
730
  )
731
+ return patches
732
+
733
+
734
+ def get_telescope_name(tel_now):
735
+ """Get the telescope name from the table row."""
736
+ try:
737
+ return tel_now["telescope_name"]
738
+ except KeyError:
739
+ return tel_now["asset_code"] + "-" + tel_now["sequence_number"]
740
+
741
+
742
+ def update_tel_counters(tel_counters, telescope_name):
743
+ """Update the counter for the given telescope type."""
744
+ for tel_type in tel_counters:
745
+ if tel_type in telescope_name:
746
+ tel_counters[tel_type] += 1
747
+
748
+
749
+ def get_sphere_radius(tel_now):
750
+ """Get the sphere radius of the telescope."""
751
+ return 1.0 * u.m if "sphere_radius" not in tel_now.colnames else tel_now["sphere_radius"]
668
752
 
669
- for _, one_telescope in enumerate(names.all_telescope_class_names):
753
+
754
+ def update_legend(ax, tel_counters, legend_objects, legend_labels):
755
+ """Update the legend with the telescope counts."""
756
+ for one_telescope in names.get_list_of_array_element_types():
670
757
  if tel_counters[one_telescope] > 0:
671
758
  legend_objects.append(leg_h.all_telescope_objects[one_telescope]())
672
759
  legend_labels.append(f"{one_telescope} ({tel_counters[one_telescope]})")
673
-
674
- plt.gca().add_collection(PatchCollection(patches, match_original=True))
675
-
676
- x_title = "Easting [m]"
677
- y_title = "Northing [m]"
678
- plt.axis("square")
679
- plt.grid(True)
680
- plt.gca().set_axisbelow(True)
681
- plt.xlabel(x_title, fontsize=18, labelpad=0)
682
- plt.ylabel(y_title, fontsize=18, labelpad=0)
683
- plt.tick_params(axis="both", which="major", labelsize=15)
684
-
685
- legend_handler_map = {
686
- list(leg_h.legend_handler_map.keys())[i_key]: list(leg_h.legend_handler_map.values())[
687
- i_key
688
- ]()
689
- for i_key, _ in enumerate(leg_h.legend_handler_map)
690
- }
691
- plt.legend(
760
+ legend_handler_map = {k: v() for k, v in leg_h.legend_handler_map.items()}
761
+ ax.legend(
692
762
  legend_objects,
693
763
  legend_labels,
694
764
  handler_map=legend_handler_map,
@@ -696,6 +766,115 @@ def plot_array(telescopes, rotate_angle=0, show_tel_label=False):
696
766
  loc="best",
697
767
  )
698
768
 
769
+
770
+ def finalize_plot(ax, patches, x_title, y_title, axes_range):
771
+ """Finalize the plot by adding titles, setting limits, and adding patches."""
772
+ ax.add_collection(PatchCollection(patches, match_original=True))
773
+ ax.set_xlabel(x_title, fontsize=12, labelpad=0)
774
+ ax.set_ylabel(y_title, fontsize=12, labelpad=0)
775
+ ax.tick_params(axis="both", which="major", labelsize=8)
776
+ ax.set_axisbelow(True)
777
+ ax.axis("square")
778
+ if axes_range is not None:
779
+ ax.set_xlim(-axes_range, axes_range)
780
+ ax.set_ylim(-axes_range, axes_range)
699
781
  plt.tight_layout()
700
782
 
783
+
784
+ def plot_simtel_ctapipe(filename, cleaning_args, distance, return_cleaned=False):
785
+ """
786
+ Read in a simtel file and plots reconstructed photoelectrons via ctapipe.
787
+
788
+ Parameters
789
+ ----------
790
+ filename : str
791
+ Path to the simtel file.
792
+ cleaning_args : tuple, optional
793
+ Cleaning parameters as (boundary_thresh, picture_thresh, min_number_picture_neighbors).
794
+ distance : astropy Quantity, optional
795
+ Distance to the target.
796
+ return_cleaned : bool, optional
797
+ If True, apply cleaning to the image.
798
+
799
+ Returns
800
+ -------
801
+ fig : matplotlib.figure.Figure
802
+ The matplotlib figure containing the plot.
803
+ """
804
+ # pylint:disable=import-outside-toplevel
805
+ import numpy as np
806
+ from ctapipe.calib import CameraCalibrator
807
+ from ctapipe.image import tailcuts_clean
808
+ from ctapipe.io import EventSource
809
+ from ctapipe.visualization import CameraDisplay
810
+
811
+ default_cleaning_levels = {
812
+ "CHEC": (2, 4, 2),
813
+ "LSTCam": (3.5, 7, 2),
814
+ "FlashCam": (3.5, 7, 2),
815
+ "NectarCam": (4, 8, 2),
816
+ }
817
+
818
+ source = EventSource(filename, max_events=1)
819
+ event = None
820
+ events = [copy.deepcopy(event) for event in source]
821
+ if len(events) > 1:
822
+ event = events[-1]
823
+ else:
824
+ try:
825
+ event = events[0]
826
+ except IndexError:
827
+ event = events
828
+ tel_id = sorted(event.r1.tel.keys())[0]
829
+
830
+ calib = CameraCalibrator(subarray=source.subarray)
831
+ calib(event)
832
+
833
+ geometry = source.subarray.tel[1].camera.geometry
834
+ image = event.dl1.tel[tel_id].image
835
+ cleaned = image.copy()
836
+
837
+ if return_cleaned:
838
+ if cleaning_args is None:
839
+ boundary, picture, min_neighbors = default_cleaning_levels[geometry.name]
840
+ else:
841
+ boundary, picture, min_neighbors = cleaning_args
842
+ mask = tailcuts_clean(
843
+ geometry,
844
+ image,
845
+ picture_thresh=picture,
846
+ boundary_thresh=boundary,
847
+ min_number_picture_neighbors=min_neighbors,
848
+ )
849
+ cleaned[~mask] = 0
850
+
851
+ fig, ax = plt.subplots(dpi=300)
852
+ title = f"CT{tel_id}, run {event.index.obs_id} event {event.index.event_id}"
853
+ disp = CameraDisplay(geometry, image=cleaned, norm="symlog", ax=ax)
854
+ disp.cmap = "RdBu_r"
855
+ disp.add_colorbar(fraction=0.02, pad=-0.1)
856
+ disp.set_limits_percent(100)
857
+ ax.set_title(title, pad=20)
858
+ ax.annotate(
859
+ f"tel type: {source.subarray.tel[1].type.name}\n"
860
+ f"optics: {source.subarray.tel[1].optics.name}\n"
861
+ f"camera: {source.subarray.tel[1].camera_name}\n"
862
+ f"distance: {distance.to(u.m)}",
863
+ xy=(0, 0),
864
+ xytext=(0.1, 1),
865
+ xycoords="axes fraction",
866
+ va="top",
867
+ size=7,
868
+ )
869
+ ax.annotate(
870
+ f"dl1 image,\ntotal $p.e._{{reco}}$: {np.round(np.sum(image))}\n",
871
+ xy=(0, 0),
872
+ xytext=(0.75, 1),
873
+ xycoords="axes fraction",
874
+ va="top",
875
+ ha="left",
876
+ size=7,
877
+ )
878
+ ax.set_axis_off()
879
+ fig.tight_layout()
701
880
  return fig