gammasimtools 0.20.0__py3-none-any.whl → 0.22.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 (315) hide show
  1. {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/METADATA +2 -3
  2. {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/RECORD +313 -296
  3. {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/entry_points.txt +3 -2
  4. simtools/_version.py +2 -2
  5. simtools/applications/calculate_incident_angles.py +1 -4
  6. simtools/applications/convert_all_model_parameters_from_simtel.py +1 -2
  7. simtools/applications/convert_model_parameter_from_simtel.py +0 -1
  8. simtools/applications/db_generate_compound_indexes.py +4 -17
  9. simtools/applications/db_upload_model_repository.py +122 -0
  10. simtools/applications/derive_psf_parameters.py +71 -42
  11. simtools/applications/docs_produce_array_element_report.py +1 -1
  12. simtools/applications/docs_produce_calibration_reports.py +1 -1
  13. simtools/applications/docs_produce_model_parameter_reports.py +1 -1
  14. simtools/applications/docs_produce_simulation_configuration_report.py +1 -1
  15. simtools/applications/generate_corsika_histograms.py +8 -185
  16. simtools/applications/maintain_simulation_model_add_production.py +81 -0
  17. simtools/applications/merge_tables.py +1 -1
  18. simtools/applications/plot_array_layout.py +1 -2
  19. simtools/applications/plot_simtel_events.py +2 -228
  20. simtools/applications/print_version.py +8 -7
  21. simtools/applications/production_derive_statistics.py +1 -2
  22. simtools/applications/production_generate_grid.py +1 -1
  23. simtools/applications/simulate_flasher.py +74 -72
  24. simtools/applications/simulate_illuminator.py +52 -186
  25. simtools/applications/{simulate_calibration_events.py → simulate_pedestals.py} +9 -55
  26. simtools/applications/submit_model_parameter_from_external.py +0 -1
  27. simtools/applications/validate_camera_efficiency.py +0 -1
  28. simtools/applications/validate_camera_fov.py +1 -2
  29. simtools/applications/validate_cumulative_psf.py +2 -3
  30. simtools/applications/validate_file_using_schema.py +20 -12
  31. simtools/applications/validate_optics.py +2 -2
  32. simtools/camera/camera_efficiency.py +8 -11
  33. simtools/configuration/commandline_parser.py +1 -7
  34. simtools/configuration/configurator.py +0 -2
  35. simtools/corsika/corsika_config.py +9 -11
  36. simtools/corsika/corsika_histograms.py +82 -1
  37. simtools/data_model/model_data_writer.py +87 -25
  38. simtools/data_model/schema.py +61 -2
  39. simtools/data_model/validate_data.py +1 -1
  40. simtools/db/db_handler.py +103 -48
  41. simtools/db/db_model_upload.py +247 -16
  42. simtools/io/io_handler.py +31 -83
  43. simtools/job_execution/job_manager.py +45 -0
  44. simtools/layout/array_layout_utils.py +1 -5
  45. simtools/model/array_model.py +93 -42
  46. simtools/model/model_parameter.py +20 -9
  47. simtools/model/model_repository.py +197 -109
  48. simtools/model/model_utils.py +21 -6
  49. simtools/model/telescope_model.py +20 -0
  50. simtools/production_configuration/derive_corsika_limits.py +1 -1
  51. simtools/ray_tracing/incident_angles.py +7 -7
  52. simtools/ray_tracing/mirror_panel_psf.py +1 -1
  53. simtools/ray_tracing/psf_parameter_optimisation.py +1106 -565
  54. simtools/ray_tracing/ray_tracing.py +1 -3
  55. simtools/reporting/docs_read_parameters.py +171 -101
  56. simtools/resources/array_elements.yml +26 -0
  57. simtools/runners/corsika_simtel_runner.py +11 -17
  58. simtools/runners/runner_services.py +5 -6
  59. simtools/runners/simtools_runner.py +0 -2
  60. simtools/schemas/application_workflow.metaschema.yml +1 -1
  61. simtools/schemas/common_definitions.schema.yml +39 -0
  62. simtools/schemas/model_parameter.metaschema.yml +19 -13
  63. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +6 -12
  64. simtools/schemas/model_parameters/adjust_gain.schema.yml +0 -5
  65. simtools/schemas/model_parameters/altitude.schema.yml +0 -5
  66. simtools/schemas/model_parameters/array_coordinates.schema.yml +0 -5
  67. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +0 -5
  68. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +0 -7
  69. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +0 -7
  70. simtools/schemas/model_parameters/array_layouts.schema.yml +0 -5
  71. simtools/schemas/model_parameters/array_triggers.schema.yml +0 -5
  72. simtools/schemas/model_parameters/array_window.schema.yml +0 -7
  73. simtools/schemas/model_parameters/asum_clipping.schema.yml +0 -3
  74. simtools/schemas/model_parameters/asum_offset.schema.yml +0 -7
  75. simtools/schemas/model_parameters/asum_shaping.schema.yml +0 -7
  76. simtools/schemas/model_parameters/asum_threshold.schema.yml +0 -7
  77. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +0 -5
  78. simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +0 -5
  79. simtools/schemas/model_parameters/axes_offsets.schema.yml +0 -7
  80. simtools/schemas/model_parameters/calibration_devices.schema.yml +30 -0
  81. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +0 -7
  82. simtools/schemas/model_parameters/camera_body_shape.schema.yml +0 -7
  83. simtools/schemas/model_parameters/camera_config_file.schema.yml +0 -7
  84. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +0 -7
  85. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +0 -7
  86. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +0 -7
  87. simtools/schemas/model_parameters/camera_depth.schema.yml +0 -7
  88. simtools/schemas/model_parameters/camera_filter.schema.yml +0 -7
  89. simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +0 -3
  90. simtools/schemas/model_parameters/camera_pixels.schema.yml +0 -7
  91. simtools/schemas/model_parameters/camera_transmission.schema.yml +0 -7
  92. simtools/schemas/model_parameters/channels_per_chip.schema.yml +0 -7
  93. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +0 -7
  94. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +0 -5
  95. simtools/schemas/model_parameters/dark_events.schema.yml +4 -3
  96. simtools/schemas/model_parameters/default_trigger.schema.yml +0 -7
  97. simtools/schemas/model_parameters/design_model.schema.yml +0 -7
  98. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +0 -7
  99. simtools/schemas/model_parameters/disc_bins.schema.yml +0 -7
  100. simtools/schemas/model_parameters/disc_start.schema.yml +0 -7
  101. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +0 -7
  102. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +0 -7
  103. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +0 -7
  104. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +0 -7
  105. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +0 -7
  106. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +0 -7
  107. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +0 -7
  108. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +0 -7
  109. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +0 -7
  110. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +0 -7
  111. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +0 -7
  112. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -9
  113. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +0 -7
  114. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +0 -7
  115. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +0 -7
  116. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +0 -7
  117. simtools/schemas/model_parameters/dish_shape_length.schema.yml +0 -5
  118. simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -5
  119. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +0 -3
  120. simtools/schemas/model_parameters/dsum_offset.schema.yml +0 -3
  121. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +0 -3
  122. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +0 -3
  123. simtools/schemas/model_parameters/dsum_prescale.schema.yml +0 -3
  124. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +0 -3
  125. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +0 -3
  126. simtools/schemas/model_parameters/dsum_shaping.schema.yml +0 -3
  127. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +0 -3
  128. simtools/schemas/model_parameters/dsum_threshold.schema.yml +2 -12
  129. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +0 -3
  130. simtools/schemas/model_parameters/effective_focal_length.schema.yml +0 -7
  131. simtools/schemas/model_parameters/epsg_code.schema.yml +0 -5
  132. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +0 -7
  133. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +2 -9
  134. simtools/schemas/model_parameters/fadc_bins.schema.yml +0 -7
  135. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +0 -7
  136. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +0 -2
  137. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +0 -7
  138. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +0 -7
  139. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +2 -9
  140. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +0 -7
  141. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +0 -2
  142. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +0 -7
  143. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +0 -7
  144. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +0 -7
  145. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +0 -2
  146. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +0 -7
  147. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +0 -7
  148. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +0 -7
  149. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +0 -7
  150. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +0 -7
  151. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +0 -7
  152. simtools/schemas/model_parameters/fadc_long_event_threshold.schema.yml +0 -3
  153. simtools/schemas/model_parameters/fadc_long_sum_bins.schema.yml +0 -3
  154. simtools/schemas/model_parameters/fadc_long_sum_offset.schema.yml +0 -3
  155. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +0 -7
  156. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +0 -2
  157. simtools/schemas/model_parameters/fadc_mhz.schema.yml +0 -7
  158. simtools/schemas/model_parameters/fadc_noise.schema.yml +0 -7
  159. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +0 -7
  160. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +0 -7
  161. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +0 -7
  162. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +0 -7
  163. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +0 -7
  164. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +0 -7
  165. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +0 -7
  166. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +0 -7
  167. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +0 -3
  168. simtools/schemas/model_parameters/flasher_angular_distribution.schema.yml +32 -0
  169. simtools/schemas/model_parameters/flasher_angular_distribution_width.schema.yml +32 -0
  170. simtools/schemas/model_parameters/flasher_bunch_size.schema.yml +28 -0
  171. simtools/schemas/model_parameters/flasher_external_trigger.schema.yml +32 -0
  172. simtools/schemas/model_parameters/flasher_photons.schema.yml +34 -0
  173. simtools/schemas/model_parameters/flasher_position.schema.yml +43 -0
  174. simtools/schemas/model_parameters/flasher_pulse_exp_decay.schema.yml +29 -0
  175. simtools/schemas/model_parameters/flasher_pulse_offset.schema.yml +35 -0
  176. simtools/schemas/model_parameters/flasher_pulse_shape.schema.yml +30 -0
  177. simtools/schemas/model_parameters/flasher_pulse_width.schema.yml +32 -0
  178. simtools/schemas/model_parameters/flasher_type.schema.yml +28 -0
  179. simtools/schemas/model_parameters/flasher_var_photons.schema.yml +31 -0
  180. simtools/schemas/model_parameters/flasher_wavelength.schema.yml +33 -0
  181. simtools/schemas/model_parameters/flatfielding.schema.yml +0 -7
  182. simtools/schemas/model_parameters/focal_length.schema.yml +0 -7
  183. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +0 -3
  184. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +0 -3
  185. simtools/schemas/model_parameters/focus_offset.schema.yml +0 -7
  186. simtools/schemas/model_parameters/gain_variation.schema.yml +0 -7
  187. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +2 -7
  188. simtools/schemas/model_parameters/geomag_rotation.schema.yml +2 -7
  189. simtools/schemas/model_parameters/geomag_vertical.schema.yml +2 -7
  190. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +0 -5
  191. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +0 -7
  192. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +0 -7
  193. simtools/schemas/model_parameters/laser_events.schema.yml +4 -3
  194. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +4 -3
  195. simtools/schemas/model_parameters/laser_photons.schema.yml +4 -3
  196. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +4 -3
  197. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +4 -3
  198. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +4 -3
  199. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +4 -3
  200. simtools/schemas/model_parameters/laser_var_photons.schema.yml +4 -3
  201. simtools/schemas/model_parameters/laser_wavelength.schema.yml +4 -3
  202. simtools/schemas/model_parameters/led_events.schema.yml +4 -3
  203. simtools/schemas/model_parameters/led_photons.schema.yml +4 -3
  204. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +4 -3
  205. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +4 -3
  206. simtools/schemas/model_parameters/led_var_photons.schema.yml +4 -3
  207. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +0 -7
  208. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +0 -7
  209. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +0 -7
  210. simtools/schemas/model_parameters/min_photons.schema.yml +0 -7
  211. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +0 -5
  212. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +0 -7
  213. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +0 -7
  214. simtools/schemas/model_parameters/mirror_class.schema.yml +2 -9
  215. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +0 -7
  216. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +0 -5
  217. simtools/schemas/model_parameters/mirror_list.schema.yml +0 -7
  218. simtools/schemas/model_parameters/mirror_offset.schema.yml +0 -7
  219. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +0 -7
  220. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +0 -7
  221. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +0 -7
  222. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +0 -7
  223. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +0 -7
  224. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +0 -3
  225. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +0 -7
  226. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +0 -7
  227. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +0 -5
  228. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +0 -5
  229. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +0 -5
  230. simtools/schemas/model_parameters/nsb_sky_map.schema.yml +0 -5
  231. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +0 -5
  232. simtools/schemas/model_parameters/num_gains.schema.yml +0 -7
  233. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +0 -7
  234. simtools/schemas/model_parameters/optics_properties.schema.yml +0 -7
  235. simtools/schemas/model_parameters/parabolic_dish.schema.yml +0 -3
  236. simtools/schemas/model_parameters/pedestal_events.schema.yml +4 -7
  237. simtools/schemas/model_parameters/photon_delay.schema.yml +0 -7
  238. simtools/schemas/model_parameters/photons_per_run.schema.yml +4 -4
  239. simtools/schemas/model_parameters/pixel_cells.schema.yml +0 -3
  240. simtools/schemas/model_parameters/pixels_parallel.schema.yml +0 -3
  241. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +0 -7
  242. simtools/schemas/model_parameters/pm_average_gain.schema.yml +0 -5
  243. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +0 -5
  244. simtools/schemas/model_parameters/pm_gain_index.schema.yml +0 -5
  245. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +0 -7
  246. simtools/schemas/model_parameters/pm_transit_time.schema.yml +4 -9
  247. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +0 -5
  248. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +0 -7
  249. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +0 -3
  250. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +0 -3
  251. simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +0 -3
  252. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +0 -3
  253. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +0 -3
  254. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +0 -3
  255. simtools/schemas/model_parameters/qe_variation.schema.yml +0 -7
  256. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +0 -7
  257. simtools/schemas/model_parameters/random_focal_length.schema.yml +2 -7
  258. simtools/schemas/model_parameters/random_generator.schema.yml +0 -7
  259. simtools/schemas/model_parameters/random_mono_probability.schema.yml +0 -7
  260. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +0 -5
  261. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +0 -5
  262. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +0 -5
  263. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +0 -5
  264. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +0 -5
  265. simtools/schemas/model_parameters/sampled_output.schema.yml +0 -7
  266. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +0 -7
  267. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +0 -3
  268. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +0 -3
  269. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +0 -3
  270. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +0 -3
  271. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +0 -3
  272. simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +0 -3
  273. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +0 -3
  274. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +0 -3
  275. simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +0 -3
  276. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +0 -3
  277. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +0 -3
  278. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +0 -3
  279. simtools/schemas/model_parameters/stars.schema.yml +0 -5
  280. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +0 -7
  281. simtools/schemas/model_parameters/tailcut_scale.schema.yml +0 -7
  282. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +0 -7
  283. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +0 -7
  284. simtools/schemas/model_parameters/telescope_random_error.schema.yml +0 -7
  285. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +0 -7
  286. simtools/schemas/model_parameters/telescope_transmission.schema.yml +0 -7
  287. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +0 -7
  288. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +0 -7
  289. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +0 -7
  290. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +0 -7
  291. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +0 -7
  292. simtools/schemas/model_parameters/transit_time_error.schema.yml +0 -7
  293. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +0 -7
  294. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +0 -7
  295. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +0 -7
  296. simtools/schemas/model_parameters/trigger_pixels.schema.yml +0 -7
  297. simtools/schemas/production_tables.schema.yml +8 -8
  298. simtools/schemas/simulation_models_info.schema.yml +78 -0
  299. simtools/simtel/simtel_config_writer.py +88 -14
  300. simtools/simtel/simulator_array.py +44 -74
  301. simtools/simtel/simulator_light_emission.py +336 -629
  302. simtools/simtel/simulator_ray_tracing.py +2 -2
  303. simtools/simulator.py +46 -18
  304. simtools/testing/configuration.py +4 -2
  305. simtools/testing/sim_telarray_metadata.py +4 -4
  306. simtools/utils/geometry.py +34 -0
  307. simtools/version.py +111 -0
  308. simtools/{corsika/corsika_histograms_visualize.py → visualization/plot_corsika_histograms.py} +109 -0
  309. simtools/visualization/plot_psf.py +775 -0
  310. simtools/visualization/plot_simtel_events.py +284 -87
  311. simtools/applications/maintain_simulation_model_add_production_table.py +0 -71
  312. simtools/model/flasher_model.py +0 -106
  313. {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/WHEEL +0 -0
  314. {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/licenses/LICENSE +0 -0
  315. {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/top_level.txt +0 -0
@@ -132,11 +132,10 @@ def main(): # noqa: D103
132
132
  logger = logging.getLogger()
133
133
  logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
134
134
 
135
- # Output directory to save files related directly to this app
136
135
  _io_handler = io_handler.IOHandler()
137
- output_dir = _io_handler.get_output_directory(label, sub_dir="application-plots")
136
+ output_dir = _io_handler.get_output_directory()
138
137
 
139
- tel_model, site_model = initialize_simulation_models(
138
+ tel_model, site_model, _ = initialize_simulation_models(
140
139
  label=label,
141
140
  db_config=db_config,
142
141
  site=args_dict["site"],
@@ -61,12 +61,15 @@ def _parse(label, description):
61
61
 
62
62
  """
63
63
  config = configurator.Configurator(label=label, description=description)
64
- group = config.parser.add_mutually_exclusive_group(required=True)
65
- group.add_argument("--file_name", help="File to be validated")
66
- group.add_argument(
64
+ config.parser.add_argument(
65
+ "--file_name",
66
+ help="File to be validated (full path or name pattern, e.g., '*.json')",
67
+ default="*.json",
68
+ )
69
+ config.parser.add_argument(
67
70
  "--file_directory",
68
71
  help=(
69
- "Directory with json files to be validated. "
72
+ "Directory with files to be validated. "
70
73
  "If no schema file is provided, the assumption is that model "
71
74
  "parameters are validated and the schema files are taken from "
72
75
  f"{MODEL_PARAMETER_SCHEMA_PATH}."
@@ -84,6 +87,11 @@ def _parse(label, description):
84
87
  help="Require exact data type for validation",
85
88
  action="store_true",
86
89
  )
90
+ config.parser.add_argument(
91
+ "--ignore_software_version",
92
+ help="Ignore software version check.",
93
+ action="store_true",
94
+ )
87
95
  return config.initialize(paths=False)
88
96
 
89
97
 
@@ -115,11 +123,11 @@ def _get_schema_file_name(args_dict, data_dict=None):
115
123
  return schema_file
116
124
 
117
125
 
118
- def _get_json_file_list(file_directory=None, file_name=None):
119
- """Return list of json files in a directory."""
126
+ def _get_file_list(file_directory=None, file_name="*.json"):
127
+ """Return list of files in a directory."""
120
128
  file_list = []
121
129
  if file_directory is not None:
122
- file_list = list(Path(file_directory).rglob("*.json"))
130
+ file_list = list(Path(file_directory).rglob(file_name))
123
131
  if not file_list:
124
132
  raise FileNotFoundError(f"No files found in {file_directory}")
125
133
  elif file_name is not None:
@@ -137,9 +145,7 @@ def validate_dict_using_schema(args_dict, logger):
137
145
  the metadata section of the data dictionary.
138
146
 
139
147
  """
140
- for file_name in _get_json_file_list(
141
- args_dict.get("file_directory"), args_dict.get("file_name")
142
- ):
148
+ for file_name in _get_file_list(args_dict.get("file_directory"), args_dict.get("file_name")):
143
149
  try:
144
150
  data = ascii_handler.collect_data_from_file(file_name=file_name)
145
151
  except FileNotFoundError as exc:
@@ -148,7 +154,9 @@ def validate_dict_using_schema(args_dict, logger):
148
154
  try:
149
155
  for data_dict in data:
150
156
  schema.validate_dict_using_schema(
151
- data_dict, _get_schema_file_name(args_dict, data_dict)
157
+ data_dict,
158
+ _get_schema_file_name(args_dict, data_dict),
159
+ ignore_software_version=args_dict.get("ignore_software_version", False),
152
160
  )
153
161
  except Exception as exc:
154
162
  raise ValueError(f"Validation of file {file_name} failed") from exc
@@ -159,7 +167,7 @@ def validate_data_files(args_dict, logger):
159
167
  """Validate data files."""
160
168
  if args_dict.get("file_directory") is not None:
161
169
  tmp_args_dict = {}
162
- for file_name in _get_json_file_list(args_dict.get("file_directory")):
170
+ for file_name in _get_file_list(args_dict.get("file_directory")):
163
171
  tmp_args_dict["file_name"] = file_name
164
172
  parameter_name = re.sub(r"-\d+\.\d+\.\d+", "", file_name.stem)
165
173
  schema_file = schema.get_model_parameter_schema_file(f"{parameter_name}")
@@ -126,9 +126,9 @@ def main(): # noqa: D103
126
126
  logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
127
127
 
128
128
  _io_handler = io_handler.IOHandler()
129
- output_dir = _io_handler.get_output_directory(label, sub_dir="application-plots")
129
+ output_dir = _io_handler.get_output_directory()
130
130
 
131
- tel_model, site_model = initialize_simulation_models(
131
+ tel_model, site_model, _ = initialize_simulation_models(
132
132
  label=label,
133
133
  db_config=db_config,
134
134
  site=args_dict["site"],
@@ -40,14 +40,14 @@ class CameraEfficiency:
40
40
  self.label = label
41
41
 
42
42
  self.io_handler = io_handler.IOHandler()
43
- self.telescope_model, self.site_model = initialize_simulation_models(
44
- self.label,
45
- db_config,
46
- config_data["site"],
47
- config_data["telescope"],
48
- config_data["model_version"],
43
+ self.telescope_model, self.site_model, _ = initialize_simulation_models(
44
+ label=self.label,
45
+ db_config=db_config,
46
+ model_version=config_data["model_version"],
47
+ site=config_data["site"],
48
+ telescope_name=config_data["telescope"],
49
49
  )
50
- self.output_dir = self.io_handler.get_output_directory(self.label, sub_dir="plots")
50
+ self.output_dir = self.io_handler.get_output_directory()
51
51
 
52
52
  self._results = None
53
53
  self._has_results = False
@@ -101,10 +101,7 @@ class CameraEfficiency:
101
101
  label=self.label,
102
102
  )
103
103
 
104
- _file[label] = self.io_handler.get_output_directory(
105
- label=self.label,
106
- sub_dir="camera_efficiency",
107
- ).joinpath(file_name)
104
+ _file[label] = self.io_handler.get_output_directory().joinpath(file_name)
108
105
  return _file
109
106
 
110
107
  def simulate(self):
@@ -21,7 +21,7 @@ class CommandLineParser(argparse.ArgumentParser):
21
21
 
22
22
  Wrapper around standard python argparse.ArgumentParser.
23
23
 
24
- Command line arguments should be given in snake_case, e.g. input_meta.
24
+ Command line arguments should be given in snake_case, e.g. 'input_meta'.
25
25
 
26
26
  Parameters
27
27
  ----------
@@ -102,12 +102,6 @@ class CommandLineParser(argparse.ArgumentParser):
102
102
  default="./simtools-output/",
103
103
  required=False,
104
104
  )
105
- _job_group.add_argument(
106
- "--use_plain_output_path",
107
- help="use plain output path (without the tool name and dates)",
108
- action="store_true",
109
- required=False,
110
- )
111
105
  _job_group.add_argument(
112
106
  "--model_path",
113
107
  help="path pointing towards simulation model file directory",
@@ -340,8 +340,6 @@ class Configurator:
340
340
  _io_handler = io_handler.IOHandler()
341
341
  _io_handler.set_paths(
342
342
  output_path=self.config.get("output_path", None),
343
- use_plain_output_path=self.config.get("use_plain_output_path", False),
344
- data_path=self.config.get("data_path", None),
345
343
  model_path=self.config.get("model_path", None),
346
344
  )
347
345
 
@@ -114,8 +114,8 @@ class CorsikaConfig:
114
114
  return {}
115
115
 
116
116
  self.is_file_updated = False
117
- self.azimuth_angle = int(args_dict["azimuth_angle"].to("deg").value)
118
- self.zenith_angle = args_dict["zenith_angle"].to("deg").value
117
+ self.azimuth_angle = int(args_dict.get("azimuth_angle", 0.0 * u.deg).to("deg").value)
118
+ self.zenith_angle = int(args_dict.get("zenith_angle", 0.0 * u.deg).to("deg").value)
119
119
 
120
120
  self._logger.debug(
121
121
  f"Setting CORSIKA parameters from database ({args_dict['model_version']})"
@@ -563,8 +563,9 @@ class CorsikaConfig:
563
563
  if self.is_file_updated:
564
564
  self._logger.debug(f"CORSIKA input file already updated: {self.config_file_path}")
565
565
  return self.config_file_path
566
- _output_generic_file_name = self.set_output_file_and_directory(use_multipipe=use_multipipe)
567
566
  self._logger.info(f"Exporting CORSIKA input file to {self.config_file_path}")
567
+ _output_generic_file_name = self.set_output_file_and_directory(use_multipipe=use_multipipe)
568
+ self._logger.info(f"Output generic file name: {_output_generic_file_name}")
568
569
 
569
570
  with open(self.config_file_path, "w", encoding="utf-8") as file:
570
571
  file.write("\n* [ RUN PARAMETERS ]\n")
@@ -712,13 +713,10 @@ class CorsikaConfig:
712
713
  str
713
714
  Output file name.
714
715
  """
715
- sub_dir = "corsika_sim_telarray" if use_multipipe else "corsika"
716
- config_file_name = self.get_corsika_config_file_name(file_type="config")
717
- file_directory = self.io_handler.get_output_directory(label=self.label, sub_dir=sub_dir)
718
- self._logger.debug(f"Creating directory {file_directory}")
719
- file_directory.mkdir(parents=True, exist_ok=True)
720
- self.config_file_path = file_directory.joinpath(config_file_name)
721
-
716
+ self.config_file_path = self.io_handler.get_output_file(
717
+ file_name=self.get_corsika_config_file_name(file_type="config"),
718
+ sub_dir="corsika_sim_telarray" if use_multipipe else "corsika",
719
+ )
722
720
  return self.get_corsika_config_file_name(file_type="output_generic")
723
721
 
724
722
  def _write_seeds(self, file, use_test_seeds=False):
@@ -748,7 +746,7 @@ class CorsikaConfig:
748
746
  Piece of text to be added to the CORSIKA input file.
749
747
  """
750
748
  corsika_input_list = ""
751
- for telescope_name, telescope in self.array_model.telescope_model.items():
749
+ for telescope_name, telescope in self.array_model.telescope_models.items():
752
750
  positions = telescope.get_parameter_value_with_unit("array_element_position_ground")
753
751
  corsika_input_list += "TELESCOPE"
754
752
  for pos in positions:
@@ -22,6 +22,7 @@ from simtools.io.ascii_handler import collect_data_from_file
22
22
  from simtools.io.hdf5_handler import fill_hdf5_table
23
23
  from simtools.utils.geometry import convert_2d_to_radial_distr, rotate
24
24
  from simtools.utils.names import sanitize_name
25
+ from simtools.visualization import plot_corsika_histograms as visualize
25
26
 
26
27
  X_AXIS_STRING = "x axis"
27
28
  Y_AXIS_STRING = "y axis"
@@ -66,7 +67,7 @@ class CorsikaHistograms:
66
67
  raise FileNotFoundError
67
68
 
68
69
  self.io_handler = io_handler.IOHandler()
69
- _default_output_path = self.io_handler.get_output_directory(self.label, "corsika")
70
+ _default_output_path = self.io_handler.get_output_directory("corsika")
70
71
 
71
72
  if output_path is None:
72
73
  self.output_path = _default_output_path
@@ -111,6 +112,86 @@ class CorsikaHistograms:
111
112
  self.read_event_information()
112
113
  self._initialize_header()
113
114
 
115
+ def parse_telescope_indices(self, indices_arg):
116
+ """Return telescope indices as ndarray[int] or None.
117
+
118
+ Accepts None, a sequence of strings/ints. Raises ValueError on invalid input.
119
+ """
120
+ if indices_arg is None:
121
+ return None
122
+ try:
123
+ return np.array(indices_arg).astype(int)
124
+ except ValueError as exc:
125
+ msg = (
126
+ f"{indices_arg} not a valid input. Please use integer numbers for telescope_indices"
127
+ )
128
+ self._logger.error(msg)
129
+ raise ValueError(msg) from exc
130
+
131
+ def should_overwrite(
132
+ self, write_hdf5: bool, event1d: list | None, event2d: list | None
133
+ ) -> bool:
134
+ """Return True if output HDF5 exists and any writing flag is requested."""
135
+ exists = Path(self.hdf5_file_name).exists()
136
+ if exists and (write_hdf5 or bool(event1d) or bool(event2d)):
137
+ self._logger.warning(
138
+ f"Output hdf5 file {self.hdf5_file_name} already exists. Overwriting it."
139
+ )
140
+ return True
141
+ return False
142
+
143
+ def run_export_pipeline(
144
+ self,
145
+ *,
146
+ individual_telescopes: bool,
147
+ hist_config,
148
+ indices_arg,
149
+ write_pdf: bool,
150
+ write_hdf5: bool,
151
+ event1d: list | None,
152
+ event2d: list | None,
153
+ test: bool = False,
154
+ ) -> dict:
155
+ """Run the full histogram export pipeline and return output artifact paths.
156
+
157
+ Returns a dict with optional keys: pdf_photons, pdf_event1d, pdf_event2d.
158
+ """
159
+ outputs: dict[str, Path | None] = {
160
+ "pdf_photons": None,
161
+ "pdf_event_1d": None,
162
+ "pdf_event_2d": None,
163
+ }
164
+
165
+ indices = self.parse_telescope_indices(indices_arg)
166
+ overwrite = self.should_overwrite(write_hdf5, event1d, event2d)
167
+
168
+ self.set_histograms(
169
+ telescope_indices=indices,
170
+ individual_telescopes=individual_telescopes,
171
+ hist_config=hist_config,
172
+ )
173
+
174
+ if write_pdf:
175
+ pdf_path = visualize.export_all_photon_figures_pdf(self, test=test)
176
+ outputs["pdf_photons"] = pdf_path
177
+ if write_hdf5:
178
+ self.export_histograms(overwrite=overwrite)
179
+
180
+ if event1d is not None:
181
+ outputs["pdf_event_1d"] = visualize.derive_event_1d_histograms(
182
+ self, event1d, pdf=write_pdf, hdf5=write_hdf5, overwrite=not write_hdf5
183
+ )
184
+ if event2d is not None:
185
+ outputs["pdf_event_2d"] = visualize.derive_event_2d_histograms(
186
+ self,
187
+ event2d,
188
+ pdf=write_pdf,
189
+ hdf5=write_hdf5,
190
+ overwrite=not (write_hdf5 or bool(event1d)),
191
+ )
192
+
193
+ return outputs
194
+
114
195
  @property
115
196
  def hdf5_file_name(self):
116
197
  """
@@ -3,6 +3,7 @@
3
3
  import logging
4
4
  from pathlib import Path
5
5
 
6
+ import packaging.version
6
7
  from astropy.io.registry.base import IORegistryError
7
8
 
8
9
  import simtools.utils.general as gen
@@ -29,8 +30,6 @@ class ModelDataWriter:
29
30
  Dictionary with configuration parameters.
30
31
  output_path: str or Path
31
32
  Path to output file.
32
- use_plain_output_path: bool
33
- Use plain output path.
34
33
  args_dict: dict
35
34
  Dictionary with configuration parameters.
36
35
 
@@ -41,7 +40,6 @@ class ModelDataWriter:
41
40
  product_data_file=None,
42
41
  product_data_format=None,
43
42
  output_path=None,
44
- use_plain_output_path=True,
45
43
  args_dict=None,
46
44
  ):
47
45
  """Initialize model data writer."""
@@ -50,11 +48,8 @@ class ModelDataWriter:
50
48
  self.schema_dict = {}
51
49
  if args_dict is not None:
52
50
  output_path = args_dict.get("output_path", output_path)
53
- use_plain_output_path = args_dict.get("use_plain_output_path", use_plain_output_path)
54
51
  if output_path is not None:
55
- self.io_handler.set_paths(
56
- output_path=output_path, use_plain_output_path=use_plain_output_path
57
- )
52
+ self.io_handler.set_paths(output_path=output_path)
58
53
  try:
59
54
  self.product_data_file = self.io_handler.get_output_file(file_name=product_data_file)
60
55
  except TypeError:
@@ -104,9 +99,10 @@ class ModelDataWriter:
104
99
  parameter_version,
105
100
  output_file,
106
101
  output_path=None,
107
- use_plain_output_path=False,
108
102
  metadata_input_dict=None,
109
103
  db_config=None,
104
+ unit=None,
105
+ meta_parameter=False,
110
106
  ):
111
107
  """
112
108
  Generate DB-style model parameter dict and write it to json file.
@@ -125,12 +121,12 @@ class ModelDataWriter:
125
121
  Name of output file.
126
122
  output_path: str or Path
127
123
  Path to output file.
128
- use_plain_output_path: bool
129
- Use plain output path.
130
124
  metadata_input_dict: dict
131
125
  Input to metadata collector.
132
126
  db_config: dict
133
127
  Database configuration. If not None, check if parameter with the same version exists.
128
+ unit: str
129
+ Unit of the parameter value (if applicable and value is not of type astropy Quantity).
134
130
 
135
131
  Returns
136
132
  -------
@@ -142,7 +138,6 @@ class ModelDataWriter:
142
138
  product_data_format="json",
143
139
  args_dict=None,
144
140
  output_path=output_path,
145
- use_plain_output_path=use_plain_output_path,
146
141
  )
147
142
  if db_config is not None:
148
143
  writer.check_db_for_existing_parameter(
@@ -160,7 +155,13 @@ class ModelDataWriter:
160
155
  )
161
156
 
162
157
  _json_dict = writer.get_validated_parameter_dict(
163
- parameter_name, value, instrument, parameter_version, unique_id
158
+ parameter_name,
159
+ value,
160
+ instrument,
161
+ parameter_version,
162
+ unique_id,
163
+ unit=unit,
164
+ meta_parameter=meta_parameter,
164
165
  )
165
166
  writer.write_dict_to_model_parameter_json(output_file, _json_dict)
166
167
  return _json_dict
@@ -210,6 +211,8 @@ class ModelDataWriter:
210
211
  parameter_version,
211
212
  unique_id=None,
212
213
  schema_version=None,
214
+ unit=None,
215
+ meta_parameter=False,
213
216
  ):
214
217
  """
215
218
  Get validated parameter dictionary.
@@ -226,6 +229,12 @@ class ModelDataWriter:
226
229
  Version of the parameter.
227
230
  schema_version: str
228
231
  Version of the schema.
232
+ unique_id: str
233
+ Unique ID of the parameter set (from metadata).
234
+ unit: str
235
+ Unit of the parameter value (if applicable and value is not an astropy Quantity).
236
+ meta_parameter: bool
237
+ Setting for meta parameter flag.
229
238
 
230
239
  Returns
231
240
  -------
@@ -233,10 +242,10 @@ class ModelDataWriter:
233
242
  Validated parameter dictionary.
234
243
  """
235
244
  self._logger.debug(f"Getting validated parameter dictionary for {instrument}")
236
- schema_file = schema.get_model_parameter_schema_file(parameter_name)
237
- self.schema_dict = ascii_handler.collect_data_from_file(schema_file)
245
+ self.schema_dict, schema_file = self._read_schema_dict(parameter_name, schema_version)
238
246
 
239
- value, unit = value_conversion.split_value_and_unit(value)
247
+ if unit is None:
248
+ value, unit = value_conversion.split_value_and_unit(value)
240
249
 
241
250
  data_dict = {
242
251
  "schema_version": schema.get_model_parameter_schema_version(schema_version),
@@ -249,10 +258,8 @@ class ModelDataWriter:
249
258
  "unit": unit,
250
259
  "type": self._get_parameter_type(),
251
260
  "file": self._parameter_is_a_file(),
252
- "meta_parameter": False,
253
- "model_parameter_schema_version": self.schema_dict.get(
254
- "model_parameter_schema_version", "0.1.0"
255
- ),
261
+ "meta_parameter": meta_parameter,
262
+ "model_parameter_schema_version": self.schema_dict.get("schema_version", "0.1.0"),
256
263
  }
257
264
  return self.validate_and_transform(
258
265
  product_data_dict=data_dict,
@@ -260,19 +267,74 @@ class ModelDataWriter:
260
267
  is_model_parameter=True,
261
268
  )
262
269
 
270
+ def _read_schema_dict(self, parameter_name, schema_version):
271
+ """
272
+ Read schema dict for given parameter name and version.
273
+
274
+ Use newest schema version if schema_version is None.
275
+
276
+ Parameters
277
+ ----------
278
+ parameter_name: str
279
+ Name of the parameter.
280
+ schema_version: str
281
+ Schema version.
282
+
283
+ Returns
284
+ -------
285
+ dict
286
+ Schema dictionary.
287
+ """
288
+ schema_file = schema.get_model_parameter_schema_file(parameter_name)
289
+ schemas = ascii_handler.collect_data_from_file(schema_file)
290
+ if isinstance(schemas, list):
291
+ if schema_version is None:
292
+ return self._find_highest_schema_version(schemas), schema_file
293
+ for entry in schemas:
294
+ if entry.get("schema_version") == schema_version:
295
+ return entry, schema_file
296
+ else:
297
+ return schemas, schema_file
298
+
299
+ raise ValueError(f"Schema version {schema_version} not found for {parameter_name}")
300
+
301
+ def _find_highest_schema_version(self, schema_list):
302
+ """
303
+ Find entry with highest schema_version in a list of schema dicts.
304
+
305
+ Parameters
306
+ ----------
307
+ schema_list: list
308
+ List of schema dictionaries.
309
+
310
+ Returns
311
+ -------
312
+ dict
313
+ Schema dictionary with highest schema_version.
314
+ """
315
+ try:
316
+ valid_entries = [entry for entry in schema_list if "schema_version" in entry]
317
+ except TypeError as exc:
318
+ raise TypeError("No valid schema versions found in the list.") from exc
319
+ return max(valid_entries, key=lambda e: packaging.version.Version(e["schema_version"]))
320
+
263
321
  def _get_parameter_type(self):
264
322
  """
265
323
  Return parameter type from schema.
266
324
 
325
+ Reduce list of types to single type if all types are the same.
326
+
267
327
  Returns
268
328
  -------
269
- str
329
+ str or list[str]
270
330
  Parameter type
271
331
  """
272
- _parameter_type = []
273
- for data in self.schema_dict["data"]:
274
- _parameter_type.append(data["type"])
275
- return _parameter_type if len(_parameter_type) > 1 else _parameter_type[0]
332
+ _parameter_type = [data["type"] for data in self.schema_dict["data"]]
333
+ return (
334
+ _parameter_type[0]
335
+ if all(t == _parameter_type[0] for t in _parameter_type)
336
+ else _parameter_type
337
+ )
276
338
 
277
339
  def _parameter_is_a_file(self):
278
340
  """
@@ -399,7 +461,7 @@ class ModelDataWriter:
399
461
  ascii_handler.write_data_to_file(
400
462
  data=data_dict,
401
463
  output_file=self.io_handler.get_output_file(file_name),
402
- sort_keys=False,
464
+ sort_keys=True,
403
465
  numpy_types=True,
404
466
  )
405
467
 
@@ -4,9 +4,12 @@ import logging
4
4
  from pathlib import Path
5
5
 
6
6
  import jsonschema
7
+ from packaging.specifiers import SpecifierSet
8
+ from packaging.version import Version
7
9
  from referencing import Registry, Resource
8
10
 
9
11
  import simtools.utils.general as gen
12
+ from simtools import version
10
13
  from simtools.constants import (
11
14
  METADATA_JSON_SCHEMA,
12
15
  MODEL_PARAMETER_METASCHEMA,
@@ -66,7 +69,7 @@ def get_model_parameter_schema_file(parameter):
66
69
 
67
70
  def get_model_parameter_schema_version(schema_version=None):
68
71
  """
69
- Validate and return schema versions.
72
+ Validate and return schema versions.
70
73
 
71
74
  If no schema_version is given, the most recent version is provided.
72
75
 
@@ -92,7 +95,9 @@ def get_model_parameter_schema_version(schema_version=None):
92
95
  raise ValueError(f"Schema version {schema_version} not found in {MODEL_PARAMETER_METASCHEMA}.")
93
96
 
94
97
 
95
- def validate_dict_using_schema(data, schema_file=None, json_schema=None):
98
+ def validate_dict_using_schema(
99
+ data, schema_file=None, json_schema=None, ignore_software_version=False
100
+ ):
96
101
  """
97
102
  Validate a data dictionary against a schema.
98
103
 
@@ -102,6 +107,10 @@ def validate_dict_using_schema(data, schema_file=None, json_schema=None):
102
107
  dictionary to be validated
103
108
  schema_file (dict)
104
109
  schema used for validation
110
+ json_schema (dict)
111
+ schema used for validation
112
+ ignore_software_version: bool
113
+ If True, ignore software version check.
105
114
 
106
115
  Raises
107
116
  ------
@@ -115,6 +124,8 @@ def validate_dict_using_schema(data, schema_file=None, json_schema=None):
115
124
  if json_schema is None:
116
125
  json_schema = load_schema(schema_file, get_schema_version_from_data(data))
117
126
 
127
+ _validate_deprecation_and_version(data, ignore_software_version)
128
+
118
129
  validator = jsonschema.Draft6Validator(
119
130
  schema=json_schema,
120
131
  format_checker=format_checkers.format_checker,
@@ -294,3 +305,51 @@ def _add_array_elements(key, schema):
294
305
 
295
306
  recursive_search(schema, key)
296
307
  return schema
308
+
309
+
310
+ def _validate_deprecation_and_version(
311
+ data, software_name="simtools", ignore_software_version=False
312
+ ):
313
+ """
314
+ Check if data contains deprecated parameters or version mismatches.
315
+
316
+ Parameters
317
+ ----------
318
+ data: dict
319
+ Data dictionary to check.
320
+ software_name: str
321
+ Name of the software to check version against.
322
+ ignore_software_version: bool
323
+ If True, ignore software version check.
324
+ """
325
+ if not isinstance(data, dict):
326
+ return
327
+
328
+ if data.get("deprecated", False):
329
+ note = data.get("deprecation_note", "(no deprecation note provided)")
330
+ _logger.warning(f"Data is deprecated. Note: {note}")
331
+
332
+ def check_version(sw):
333
+ constraint = sw.get("version")
334
+ if constraint is None:
335
+ return
336
+ constraint = constraint.strip()
337
+ spec = SpecifierSet(constraint, prereleases=True)
338
+ if Version(version.__version__) in spec:
339
+ _logger.debug(
340
+ f"Version {version.__version__} of {software_name} matches constraint {constraint}."
341
+ )
342
+ else:
343
+ msg = (
344
+ f"Version {version.__version__} of {software_name} "
345
+ f"does not match constraint {constraint}."
346
+ )
347
+ if ignore_software_version:
348
+ _logger.warning(f"{msg}, but version check is ignored.")
349
+ return
350
+ raise ValueError(msg)
351
+
352
+ for sw in data.get("simulation_software", []):
353
+ if sw.get("name") == software_name:
354
+ check_version(sw)
355
+ break
@@ -232,7 +232,7 @@ class DataValidator:
232
232
  else:
233
233
  self._check_data_type(np.array(value).dtype, index, value)
234
234
 
235
- if self.data_dict.get("type") not in ("string", "dict", "file"):
235
+ if self._get_data_description(index).get("type", None) not in ("string", "dict", "file"):
236
236
  self._check_for_not_a_number(value, index)
237
237
  value, unit = self._check_and_convert_units(value, unit, index)
238
238
  for range_type in ("allowed_range", "required_range"):