gammasimtools 0.17.0__py3-none-any.whl → 0.19.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.0.dist-info}/METADATA +27 -69
  2. gammasimtools-0.19.0.dist-info/RECORD +393 -0
  3. {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.0.dist-info}/entry_points.txt +10 -2
  4. {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.0.dist-info}/licenses/LICENSE +1 -1
  5. simtools/_version.py +16 -3
  6. simtools/applications/calculate_trigger_rate.py +1 -1
  7. simtools/applications/convert_all_model_parameters_from_simtel.py +4 -3
  8. simtools/applications/convert_geo_coordinates_of_array_elements.py +3 -3
  9. simtools/applications/db_add_simulation_model_from_repository_to_db.py +10 -1
  10. simtools/applications/db_add_value_from_json_to_db.py +2 -1
  11. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +8 -13
  12. simtools/applications/db_generate_compound_indexes.py +61 -0
  13. simtools/applications/db_get_file_from_db.py +1 -1
  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 +18 -12
  17. simtools/applications/derive_psf_parameters.py +59 -309
  18. simtools/applications/docs_produce_array_element_report.py +1 -1
  19. simtools/applications/docs_produce_calibration_reports.py +1 -1
  20. simtools/applications/docs_produce_model_parameter_reports.py +1 -1
  21. simtools/applications/docs_produce_simulation_configuration_report.py +1 -1
  22. simtools/applications/generate_corsika_histograms.py +1 -1
  23. simtools/applications/generate_default_metadata.py +8 -24
  24. simtools/applications/generate_sim_telarray_histograms.py +1 -1
  25. simtools/applications/generate_simtel_event_data.py +97 -5
  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 +16 -18
  30. simtools/applications/plot_array_layout.py +3 -3
  31. simtools/applications/plot_simtel_events.py +379 -0
  32. simtools/applications/plot_tabular_data.py +21 -3
  33. simtools/applications/plot_tabular_data_for_model_parameter.py +104 -0
  34. simtools/applications/print_version.py +8 -9
  35. simtools/applications/production_derive_corsika_limits.py +64 -27
  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 +2 -1
  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 +31 -1
  55. simtools/configuration/configurator.py +4 -4
  56. simtools/constants.py +2 -0
  57. simtools/corsika/corsika_config.py +45 -25
  58. simtools/corsika/corsika_histograms.py +6 -5
  59. simtools/data_model/data_reader.py +2 -3
  60. simtools/data_model/metadata_collector.py +32 -36
  61. simtools/data_model/metadata_model.py +15 -12
  62. simtools/data_model/model_data_writer.py +13 -32
  63. simtools/data_model/schema.py +88 -24
  64. simtools/data_model/validate_data.py +34 -9
  65. simtools/db/db_handler.py +48 -37
  66. simtools/db/db_model_upload.py +3 -3
  67. simtools/dependencies.py +88 -25
  68. simtools/io/ascii_handler.py +279 -0
  69. simtools/{io_operations → io}/io_handler.py +25 -3
  70. simtools/{io_operations/io_table_handler.py → io/table_handler.py} +1 -1
  71. simtools/job_execution/htcondor_script_generator.py +15 -4
  72. simtools/layout/array_layout.py +1 -1
  73. simtools/layout/array_layout_utils.py +19 -8
  74. simtools/model/array_model.py +28 -5
  75. simtools/model/flasher_model.py +106 -0
  76. simtools/model/model_parameter.py +4 -4
  77. simtools/model/model_repository.py +197 -2
  78. simtools/model/telescope_model.py +3 -1
  79. simtools/production_configuration/derive_corsika_limits.py +361 -427
  80. simtools/production_configuration/derive_production_statistics_handler.py +7 -6
  81. simtools/production_configuration/generate_production_grid.py +9 -11
  82. simtools/production_configuration/merge_corsika_limits.py +528 -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/resources/array-element-ids.json +126 -0
  88. simtools/runners/corsika_runner.py +1 -1
  89. simtools/runners/corsika_simtel_runner.py +14 -5
  90. simtools/runners/runner_services.py +10 -5
  91. simtools/runners/simtools_runner.py +267 -0
  92. simtools/schemas/application_workflow.metaschema.yml +101 -68
  93. simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +1 -1
  94. simtools/schemas/input/single_pe_spectrum.schema.yml +1 -1
  95. simtools/schemas/metadata.metaschema.yml +577 -3
  96. simtools/schemas/model_parameter.metaschema.yml +6 -6
  97. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +7 -3
  98. simtools/schemas/model_parameters/adjust_gain.schema.yml +1 -1
  99. simtools/schemas/model_parameters/altitude.schema.yml +1 -1
  100. simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
  101. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +1 -1
  102. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +1 -1
  103. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
  104. simtools/schemas/model_parameters/array_layouts.schema.yml +1 -1
  105. simtools/schemas/model_parameters/array_triggers.schema.yml +1 -1
  106. simtools/schemas/model_parameters/array_window.schema.yml +1 -1
  107. simtools/schemas/model_parameters/asum_clipping.schema.yml +1 -1
  108. simtools/schemas/model_parameters/asum_offset.schema.yml +1 -1
  109. simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
  110. simtools/schemas/model_parameters/asum_threshold.schema.yml +1 -1
  111. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +42 -1
  112. simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +44 -1
  113. simtools/schemas/model_parameters/axes_offsets.schema.yml +1 -1
  114. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +1 -1
  115. simtools/schemas/model_parameters/camera_body_shape.schema.yml +1 -1
  116. simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
  117. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +1 -1
  118. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +1 -1
  119. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
  120. simtools/schemas/model_parameters/camera_depth.schema.yml +1 -1
  121. simtools/schemas/model_parameters/camera_filter.schema.yml +11 -1
  122. simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +11 -1
  123. simtools/schemas/model_parameters/camera_pixels.schema.yml +1 -1
  124. simtools/schemas/model_parameters/camera_transmission.schema.yml +1 -1
  125. simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
  126. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +1 -1
  127. simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +1 -1
  128. simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +1 -1
  129. simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +1 -1
  130. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +1 -1
  131. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +1 -1
  132. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +1 -1
  133. simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +1 -1
  134. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +1 -1
  135. simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +1 -1
  136. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +3 -3
  137. simtools/schemas/model_parameters/dark_events.schema.yml +1 -1
  138. simtools/schemas/model_parameters/default_trigger.schema.yml +1 -1
  139. simtools/schemas/model_parameters/design_model.schema.yml +1 -1
  140. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +1 -1
  141. simtools/schemas/model_parameters/disc_bins.schema.yml +1 -1
  142. simtools/schemas/model_parameters/disc_start.schema.yml +1 -1
  143. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +1 -1
  144. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +1 -1
  145. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +1 -1
  146. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +1 -1
  147. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +1 -1
  148. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +1 -1
  149. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +32 -1
  150. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +1 -1
  151. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +1 -1
  152. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +1 -1
  153. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +1 -1
  154. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -1
  155. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +1 -1
  156. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +1 -1
  157. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +1 -1
  158. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +1 -1
  159. simtools/schemas/model_parameters/dish_shape_length.schema.yml +1 -1
  160. simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -1
  161. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +1 -1
  162. simtools/schemas/model_parameters/dsum_offset.schema.yml +1 -1
  163. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +1 -1
  164. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +1 -1
  165. simtools/schemas/model_parameters/dsum_prescale.schema.yml +1 -1
  166. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +1 -1
  167. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +1 -1
  168. simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
  169. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +1 -1
  170. simtools/schemas/model_parameters/dsum_threshold.schema.yml +2 -2
  171. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +1 -1
  172. simtools/schemas/model_parameters/effective_focal_length.schema.yml +1 -1
  173. simtools/schemas/model_parameters/epsg_code.schema.yml +1 -1
  174. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +1 -1
  175. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +1 -1
  176. simtools/schemas/model_parameters/fadc_bins.schema.yml +1 -1
  177. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
  178. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
  179. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +1 -1
  180. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +1 -1
  181. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +1 -1
  182. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
  183. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
  184. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +1 -1
  185. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +1 -1
  186. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +1 -1
  187. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +1 -1
  188. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +1 -1
  189. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +1 -1
  190. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +1 -1
  191. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +1 -1
  192. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +1 -1
  193. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +1 -1
  194. simtools/schemas/model_parameters/fadc_long_event_threshold.schema.yml +35 -0
  195. simtools/schemas/model_parameters/fadc_long_sum_bins.schema.yml +41 -0
  196. simtools/schemas/model_parameters/fadc_long_sum_offset.schema.yml +38 -0
  197. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +1 -1
  198. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +1 -1
  199. simtools/schemas/model_parameters/fadc_mhz.schema.yml +1 -1
  200. simtools/schemas/model_parameters/fadc_noise.schema.yml +1 -1
  201. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +1 -1
  202. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +13 -1
  203. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +1 -1
  204. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +1 -1
  205. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +1 -1
  206. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +1 -1
  207. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +1 -1
  208. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +1 -1
  209. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  210. simtools/schemas/model_parameters/flatfielding.schema.yml +1 -1
  211. simtools/schemas/model_parameters/focal_length.schema.yml +1 -1
  212. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +1 -1
  213. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +1 -1
  214. simtools/schemas/model_parameters/focus_offset.schema.yml +1 -1
  215. simtools/schemas/model_parameters/gain_variation.schema.yml +1 -1
  216. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +1 -1
  217. simtools/schemas/model_parameters/geomag_rotation.schema.yml +1 -1
  218. simtools/schemas/model_parameters/geomag_vertical.schema.yml +1 -1
  219. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +1 -1
  220. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
  221. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
  222. simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
  223. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +1 -1
  224. simtools/schemas/model_parameters/laser_photons.schema.yml +1 -1
  225. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +1 -1
  226. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +1 -1
  227. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +1 -1
  228. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +1 -1
  229. simtools/schemas/model_parameters/laser_var_photons.schema.yml +1 -1
  230. simtools/schemas/model_parameters/laser_wavelength.schema.yml +1 -1
  231. simtools/schemas/model_parameters/led_events.schema.yml +1 -1
  232. simtools/schemas/model_parameters/led_photons.schema.yml +1 -1
  233. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +1 -1
  234. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +1 -1
  235. simtools/schemas/model_parameters/led_var_photons.schema.yml +1 -1
  236. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +11 -1
  237. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +50 -1
  238. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
  239. simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
  240. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +1 -1
  241. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +1 -1
  242. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +1 -1
  243. simtools/schemas/model_parameters/mirror_class.schema.yml +1 -1
  244. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +1 -1
  245. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +1 -1
  246. simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
  247. simtools/schemas/model_parameters/mirror_offset.schema.yml +1 -1
  248. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +1 -1
  249. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +1 -1
  250. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +11 -1
  251. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +1 -1
  252. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +1 -1
  253. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +1 -1
  254. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +1 -1
  255. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +1 -1
  256. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +1 -1
  257. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +13 -1
  258. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +1 -1
  259. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +1 -1
  260. simtools/schemas/model_parameters/nsb_sky_map.schema.yml +1 -1
  261. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +1 -1
  262. simtools/schemas/model_parameters/num_gains.schema.yml +1 -1
  263. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +1 -1
  264. simtools/schemas/model_parameters/optics_properties.schema.yml +1 -1
  265. simtools/schemas/model_parameters/parabolic_dish.schema.yml +1 -1
  266. simtools/schemas/model_parameters/pedestal_events.schema.yml +1 -1
  267. simtools/schemas/model_parameters/photon_delay.schema.yml +1 -1
  268. simtools/schemas/model_parameters/photons_per_run.schema.yml +1 -1
  269. simtools/schemas/model_parameters/pixel_cells.schema.yml +1 -1
  270. simtools/schemas/model_parameters/pixels_parallel.schema.yml +1 -1
  271. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +1 -1
  272. simtools/schemas/model_parameters/pm_average_gain.schema.yml +1 -1
  273. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +1 -1
  274. simtools/schemas/model_parameters/pm_gain_index.schema.yml +1 -1
  275. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +20 -1
  276. simtools/schemas/model_parameters/pm_transit_time.schema.yml +1 -1
  277. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +1 -1
  278. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +1 -1
  279. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +1 -1
  280. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +1 -1
  281. simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +11 -1
  282. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +1 -1
  283. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +1 -1
  284. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
  285. simtools/schemas/model_parameters/qe_variation.schema.yml +1 -1
  286. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +11 -1
  287. simtools/schemas/model_parameters/random_focal_length.schema.yml +1 -1
  288. simtools/schemas/model_parameters/random_generator.schema.yml +1 -1
  289. simtools/schemas/model_parameters/random_mono_probability.schema.yml +1 -1
  290. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +1 -1
  291. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +1 -1
  292. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +1 -1
  293. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +1 -1
  294. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +1 -1
  295. simtools/schemas/model_parameters/sampled_output.schema.yml +1 -1
  296. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +1 -1
  297. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +1 -1
  298. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
  299. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
  300. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +1 -1
  301. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +1 -1
  302. simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +11 -1
  303. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +1 -1
  304. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +1 -1
  305. simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +11 -1
  306. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
  307. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +1 -1
  308. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +1 -1
  309. simtools/schemas/model_parameters/stars.schema.yml +1 -1
  310. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
  311. simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
  312. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +1 -1
  313. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +1 -1
  314. simtools/schemas/model_parameters/telescope_random_error.schema.yml +1 -1
  315. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +1 -1
  316. simtools/schemas/model_parameters/telescope_transmission.schema.yml +1 -1
  317. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +1 -1
  318. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +1 -1
  319. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +1 -1
  320. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +1 -1
  321. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +1 -1
  322. simtools/schemas/model_parameters/transit_time_error.schema.yml +1 -1
  323. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +1 -1
  324. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +1 -1
  325. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +1 -1
  326. simtools/schemas/model_parameters/trigger_pixels.schema.yml +1 -1
  327. simtools/schemas/plot_configuration.metaschema.yml +51 -59
  328. simtools/schemas/production_configuration_metrics.schema.yml +12 -2
  329. simtools/schemas/production_tables.schema.yml +2 -2
  330. simtools/simtel/simtel_config_reader.py +2 -2
  331. simtools/simtel/simtel_config_writer.py +16 -4
  332. simtools/simtel/simtel_io_event_histograms.py +746 -0
  333. simtools/simtel/simtel_io_event_reader.py +16 -43
  334. simtools/simtel/simtel_io_event_writer.py +46 -10
  335. simtools/simtel/simtel_io_histogram.py +3 -1
  336. simtools/simtel/simtel_io_histograms.py +7 -3
  337. simtools/simtel/simtel_io_metadata.py +99 -3
  338. simtools/simtel/simtel_table_reader.py +92 -10
  339. simtools/simtel/simulator_array.py +138 -10
  340. simtools/simtel/simulator_camera_efficiency.py +32 -23
  341. simtools/simtel/simulator_light_emission.py +437 -271
  342. simtools/simtel/simulator_ray_tracing.py +1 -1
  343. simtools/simulator.py +105 -147
  344. simtools/testing/configuration.py +24 -26
  345. simtools/testing/helpers.py +2 -2
  346. simtools/testing/log_inspector.py +50 -0
  347. simtools/testing/validate_output.py +87 -37
  348. simtools/utils/general.py +125 -257
  349. simtools/utils/geometry.py +36 -0
  350. simtools/utils/names.py +72 -3
  351. simtools/visualization/legend_handlers.py +180 -264
  352. simtools/visualization/plot_array_layout.py +20 -8
  353. simtools/visualization/plot_pixels.py +1 -2
  354. simtools/visualization/plot_tables.py +202 -27
  355. simtools/visualization/simtel_event_plots.py +816 -0
  356. simtools/visualization/visualize.py +4 -101
  357. gammasimtools-0.17.0.dist-info/RECORD +0 -374
  358. simtools/production_configuration/derive_corsika_limits_grid.py +0 -189
  359. {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.0.dist-info}/WHEEL +0 -0
  360. {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.0.dist-info}/top_level.txt +0 -0
  361. /simtools/{io_operations → io}/hdf5_handler.py +0 -0
  362. /simtools/{io_operations → io}/legacy_data_handler.py +0 -0
  363. /simtools/{schemas → resources}/array_elements.yml +0 -0
@@ -11,13 +11,11 @@ import logging
11
11
  import uuid
12
12
  from pathlib import Path
13
13
 
14
- import yaml
15
-
16
14
  import simtools.utils.general as gen
17
15
  import simtools.version
18
16
  from simtools.constants import METADATA_JSON_SCHEMA
19
17
  from simtools.data_model import metadata_model, schema
20
- from simtools.io_operations import io_handler
18
+ from simtools.io import ascii_handler, io_handler
21
19
  from simtools.utils import names
22
20
 
23
21
  __all__ = ["MetadataCollector"]
@@ -41,33 +39,36 @@ class MetadataCollector:
41
39
  Command line parameters
42
40
  metadata_file_name: str
43
41
  Name of metadata file (only required when args_dict is None)
44
- data_model_name: str
45
- Name of data model parameter
42
+ model_parameter_name: str
43
+ Name of model parameter
46
44
  observatory: str
47
45
  Name of observatory (default: "cta")
48
46
  clean_meta: bool
49
47
  Clean metadata from None values and empty lists (default: True)
48
+ schema_version: str
49
+ Version of the metadata schema to use (default: 'latest')
50
50
  """
51
51
 
52
52
  def __init__(
53
53
  self,
54
- args_dict,
54
+ args_dict=None,
55
55
  metadata_file_name=None,
56
- data_model_name=None,
56
+ model_parameter_name=None,
57
57
  observatory="cta",
58
58
  clean_meta=True,
59
+ schema_version="latest",
59
60
  ):
60
61
  """Initialize metadata collector."""
61
62
  self._logger = logging.getLogger(__name__)
62
63
  self.observatory = observatory
63
64
  self.io_handler = io_handler.IOHandler()
64
65
 
65
- self.args_dict = args_dict if args_dict else {}
66
- self.data_model_name = data_model_name
66
+ self.args_dict = args_dict or {}
67
+ self.model_parameter_name = model_parameter_name
67
68
  self.schema_file = None
68
69
  self.schema_dict = None
69
- self.top_level_meta = gen.change_dict_keys_case(
70
- data_dict=metadata_model.get_default_metadata_dict(), lower_case=True
70
+ self.top_level_meta = metadata_model.get_default_metadata_dict(
71
+ schema_version=schema_version
71
72
  )
72
73
  self.input_metadata = self._read_input_metadata_from_file(metadata_file_name)
73
74
  self.collect_meta_data()
@@ -119,7 +120,7 @@ class MetadataCollector:
119
120
  collector = MetadataCollector(args_dict)
120
121
  collector.write(output_file, add_activity_name=add_activity_name)
121
122
 
122
- def write(self, yml_file=None, keys_lower_case=False, add_activity_name=False):
123
+ def write(self, yml_file=None, keys_lower_case=True, add_activity_name=False):
123
124
  """
124
125
  Write toplevel metadata to file (yaml file format).
125
126
 
@@ -155,16 +156,13 @@ class MetadataCollector:
155
156
 
156
157
  try:
157
158
  yml_file = names.file_name_with_version(yml_file, suffix)
158
- with open(yml_file, "w", encoding="UTF-8") as file:
159
- yaml.safe_dump(
160
- gen.change_dict_keys_case(
161
- gen.remove_substring_recursively_from_dict(metadata, substring="\n"),
162
- keys_lower_case,
163
- ),
164
- file,
165
- sort_keys=False,
166
- explicit_start=True,
167
- )
159
+ ascii_handler.write_data_to_file(
160
+ data=gen.change_dict_keys_case(
161
+ gen.remove_substring_recursively_from_dict(metadata, substring="\n"),
162
+ keys_lower_case,
163
+ ),
164
+ output_file=yml_file,
165
+ )
168
166
  self._logger.info(f"Writing metadata to {yml_file}")
169
167
  return yml_file
170
168
  except FileNotFoundError as exc:
@@ -198,10 +196,10 @@ class MetadataCollector:
198
196
  except KeyError:
199
197
  pass
200
198
 
201
- # from data model name
202
- if self.data_model_name:
203
- self._logger.debug(f"Schema file from data model name: {self.data_model_name}")
204
- return str(schema.get_model_parameter_schema_file(self.data_model_name))
199
+ # from model parameter name
200
+ if self.model_parameter_name:
201
+ self._logger.debug(f"Schema file from data model name: {self.model_parameter_name}")
202
+ return str(schema.get_model_parameter_schema_file(self.model_parameter_name))
205
203
 
206
204
  # from first entry in input metadata (least preferred)
207
205
  try:
@@ -225,7 +223,7 @@ class MetadataCollector:
225
223
 
226
224
  """
227
225
  try:
228
- return gen.collect_data_from_file(file_name=self.schema_file)
226
+ return ascii_handler.collect_data_from_file(file_name=self.schema_file)
229
227
  except TypeError:
230
228
  self._logger.debug(f"No valid schema file provided ({self.schema_file}).")
231
229
  return {}
@@ -334,7 +332,7 @@ class MetadataCollector:
334
332
 
335
333
  Raises
336
334
  ------
337
- gen.InvalidConfigDataError, FileNotFoundError
335
+ ValueError:
338
336
  if metadata cannot be read from file.
339
337
  KeyError:
340
338
  if metadata does not exist
@@ -365,7 +363,7 @@ class MetadataCollector:
365
363
  )
366
364
  continue
367
365
  else:
368
- raise gen.InvalidConfigDataError(f"Unknown metadata file format: {metadata_file}")
366
+ raise ValueError(f"Unknown metadata file format: {metadata_file}")
369
367
 
370
368
  schema.validate_dict_using_schema(_input_metadata, schema_file=METADATA_JSON_SCHEMA)
371
369
  metadata.append(gen.change_dict_keys_case(_input_metadata, lower_case=True))
@@ -391,16 +389,14 @@ class MetadataCollector:
391
389
  def _read_input_metadata_from_yml_or_json(self, metadata_file_name):
392
390
  """Read input metadata from yml or json file."""
393
391
  try:
394
- _input_metadata = gen.collect_data_from_file(file_name=metadata_file_name)
392
+ _input_metadata = ascii_handler.collect_data_from_file(file_name=metadata_file_name)
395
393
  _json_type_metadata = {"Metadata", "metadata", "METADATA"}.intersection(_input_metadata)
396
394
  if len(_json_type_metadata) == 1:
397
395
  _input_metadata = _input_metadata[_json_type_metadata.pop()]
398
396
  if len(_json_type_metadata) > 1:
399
- self._logger.error("More than one metadata entry found in %s", metadata_file_name)
400
- raise gen.InvalidConfigDataError
401
- except (gen.InvalidConfigDataError, FileNotFoundError) as exc:
402
- self._logger.error("Failed reading metadata from %s", metadata_file_name)
403
- raise exc
397
+ raise ValueError(f"More than one metadata entry found in {metadata_file_name}")
398
+ except FileNotFoundError as exc:
399
+ raise FileNotFoundError(f"Failed reading metadata from {metadata_file_name}") from exc
404
400
  return _input_metadata
405
401
 
406
402
  def _fill_product_meta(self, product_dict):
@@ -443,7 +439,7 @@ class MetadataCollector:
443
439
  or self.args_dict.get("metadata_product_data_name")
444
440
  or "undefined_model_name"
445
441
  )
446
- product_dict["data"]["model"]["version"] = self.schema_dict.get("version", "0.0.0")
442
+ product_dict["data"]["model"]["version"] = self.schema_dict.get("schema_version", "0.0.0")
447
443
  product_dict["data"]["model"]["type"] = self.schema_dict.get("meta_schema", None)
448
444
  product_dict["data"]["model"]["url"] = self.schema_file or self.args_dict.get(
449
445
  "metadata_product_data_url"
@@ -11,11 +11,14 @@ Follows CTAO top-level data model definition.
11
11
  import logging
12
12
 
13
13
  import simtools.data_model.schema
14
+ import simtools.utils.general as gen
14
15
 
15
16
  _logger = logging.getLogger(__name__)
16
17
 
17
18
 
18
- def get_default_metadata_dict(schema_file=None, observatory="CTA"):
19
+ def get_default_metadata_dict(
20
+ schema_file=None, observatory="CTA", schema_version="latest", lower_case=True
21
+ ):
19
22
  """
20
23
  Return metadata schema with default values.
21
24
 
@@ -27,6 +30,10 @@ def get_default_metadata_dict(schema_file=None, observatory="CTA"):
27
30
  Schema file (jsonschema format) used for validation
28
31
  observatory: str
29
32
  Observatory name
33
+ schema_version: str, optional
34
+ Version of the schema to use. If not provided, the latest version is used.
35
+ lower_case: bool, optional
36
+ If True, all keys in the returned dictionary will be converted to lower case.
30
37
 
31
38
  Returns
32
39
  -------
@@ -35,8 +42,11 @@ def get_default_metadata_dict(schema_file=None, observatory="CTA"):
35
42
 
36
43
 
37
44
  """
38
- schema = simtools.data_model.schema.load_schema(schema_file)
39
- return _fill_defaults(schema["definitions"], observatory)
45
+ schema = simtools.data_model.schema.load_schema(schema_file, schema_version=schema_version)
46
+ return gen.change_dict_keys_case(
47
+ data_dict=_fill_defaults(schema["definitions"], observatory.lower()),
48
+ lower_case=lower_case,
49
+ )
40
50
 
41
51
 
42
52
  def _resolve_references(yaml_data, observatory="CTA"):
@@ -62,7 +72,7 @@ def _resolve_references(yaml_data, observatory="CTA"):
62
72
  parts = ref_path.split("/")
63
73
  ref_data = yaml_data
64
74
  for part in parts:
65
- if part in ("definitions", observatory):
75
+ if part in ("definitions", observatory.lower()):
66
76
  continue
67
77
  ref_data = ref_data.get(part, {})
68
78
  return ref_data
@@ -123,7 +133,7 @@ def _fill_defaults_recursive(sub_schema, current_dict):
123
133
  Current dictionary to fill with default values.
124
134
  """
125
135
  if "properties" not in sub_schema:
126
- _raise_missing_properties_error()
136
+ raise KeyError("Missing 'properties' key in schema.")
127
137
 
128
138
  for prop, prop_schema in sub_schema["properties"].items():
129
139
  _process_property(prop, prop_schema, current_dict)
@@ -152,10 +162,3 @@ def _process_property(prop, prop_schema, current_dict):
152
162
  current_dict[prop] = [{}]
153
163
  if "items" in prop_schema and isinstance(prop_schema["items"], dict):
154
164
  _fill_defaults_recursive(prop_schema["items"], current_dict[prop][0])
155
-
156
-
157
- def _raise_missing_properties_error():
158
- """Raise an error when the 'properties' key is missing in the schema."""
159
- msg = "Missing 'properties' key in schema."
160
- _logger.error(msg)
161
- raise KeyError(msg)
@@ -1,40 +1,20 @@
1
1
  """Model data writer module."""
2
2
 
3
- import json
4
3
  import logging
5
4
  from pathlib import Path
6
5
 
7
- import astropy.units as u
8
- import numpy as np
9
6
  from astropy.io.registry.base import IORegistryError
10
7
 
11
8
  import simtools.utils.general as gen
12
9
  from simtools.data_model import schema, validate_data
13
10
  from simtools.data_model.metadata_collector import MetadataCollector
14
11
  from simtools.db import db_handler
15
- from simtools.io_operations import io_handler
12
+ from simtools.io import ascii_handler, io_handler
16
13
  from simtools.utils import names, value_conversion
17
14
 
18
15
  __all__ = ["ModelDataWriter"]
19
16
 
20
17
 
21
- class JsonNumpyEncoder(json.JSONEncoder):
22
- """Convert numpy to python types as accepted by json.dump."""
23
-
24
- def default(self, o):
25
- if isinstance(o, np.floating):
26
- return float(o)
27
- if isinstance(o, np.integer):
28
- return int(o)
29
- if isinstance(o, np.ndarray):
30
- return o.tolist()
31
- if isinstance(o, u.core.CompositeUnit | u.core.IrreducibleUnit | u.core.Unit):
32
- return str(o) if o != u.dimensionless_unscaled else None
33
- if np.issubdtype(type(o), np.bool_):
34
- return bool(o)
35
- return super().default(o)
36
-
37
-
38
18
  class ModelDataWriter:
39
19
  """
40
20
  Writer for simulation model data and metadata.
@@ -254,7 +234,7 @@ class ModelDataWriter:
254
234
  """
255
235
  self._logger.debug(f"Getting validated parameter dictionary for {instrument}")
256
236
  schema_file = schema.get_model_parameter_schema_file(parameter_name)
257
- self.schema_dict = gen.collect_data_from_file(schema_file)
237
+ self.schema_dict = ascii_handler.collect_data_from_file(schema_file)
258
238
 
259
239
  value, unit = value_conversion.split_value_and_unit(value)
260
240
 
@@ -381,7 +361,7 @@ class ModelDataWriter:
381
361
 
382
362
  if metadata is not None:
383
363
  product_data.meta.update(
384
- gen.change_dict_keys_case(metadata.get_top_level_metadata(), False)
364
+ gen.change_dict_keys_case(metadata.get_top_level_metadata(), True)
385
365
  )
386
366
 
387
367
  self._logger.info(f"Writing data to {self.product_data_file}")
@@ -415,15 +395,13 @@ class ModelDataWriter:
415
395
  if data writing was not successful.
416
396
  """
417
397
  data_dict = ModelDataWriter.prepare_data_dict_for_writing(data_dict)
418
- try:
419
- self._logger.info(f"Writing data to {self.io_handler.get_output_file(file_name)}")
420
- with open(self.io_handler.get_output_file(file_name), "w", encoding="UTF-8") as file:
421
- json.dump(data_dict, file, indent=4, sort_keys=False, cls=JsonNumpyEncoder)
422
- file.write("\n")
423
- except FileNotFoundError as exc:
424
- raise FileNotFoundError(
425
- f"Error writing model data to {self.io_handler.get_output_file(file_name)}"
426
- ) from exc
398
+ self._logger.info(f"Writing data to {self.io_handler.get_output_file(file_name)}")
399
+ ascii_handler.write_data_to_file(
400
+ data=data_dict,
401
+ output_file=self.io_handler.get_output_file(file_name),
402
+ sort_keys=False,
403
+ numpy_types=True,
404
+ )
427
405
 
428
406
  @staticmethod
429
407
  def prepare_data_dict_for_writing(data_dict):
@@ -432,6 +410,7 @@ class ModelDataWriter:
432
410
 
433
411
  Ensure sim_telarray style lists as strings 'type' and 'unit' entries.
434
412
  Replace "None" with "null" for unit field.
413
+ Replace list of equal units with single unit string.
435
414
 
436
415
  Parameters
437
416
  ----------
@@ -452,6 +431,8 @@ class ModelDataWriter:
452
431
  unit.replace("None", "null") if isinstance(unit, str) else unit
453
432
  for unit in data_dict["unit"]
454
433
  ]
434
+ if all(u == data_dict["unit"][0] for u in data_dict["unit"]):
435
+ data_dict["unit"] = data_dict["unit"][0]
455
436
  except KeyError:
456
437
  pass
457
438
  return data_dict
@@ -4,6 +4,7 @@ import logging
4
4
  from pathlib import Path
5
5
 
6
6
  import jsonschema
7
+ from referencing import Registry, Resource
7
8
 
8
9
  import simtools.utils.general as gen
9
10
  from simtools.constants import (
@@ -13,6 +14,7 @@ from simtools.constants import (
13
14
  SCHEMA_PATH,
14
15
  )
15
16
  from simtools.data_model import format_checkers
17
+ from simtools.io import ascii_handler
16
18
  from simtools.utils import names
17
19
 
18
20
  _logger = logging.getLogger(__name__)
@@ -36,7 +38,7 @@ def get_model_parameter_schema_files(schema_directory=MODEL_PARAMETER_SCHEMA_PAT
36
38
  parameters = []
37
39
  for schema_file in schema_files:
38
40
  # reading parameter 'name' only - first document in schema file should be ok
39
- schema_dict = gen.collect_data_from_file(file_name=schema_file, yaml_document=0)
41
+ schema_dict = ascii_handler.collect_data_from_file(file_name=schema_file, yaml_document=0)
40
42
  parameters.append(schema_dict.get("name"))
41
43
  return parameters, schema_files
42
44
 
@@ -79,12 +81,12 @@ def get_model_parameter_schema_version(schema_version=None):
79
81
  Schema version.
80
82
 
81
83
  """
82
- schemas = gen.collect_data_from_file(MODEL_PARAMETER_METASCHEMA)
84
+ schemas = ascii_handler.collect_data_from_file(MODEL_PARAMETER_METASCHEMA)
83
85
 
84
86
  if schema_version is None and schemas:
85
- return schemas[0].get("version")
87
+ return schemas[0].get("schema_version")
86
88
 
87
- if any(schema.get("version") == schema_version for schema in schemas):
89
+ if any(schema.get("schema_version") == schema_version for schema in schemas):
88
90
  return schema_version
89
91
 
90
92
  raise ValueError(f"Schema version {schema_version} not found in {MODEL_PARAMETER_METASCHEMA}.")
@@ -111,16 +113,16 @@ def validate_dict_using_schema(data, schema_file=None, json_schema=None):
111
113
  _logger.warning(f"No schema provided for validation of {data}")
112
114
  return None
113
115
  if json_schema is None:
114
- json_schema = load_schema(
115
- schema_file,
116
- data.get("schema_version")
117
- or data.get(
118
- "SCHEMA_VERSION", "0.1.0"
119
- ), # default version to ensure backward compatibility
120
- )
116
+ json_schema = load_schema(schema_file, get_schema_version_from_data(data))
117
+
118
+ validator = jsonschema.Draft6Validator(
119
+ schema=json_schema,
120
+ format_checker=format_checkers.format_checker,
121
+ registry=Registry(retrieve=_retrieve_yaml_schema_from_uri),
122
+ )
121
123
 
122
124
  try:
123
- jsonschema.validate(data, schema=json_schema, format_checker=format_checkers.format_checker)
125
+ validator.validate(instance=data)
124
126
  except jsonschema.exceptions.ValidationError as exc:
125
127
  _logger.error(f"Validation failed using schema: {json_schema} for data: {data}")
126
128
  raise exc
@@ -135,7 +137,39 @@ def validate_dict_using_schema(data, schema_file=None, json_schema=None):
135
137
  return data
136
138
 
137
139
 
138
- def load_schema(schema_file=None, schema_version=None):
140
+ def _retrieve_yaml_schema_from_uri(uri):
141
+ """Load schema from a file URI."""
142
+ path = SCHEMA_PATH / Path(uri.removeprefix("file:/"))
143
+ contents = ascii_handler.collect_data_from_file(file_name=path)
144
+ return Resource.from_contents(contents)
145
+
146
+
147
+ def get_schema_version_from_data(data, observatory="cta"):
148
+ """
149
+ Get schema version from data dictionary.
150
+
151
+ Parameters
152
+ ----------
153
+ data: dict
154
+ data dictionary.
155
+
156
+ Returns
157
+ -------
158
+ str
159
+ Schema version. If not found, returns 'latest'.
160
+ """
161
+ schema_version = data.get("schema_version") or data.get("SCHEMA_VERSION")
162
+ if schema_version:
163
+ return schema_version
164
+ reference_version = data.get(observatory.upper(), {}).get("REFERENCE", {}).get(
165
+ "VERSION"
166
+ ) or data.get(observatory.lower(), {}).get("reference", {}).get("version")
167
+ if reference_version:
168
+ return reference_version
169
+ return "latest"
170
+
171
+
172
+ def load_schema(schema_file=None, schema_version="latest"):
139
173
  """
140
174
  Load parameter schema from file.
141
175
 
@@ -161,28 +195,58 @@ def load_schema(schema_file=None, schema_version=None):
161
195
 
162
196
  for path in (schema_file, SCHEMA_PATH / schema_file):
163
197
  try:
164
- schema = gen.collect_data_from_file(file_name=path)
198
+ schema = ascii_handler.collect_data_from_file(file_name=path)
165
199
  break
166
200
  except FileNotFoundError:
167
201
  continue
168
202
  else:
169
203
  raise FileNotFoundError(f"Schema file not found: {schema_file}")
170
204
 
171
- if isinstance(schema, list): # schema file with several schemas defined
172
- if schema_version is None:
173
- raise ValueError(f"Schema version not given in {schema_file}.")
174
- schema = next((doc for doc in schema if doc.get("version") == schema_version), None)
175
- if schema is None:
176
- raise ValueError(f"Schema version {schema_version} not found in {schema_file}.")
177
- elif schema_version is not None and schema_version != schema.get("version"):
178
- _logger.warning(f"Schema version {schema_version} does not match {schema.get('version')}")
179
-
180
- _logger.debug(f"Loading schema from {schema_file}")
205
+ _logger.debug(f"Loading schema from {schema_file} for schema version {schema_version}")
206
+ schema = _get_schema_for_version(schema, schema_file, schema_version)
181
207
  _add_array_elements("InstrumentTypeElement", schema)
182
208
 
183
209
  return schema
184
210
 
185
211
 
212
+ def _get_schema_for_version(schema, schema_file, schema_version):
213
+ """
214
+ Get schema for a specific version.
215
+
216
+ Allow for 'latest' version to return the most recent schema.
217
+
218
+ Parameters
219
+ ----------
220
+ schema: dict or list
221
+ Schema dictionary or list of dictionaries.
222
+ schema_file: str
223
+ Path to schema file.
224
+ schema_version: str or None
225
+ Schema version to retrieve. If 'latest', the most recent version is returned.
226
+
227
+ Returns
228
+ -------
229
+ dict
230
+ Schema dictionary for the specified version.
231
+ """
232
+ if schema_version is None:
233
+ raise ValueError(f"Schema version not given in {schema_file}.")
234
+
235
+ if isinstance(schema, list): # schema file with several schemas defined
236
+ if len(schema) == 0:
237
+ raise ValueError(f"No schemas found in {schema_file}.")
238
+ if schema_version == "latest":
239
+ schema_version = schema[0].get("schema_version")
240
+ schema = next((doc for doc in schema if doc.get("schema_version") == schema_version), None)
241
+ if schema is None:
242
+ raise ValueError(f"Schema version {schema_version} not found in {schema_file}.")
243
+ if schema_version not in (None, "latest") and schema_version != schema.get("schema_version"):
244
+ _logger.warning(
245
+ f"Schema version {schema_version} does not match {schema.get('schema_version')}"
246
+ )
247
+ return schema
248
+
249
+
186
250
  def _get_array_element_list():
187
251
  """Build complete list of array elements including design types."""
188
252
  elements = set(names.array_elements().keys())
@@ -12,6 +12,7 @@ from astropy.utils.diff import report_diff_values
12
12
 
13
13
  import simtools.utils.general as gen
14
14
  from simtools.data_model import schema
15
+ from simtools.io import ascii_handler
15
16
  from simtools.utils import names, value_conversion
16
17
 
17
18
  __all__ = ["DataValidator"]
@@ -100,7 +101,7 @@ class DataValidator:
100
101
  """
101
102
  try:
102
103
  if Path(self.data_file_name).suffix in (".yml", ".yaml", ".json"):
103
- self.data_dict = gen.collect_data_from_file(self.data_file_name)
104
+ self.data_dict = ascii_handler.collect_data_from_file(self.data_file_name)
104
105
  self._logger.info(f"Validating data from: {self.data_file_name}")
105
106
  else:
106
107
  self.data_table = Table.read(self.data_file_name, guess=True, delimiter=r"\s")
@@ -563,7 +564,7 @@ class DataValidator:
563
564
  If unit conversions fails
564
565
 
565
566
  """
566
- self._logger.debug(f"Checking data column '{col_name}'")
567
+ self._rate_limited_logger(col_name, f"Checking data column '{col_name}'")
567
568
 
568
569
  reference_unit = self._get_reference_unit(col_name)
569
570
  try:
@@ -574,9 +575,10 @@ class DataValidator:
574
575
  if self._is_dimensionless(column_unit) and self._is_dimensionless(reference_unit):
575
576
  return data, u.dimensionless_unscaled
576
577
 
577
- self._logger.debug(
578
+ self._rate_limited_logger(
579
+ col_name,
578
580
  f"Data column '{col_name}' with reference unit "
579
- f"'{reference_unit}' and data unit '{column_unit}'"
581
+ f"'{reference_unit}' and data unit '{column_unit}'",
580
582
  )
581
583
  try:
582
584
  if isinstance(data, u.Quantity | Column):
@@ -652,7 +654,9 @@ class DataValidator:
652
654
  range columns
653
655
 
654
656
  """
655
- self._logger.debug(f"Checking data in column '{col_name}' for '{range_type}' ")
657
+ self._rate_limited_logger(
658
+ col_name, f"Checking data in column '{col_name}' for '{range_type}'"
659
+ )
656
660
 
657
661
  if range_type not in ("allowed_range", "required_range"):
658
662
  raise KeyError("Allowed range types are 'allowed_range', 'required_range'")
@@ -673,6 +677,26 @@ class DataValidator:
673
677
  f"{_entry[range_type].get('max', np.inf)}])"
674
678
  )
675
679
 
680
+ def _rate_limited_logger(self, col_name, message, max_logs=10):
681
+ """
682
+ Log debug messages at a limited rate defined by a numerical column name.
683
+
684
+ Parameters
685
+ ----------
686
+ col_name: str or int
687
+ Column name or index to limit the rate of logging.
688
+ message: str
689
+ Message to log.
690
+ max_logs: int
691
+ Maximum number of logging messages to be printed.
692
+ """
693
+ try:
694
+ col_index = int(col_name)
695
+ if col_index < max_logs:
696
+ self._logger.debug(message)
697
+ except (ValueError, TypeError):
698
+ self._logger.debug(message)
699
+
676
700
  @staticmethod
677
701
  def _interval_check(data, axis_range, range_type):
678
702
  """
@@ -732,11 +756,11 @@ class DataValidator:
732
756
  ValueError
733
757
  if schema version is not found in schema file
734
758
  """
735
- schema_data = gen.collect_data_from_file(file_name=schema_file)
759
+ schema_data = ascii_handler.collect_data_from_file(file_name=schema_file)
736
760
  entries = schema_data if isinstance(schema_data, list) else [schema_data]
737
761
 
738
762
  for entry in entries:
739
- if not schema_version or entry.get("version") == schema_version:
763
+ if not schema_version or entry.get("schema_version") == schema_version:
740
764
  try:
741
765
  return entry["data"]
742
766
  except KeyError as exc:
@@ -774,8 +798,9 @@ class DataValidator:
774
798
  If data column is not found.
775
799
 
776
800
  """
777
- self._logger.debug(
778
- f"Getting reference data column {column_name} from schema {self._data_description}"
801
+ self._rate_limited_logger(
802
+ column_name,
803
+ f"Getting reference data column {column_name} from schema {self._data_description}",
779
804
  )
780
805
  try:
781
806
  return (