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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/METADATA +26 -69
  2. gammasimtools-0.19.0.dist-info/RECORD +393 -0
  3. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/entry_points.txt +9 -2
  4. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/licenses/LICENSE +1 -1
  5. simtools/_version.py +16 -3
  6. simtools/applications/calculate_trigger_rate.py +1 -1
  7. simtools/applications/convert_all_model_parameters_from_simtel.py +4 -3
  8. simtools/applications/convert_geo_coordinates_of_array_elements.py +3 -3
  9. simtools/applications/db_add_value_from_json_to_db.py +2 -1
  10. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +8 -13
  11. simtools/applications/db_generate_compound_indexes.py +61 -0
  12. simtools/applications/db_get_file_from_db.py +1 -1
  13. simtools/applications/db_get_parameter_from_db.py +4 -4
  14. simtools/applications/db_inspect_databases.py +20 -10
  15. simtools/applications/derive_mirror_rnda.py +17 -11
  16. simtools/applications/derive_psf_parameters.py +59 -309
  17. simtools/applications/docs_produce_array_element_report.py +1 -1
  18. simtools/applications/docs_produce_calibration_reports.py +1 -1
  19. simtools/applications/docs_produce_model_parameter_reports.py +1 -1
  20. simtools/applications/docs_produce_simulation_configuration_report.py +1 -1
  21. simtools/applications/generate_corsika_histograms.py +1 -1
  22. simtools/applications/generate_default_metadata.py +8 -24
  23. simtools/applications/generate_sim_telarray_histograms.py +1 -1
  24. simtools/applications/generate_simtel_event_data.py +11 -11
  25. simtools/applications/maintain_simulation_model_add_production_table.py +71 -0
  26. simtools/applications/maintain_simulation_model_compare_productions.py +98 -0
  27. simtools/applications/{verify_simulation_model_production_tables.py → maintain_simulation_model_verify_production_tables.py} +9 -1
  28. simtools/applications/merge_tables.py +2 -2
  29. simtools/applications/plot_array_layout.py +3 -3
  30. simtools/applications/plot_simtel_events.py +379 -0
  31. simtools/applications/plot_tabular_data.py +9 -2
  32. simtools/applications/plot_tabular_data_for_model_parameter.py +2 -1
  33. simtools/applications/print_version.py +8 -9
  34. simtools/applications/production_derive_corsika_limits.py +6 -7
  35. simtools/applications/production_derive_statistics.py +1 -1
  36. simtools/applications/production_generate_grid.py +2 -2
  37. simtools/applications/production_merge_corsika_limits.py +214 -0
  38. simtools/applications/run_application.py +47 -113
  39. simtools/applications/simulate_calibration_events.py +166 -0
  40. simtools/applications/simulate_flasher.py +141 -0
  41. simtools/applications/{simulate_light_emission.py → simulate_illuminator.py} +35 -99
  42. simtools/applications/simulate_prod.py +6 -24
  43. simtools/applications/simulate_prod_htcondor_generator.py +7 -0
  44. simtools/applications/submit_array_layouts.py +2 -1
  45. simtools/applications/submit_model_parameter_from_external.py +1 -1
  46. simtools/applications/validate_camera_efficiency.py +30 -12
  47. simtools/applications/validate_camera_fov.py +1 -1
  48. simtools/applications/validate_cumulative_psf.py +1 -1
  49. simtools/applications/validate_file_using_schema.py +2 -1
  50. simtools/applications/validate_optics.py +1 -1
  51. simtools/camera/camera_efficiency.py +61 -45
  52. simtools/camera/single_photon_electron_spectrum.py +1 -1
  53. simtools/configuration/commandline_parser.py +29 -0
  54. simtools/configuration/configurator.py +4 -4
  55. simtools/corsika/corsika_config.py +45 -25
  56. simtools/corsika/corsika_histograms.py +6 -5
  57. simtools/data_model/data_reader.py +2 -3
  58. simtools/data_model/metadata_collector.py +32 -36
  59. simtools/data_model/metadata_model.py +15 -12
  60. simtools/data_model/model_data_writer.py +13 -32
  61. simtools/data_model/schema.py +74 -24
  62. simtools/data_model/validate_data.py +34 -9
  63. simtools/db/db_handler.py +43 -37
  64. simtools/db/db_model_upload.py +3 -3
  65. simtools/dependencies.py +88 -25
  66. simtools/io/ascii_handler.py +279 -0
  67. simtools/{io_operations → io}/io_handler.py +25 -3
  68. simtools/job_execution/htcondor_script_generator.py +15 -4
  69. simtools/layout/array_layout.py +1 -1
  70. simtools/layout/array_layout_utils.py +14 -7
  71. simtools/model/array_model.py +23 -4
  72. simtools/model/flasher_model.py +106 -0
  73. simtools/model/model_parameter.py +4 -4
  74. simtools/model/model_repository.py +197 -2
  75. simtools/model/telescope_model.py +3 -1
  76. simtools/production_configuration/derive_corsika_limits.py +361 -427
  77. simtools/production_configuration/derive_production_statistics_handler.py +7 -6
  78. simtools/production_configuration/generate_production_grid.py +9 -11
  79. simtools/production_configuration/merge_corsika_limits.py +528 -0
  80. simtools/ray_tracing/mirror_panel_psf.py +1 -0
  81. simtools/ray_tracing/psf_parameter_optimisation.py +792 -0
  82. simtools/ray_tracing/ray_tracing.py +6 -2
  83. simtools/reporting/docs_read_parameters.py +150 -62
  84. simtools/runners/corsika_runner.py +1 -1
  85. simtools/runners/corsika_simtel_runner.py +14 -5
  86. simtools/runners/runner_services.py +10 -5
  87. simtools/runners/simtools_runner.py +267 -0
  88. simtools/schemas/application_workflow.metaschema.yml +101 -68
  89. simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +1 -1
  90. simtools/schemas/input/single_pe_spectrum.schema.yml +1 -1
  91. simtools/schemas/metadata.metaschema.yml +577 -3
  92. simtools/schemas/model_parameter.metaschema.yml +6 -6
  93. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +2 -2
  94. simtools/schemas/model_parameters/adjust_gain.schema.yml +1 -1
  95. simtools/schemas/model_parameters/altitude.schema.yml +1 -1
  96. simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
  97. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +1 -1
  98. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +1 -1
  99. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
  100. simtools/schemas/model_parameters/array_layouts.schema.yml +1 -1
  101. simtools/schemas/model_parameters/array_triggers.schema.yml +1 -1
  102. simtools/schemas/model_parameters/array_window.schema.yml +1 -1
  103. simtools/schemas/model_parameters/asum_clipping.schema.yml +1 -1
  104. simtools/schemas/model_parameters/asum_offset.schema.yml +1 -1
  105. simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
  106. simtools/schemas/model_parameters/asum_threshold.schema.yml +1 -1
  107. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +1 -1
  108. simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +1 -1
  109. simtools/schemas/model_parameters/axes_offsets.schema.yml +1 -1
  110. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +1 -1
  111. simtools/schemas/model_parameters/camera_body_shape.schema.yml +1 -1
  112. simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
  113. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +1 -1
  114. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +1 -1
  115. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
  116. simtools/schemas/model_parameters/camera_depth.schema.yml +1 -1
  117. simtools/schemas/model_parameters/camera_filter.schema.yml +1 -1
  118. simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +1 -1
  119. simtools/schemas/model_parameters/camera_pixels.schema.yml +1 -1
  120. simtools/schemas/model_parameters/camera_transmission.schema.yml +1 -1
  121. simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
  122. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +1 -1
  123. simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +1 -1
  124. simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +1 -1
  125. simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +1 -1
  126. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +1 -1
  127. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +1 -1
  128. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +1 -1
  129. simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +1 -1
  130. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +1 -1
  131. simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +1 -1
  132. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +3 -3
  133. simtools/schemas/model_parameters/dark_events.schema.yml +1 -1
  134. simtools/schemas/model_parameters/default_trigger.schema.yml +1 -1
  135. simtools/schemas/model_parameters/design_model.schema.yml +1 -1
  136. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +1 -1
  137. simtools/schemas/model_parameters/disc_bins.schema.yml +1 -1
  138. simtools/schemas/model_parameters/disc_start.schema.yml +1 -1
  139. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +1 -1
  140. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +1 -1
  141. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +1 -1
  142. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +1 -1
  143. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +1 -1
  144. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +1 -1
  145. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +1 -1
  146. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +1 -1
  147. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +1 -1
  148. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +1 -1
  149. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +1 -1
  150. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -1
  151. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +1 -1
  152. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +1 -1
  153. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +1 -1
  154. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +1 -1
  155. simtools/schemas/model_parameters/dish_shape_length.schema.yml +1 -1
  156. simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -1
  157. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +1 -1
  158. simtools/schemas/model_parameters/dsum_offset.schema.yml +1 -1
  159. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +1 -1
  160. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +1 -1
  161. simtools/schemas/model_parameters/dsum_prescale.schema.yml +1 -1
  162. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +1 -1
  163. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +1 -1
  164. simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
  165. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +1 -1
  166. simtools/schemas/model_parameters/dsum_threshold.schema.yml +2 -2
  167. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +1 -1
  168. simtools/schemas/model_parameters/effective_focal_length.schema.yml +1 -1
  169. simtools/schemas/model_parameters/epsg_code.schema.yml +1 -1
  170. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +1 -1
  171. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +1 -1
  172. simtools/schemas/model_parameters/fadc_bins.schema.yml +1 -1
  173. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
  174. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
  175. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +1 -1
  176. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +1 -1
  177. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +1 -1
  178. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
  179. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
  180. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +1 -1
  181. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +1 -1
  182. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +1 -1
  183. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +1 -1
  184. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +1 -1
  185. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +1 -1
  186. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +1 -1
  187. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +1 -1
  188. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +1 -1
  189. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +1 -1
  190. simtools/schemas/model_parameters/fadc_long_event_threshold.schema.yml +35 -0
  191. simtools/schemas/model_parameters/fadc_long_sum_bins.schema.yml +41 -0
  192. simtools/schemas/model_parameters/fadc_long_sum_offset.schema.yml +38 -0
  193. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +1 -1
  194. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +1 -1
  195. simtools/schemas/model_parameters/fadc_mhz.schema.yml +1 -1
  196. simtools/schemas/model_parameters/fadc_noise.schema.yml +1 -1
  197. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +1 -1
  198. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +1 -1
  199. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +1 -1
  200. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +1 -1
  201. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +1 -1
  202. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +1 -1
  203. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +1 -1
  204. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +1 -1
  205. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  206. simtools/schemas/model_parameters/flatfielding.schema.yml +1 -1
  207. simtools/schemas/model_parameters/focal_length.schema.yml +1 -1
  208. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +1 -1
  209. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +1 -1
  210. simtools/schemas/model_parameters/focus_offset.schema.yml +1 -1
  211. simtools/schemas/model_parameters/gain_variation.schema.yml +1 -1
  212. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +1 -1
  213. simtools/schemas/model_parameters/geomag_rotation.schema.yml +1 -1
  214. simtools/schemas/model_parameters/geomag_vertical.schema.yml +1 -1
  215. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +1 -1
  216. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
  217. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
  218. simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
  219. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +1 -1
  220. simtools/schemas/model_parameters/laser_photons.schema.yml +1 -1
  221. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +1 -1
  222. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +1 -1
  223. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +1 -1
  224. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +1 -1
  225. simtools/schemas/model_parameters/laser_var_photons.schema.yml +1 -1
  226. simtools/schemas/model_parameters/laser_wavelength.schema.yml +1 -1
  227. simtools/schemas/model_parameters/led_events.schema.yml +1 -1
  228. simtools/schemas/model_parameters/led_photons.schema.yml +1 -1
  229. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +1 -1
  230. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +1 -1
  231. simtools/schemas/model_parameters/led_var_photons.schema.yml +1 -1
  232. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
  233. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +50 -1
  234. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
  235. simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
  236. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +1 -1
  237. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +1 -1
  238. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +1 -1
  239. simtools/schemas/model_parameters/mirror_class.schema.yml +1 -1
  240. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +1 -1
  241. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +1 -1
  242. simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
  243. simtools/schemas/model_parameters/mirror_offset.schema.yml +1 -1
  244. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +1 -1
  245. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +1 -1
  246. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +1 -1
  247. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +1 -1
  248. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +1 -1
  249. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +1 -1
  250. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +1 -1
  251. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +1 -1
  252. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +1 -1
  253. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
  254. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +1 -1
  255. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +1 -1
  256. simtools/schemas/model_parameters/nsb_sky_map.schema.yml +1 -1
  257. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +1 -1
  258. simtools/schemas/model_parameters/num_gains.schema.yml +1 -1
  259. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +1 -1
  260. simtools/schemas/model_parameters/optics_properties.schema.yml +1 -1
  261. simtools/schemas/model_parameters/parabolic_dish.schema.yml +1 -1
  262. simtools/schemas/model_parameters/pedestal_events.schema.yml +1 -1
  263. simtools/schemas/model_parameters/photon_delay.schema.yml +1 -1
  264. simtools/schemas/model_parameters/photons_per_run.schema.yml +1 -1
  265. simtools/schemas/model_parameters/pixel_cells.schema.yml +1 -1
  266. simtools/schemas/model_parameters/pixels_parallel.schema.yml +1 -1
  267. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +1 -1
  268. simtools/schemas/model_parameters/pm_average_gain.schema.yml +1 -1
  269. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +1 -1
  270. simtools/schemas/model_parameters/pm_gain_index.schema.yml +1 -1
  271. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +1 -1
  272. simtools/schemas/model_parameters/pm_transit_time.schema.yml +1 -1
  273. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +1 -1
  274. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +1 -1
  275. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +1 -1
  276. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +1 -1
  277. simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +11 -1
  278. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +1 -1
  279. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +1 -1
  280. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
  281. simtools/schemas/model_parameters/qe_variation.schema.yml +1 -1
  282. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +1 -1
  283. simtools/schemas/model_parameters/random_focal_length.schema.yml +1 -1
  284. simtools/schemas/model_parameters/random_generator.schema.yml +1 -1
  285. simtools/schemas/model_parameters/random_mono_probability.schema.yml +1 -1
  286. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +1 -1
  287. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +1 -1
  288. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +1 -1
  289. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +1 -1
  290. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +1 -1
  291. simtools/schemas/model_parameters/sampled_output.schema.yml +1 -1
  292. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +1 -1
  293. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +1 -1
  294. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
  295. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
  296. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +1 -1
  297. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +1 -1
  298. simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +11 -1
  299. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +1 -1
  300. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +1 -1
  301. simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +11 -1
  302. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
  303. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +1 -1
  304. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +1 -1
  305. simtools/schemas/model_parameters/stars.schema.yml +1 -1
  306. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
  307. simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
  308. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +1 -1
  309. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +1 -1
  310. simtools/schemas/model_parameters/telescope_random_error.schema.yml +1 -1
  311. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +1 -1
  312. simtools/schemas/model_parameters/telescope_transmission.schema.yml +1 -1
  313. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +1 -1
  314. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +1 -1
  315. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +1 -1
  316. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +1 -1
  317. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +1 -1
  318. simtools/schemas/model_parameters/transit_time_error.schema.yml +1 -1
  319. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +1 -1
  320. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +1 -1
  321. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +1 -1
  322. simtools/schemas/model_parameters/trigger_pixels.schema.yml +1 -1
  323. simtools/schemas/plot_configuration.metaschema.yml +5 -2
  324. simtools/schemas/production_configuration_metrics.schema.yml +12 -2
  325. simtools/schemas/production_tables.schema.yml +2 -2
  326. simtools/simtel/simtel_config_reader.py +2 -2
  327. simtools/simtel/simtel_config_writer.py +16 -4
  328. simtools/simtel/simtel_io_event_histograms.py +746 -0
  329. simtools/simtel/simtel_io_event_reader.py +15 -42
  330. simtools/simtel/simtel_io_event_writer.py +9 -9
  331. simtools/simtel/simtel_io_histogram.py +3 -1
  332. simtools/simtel/simtel_io_histograms.py +7 -3
  333. simtools/simtel/simtel_table_reader.py +92 -10
  334. simtools/simtel/simulator_array.py +138 -10
  335. simtools/simtel/simulator_camera_efficiency.py +32 -23
  336. simtools/simtel/simulator_light_emission.py +437 -271
  337. simtools/simtel/simulator_ray_tracing.py +1 -1
  338. simtools/simulator.py +105 -147
  339. simtools/testing/configuration.py +24 -26
  340. simtools/testing/helpers.py +2 -2
  341. simtools/testing/log_inspector.py +50 -0
  342. simtools/testing/validate_output.py +87 -37
  343. simtools/utils/general.py +125 -255
  344. simtools/utils/geometry.py +36 -0
  345. simtools/utils/names.py +1 -1
  346. simtools/visualization/legend_handlers.py +180 -264
  347. simtools/visualization/plot_array_layout.py +20 -8
  348. simtools/visualization/plot_pixels.py +1 -1
  349. simtools/visualization/plot_tables.py +133 -37
  350. simtools/visualization/simtel_event_plots.py +816 -0
  351. simtools/visualization/visualize.py +4 -101
  352. gammasimtools-0.18.0.dist-info/RECORD +0 -376
  353. simtools/production_configuration/derive_corsika_limits_grid.py +0 -232
  354. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/WHEEL +0 -0
  355. {gammasimtools-0.18.0.dist-info → gammasimtools-0.19.0.dist-info}/top_level.txt +0 -0
  356. /simtools/{io_operations → io}/hdf5_handler.py +0 -0
  357. /simtools/{io_operations → io}/legacy_data_handler.py +0 -0
  358. /simtools/{io_operations/io_table_handler.py → io/table_handler.py} +0 -0
@@ -13,7 +13,7 @@ import matplotlib.pyplot as plt
13
13
  import numpy as np
14
14
  from astropy.table import QTable
15
15
 
16
- from simtools.io_operations import io_handler
16
+ from simtools.io import io_handler
17
17
  from simtools.model.model_utils import compute_telescope_transmission
18
18
  from simtools.ray_tracing.psf_analysis import PSFImage
19
19
  from simtools.simtel.simulator_ray_tracing import SimulatorRayTracing
@@ -49,6 +49,8 @@ class RayTracing:
49
49
  Single mirror mode flag.
50
50
  use_random_focal_length: bool
51
51
  Use random focal length flag.
52
+ random_focal_length_seed: int
53
+ Seed for the random number generator used for focal length variation.
52
54
  mirror_numbers: list, str
53
55
  List of mirror numbers (or 'all').
54
56
  """
@@ -71,6 +73,7 @@ class RayTracing:
71
73
  source_distance=10.0 * u.km,
72
74
  single_mirror_mode=False,
73
75
  use_random_focal_length=False,
76
+ random_focal_length_seed=None,
74
77
  mirror_numbers="all",
75
78
  ):
76
79
  """Initialize RayTracing class."""
@@ -87,6 +90,7 @@ class RayTracing:
87
90
  self.off_axis_angle = np.around(off_axis_angle.to("deg").value, 5)
88
91
  self.single_mirror_mode = single_mirror_mode
89
92
  self.use_random_focal_length = use_random_focal_length
93
+ self.random_focal_length_seed = random_focal_length_seed
90
94
  self.mirrors = self._initialize_mirror_configuration(source_distance, mirror_numbers)
91
95
  self.output_directory = self._io_handler.get_output_directory(
92
96
  label=self.label, sub_dir="ray_tracing"
@@ -185,7 +189,7 @@ class RayTracing:
185
189
  """
186
190
  _focal_length = self.telescope_model.get_parameter_value("mirror_focal_length")
187
191
  if self.use_random_focal_length:
188
- rng = np.random.default_rng()
192
+ rng = np.random.default_rng(self.random_focal_length_seed)
189
193
  _random_focal_length = self.telescope_model.get_parameter_value("random_focal_length")
190
194
  if _random_focal_length[0] > 0.0:
191
195
  _focal_length += rng.normal(loc=0, scale=_random_focal_length[0])
@@ -9,14 +9,14 @@ from collections import defaultdict
9
9
  from itertools import groupby
10
10
  from pathlib import Path
11
11
 
12
+ import matplotlib.pyplot as plt
12
13
  import numpy as np
13
14
 
14
15
  from simtools.db import db_handler
15
- from simtools.io_operations import io_handler
16
+ from simtools.io import ascii_handler, io_handler
16
17
  from simtools.model.telescope_model import TelescopeModel
17
- from simtools.utils import general as gen
18
18
  from simtools.utils import names
19
- from simtools.visualization import plot_pixels
19
+ from simtools.visualization import plot_pixels, plot_tables
20
20
 
21
21
  logger = logging.getLogger()
22
22
 
@@ -64,72 +64,141 @@ class ReadParameters:
64
64
  )
65
65
  self._model_version = model_version
66
66
 
67
- def _convert_to_md(self, parameter, parameter_version, input_file):
67
+ def _generate_plots(self, parameter, parameter_version, input_file, outpath, design_type):
68
+ """Generate plots based on the parameter type."""
69
+ plot_names = []
70
+
71
+ if parameter == "camera_config_file":
72
+ plot_names = self._plot_camera_config(parameter, parameter_version, input_file, outpath)
73
+ elif parameter_version:
74
+ plot_names = self._plot_parameter_tables(
75
+ parameter, parameter_version, outpath, design_type
76
+ )
77
+
78
+ return plot_names
79
+
80
+ def _plot_camera_config(self, parameter, parameter_version, input_file, outpath):
81
+ """Generate plots for camera configuration files."""
82
+ if not parameter_version:
83
+ return []
84
+
85
+ plot_names = []
86
+ plot_name = input_file.stem.replace(".", "-")
87
+ plot_path = Path(f"{outpath}/{plot_name}").with_suffix(".png")
88
+
89
+ if not plot_path.exists():
90
+ plot_config = {
91
+ "file_name": input_file.name,
92
+ "telescope": self.array_element,
93
+ "parameter_version": parameter_version,
94
+ "site": self.site,
95
+ "model_version": self.model_version,
96
+ "parameter": parameter,
97
+ }
98
+
99
+ plot_pixels.plot(
100
+ config=plot_config,
101
+ output_file=Path(f"{outpath}/{plot_name}"),
102
+ db_config=self.db_config,
103
+ )
104
+ plot_names.append(plot_name)
105
+ else:
106
+ logger.info(
107
+ "Camera configuration file plot already exists: %s",
108
+ plot_path,
109
+ )
110
+ plot_names.append(plot_name)
111
+
112
+ return plot_names
113
+
114
+ def _plot_parameter_tables(self, parameter, parameter_version, outpath, design_type):
115
+ """Generate plots for parameter tables."""
116
+ telescope_design = self.db.get_design_model(
117
+ self.model_version, self.array_element, collection="telescopes"
118
+ )
119
+
120
+ if not self.array_element:
121
+ tel = None
122
+ elif not design_type:
123
+ tel = telescope_design
124
+ else:
125
+ tel = self.array_element
126
+
127
+ config_data = plot_tables.generate_plot_configurations(
128
+ parameter=parameter,
129
+ parameter_version=parameter_version,
130
+ site=self.site,
131
+ telescope=tel,
132
+ output_path=outpath,
133
+ plot_type="all",
134
+ db_config=self.db_config,
135
+ )
136
+
137
+ if not config_data:
138
+ return []
139
+
140
+ plot_configs, output_files = config_data
141
+ plot_names = [i.stem for i in output_files]
142
+
143
+ for plot_config, output_file in zip(plot_configs, output_files):
144
+ image_output_file = outpath / output_file.name
145
+ if not image_output_file.with_suffix(".png").exists():
146
+ plot_tables.plot(
147
+ config=plot_config,
148
+ output_file=image_output_file,
149
+ db_config=self.db_config,
150
+ )
151
+ plt.close("all")
152
+
153
+ return plot_names
154
+
155
+ def _convert_to_md(self, parameter, parameter_version, input_file, design_type=False):
68
156
  """Convert a file to a Markdown file, preserving formatting."""
69
157
  input_file = Path(input_file)
70
158
 
159
+ if not input_file.exists():
160
+ raise FileNotFoundError(f"Data file not found: {input_file}")
161
+
162
+ # Store the markdown output file path early and don't modify it
71
163
  output_data_path = Path(self.output_path / "_data_files")
72
164
  output_data_path.mkdir(parents=True, exist_ok=True)
73
165
  output_file_name = Path(input_file.stem + ".md")
74
- output_file = output_data_path / output_file_name
75
- image_name = f"{self.array_element}_{parameter}_{self.model_version.replace('.', '-')}"
76
- outpath = Path(io_handler.IOHandler().get_output_directory().parent / "_images")
77
- outpath.mkdir(parents=True, exist_ok=True)
78
- image_path = Path(f"{outpath}/{image_name}")
79
-
80
- if parameter == "camera_config_file" and parameter_version:
81
- image_path = Path(f"{outpath}/{input_file.stem.replace('.', '-')}")
82
- if not (image_path.with_suffix(".png")).exists():
83
- logger.info("Plotting camera configuration file: %s", input_file.name)
84
- plot_config = {
85
- "file_name": input_file.name,
86
- "telescope": self.array_element,
87
- "parameter_version": parameter_version,
88
- "site": self.site,
89
- "model_version": self.model_version,
90
- "parameter": parameter,
91
- }
166
+ relative_path = f"_data_files/{output_file_name}"
167
+ markdown_output_file = output_data_path / output_file_name
92
168
 
93
- plot_pixels.plot(
94
- config=plot_config,
95
- output_file=image_path,
96
- db_config=self.db_config,
97
- )
98
- else:
99
- logger.info(
100
- "Camera configuration file plot already exists: %s",
101
- image_path.with_suffix(".png"),
102
- )
169
+ if not markdown_output_file.exists():
170
+ outpath = Path(io_handler.IOHandler().get_output_directory().parent / "_images")
171
+ outpath.mkdir(parents=True, exist_ok=True)
103
172
 
104
- try:
105
- # with input_file.open("r", encoding="utf-8") as infile:
106
- file_contents = gen.read_file_encoded_in_utf_or_latin(input_file)
107
-
108
- if self.model_version is not None:
109
- with output_file.open("w", encoding="utf-8") as outfile:
110
- outfile.write(f"# {input_file.stem}\n")
111
- outfile.write(f"![Parameter plot.]({image_path}.png)\n\n")
112
- outfile.write(
113
- "\n\nThe full file can be found in the Simulation Model repository [here]"
114
- "(https://gitlab.cta-observatory.org/cta-science/simulations/"
115
- "simulation-model/simulation-models/-/blob/main/simulation-models/"
116
- f"model_parameters/Files/{input_file.name}).\n\n"
117
- )
118
- outfile.write("\n\n")
119
- outfile.write("The first 30 lines of the file are:\n")
120
- outfile.write("```\n")
121
- first_30_lines = "".join(file_contents[:30])
122
- outfile.write(first_30_lines)
123
- outfile.write("\n```")
173
+ plot_names = self._generate_plots(
174
+ parameter, parameter_version, input_file, outpath, design_type
175
+ )
176
+ # Write markdown file using the stored path
177
+ file_contents = ascii_handler.read_file_encoded_in_utf_or_latin(input_file)
178
+
179
+ with markdown_output_file.open("w", encoding="utf-8") as outfile:
180
+ outfile.write(f"# {input_file.stem}\n")
124
181
 
125
- except FileNotFoundError as exc:
126
- logger.exception(f"Data file not found: {input_file}.")
127
- raise FileNotFoundError(f"Data file not found: {input_file}.") from exc
182
+ for plot_name in plot_names:
183
+ outfile.write(f"![Parameter plot.]({outpath}/{plot_name}.png)\n\n")
128
184
 
129
- return f"_data_files/{output_file_name}"
185
+ outfile.write(
186
+ "\n\nThe full file can be found in the Simulation Model repository [here]"
187
+ "(https://gitlab.cta-observatory.org/cta-science/simulations/"
188
+ "simulation-model/simulation-models/-/blob/main/simulation-models/"
189
+ f"model_parameters/Files/{input_file.name}).\n\n"
190
+ )
191
+ outfile.write("\n\n")
192
+ outfile.write("The first 30 lines of the file are:\n")
193
+ outfile.write("```\n")
194
+ first_30_lines = "".join(file_contents[:30])
195
+ outfile.write(first_30_lines)
196
+ outfile.write("\n```")
197
+
198
+ return relative_path
130
199
 
131
200
  def _format_parameter_value(
132
- self, parameter, value_data, unit, file_flag, parameter_version=None
201
+ self, parameter, value_data, unit, file_flag, parameter_version=None, design_type=False
133
202
  ):
134
203
  """Format parameter value based on type."""
135
204
  if file_flag:
@@ -140,7 +209,9 @@ class ReadParameters:
140
209
  "cta-science/simulations/simulation-model/simulation-models/-/blob/main/"
141
210
  f"simulation-models/model_parameters/Files/{value_data})"
142
211
  ).strip()
143
- output_file_name = self._convert_to_md(parameter, parameter_version, input_file_name)
212
+ output_file_name = self._convert_to_md(
213
+ parameter, parameter_version, input_file_name, design_type
214
+ )
144
215
  return f"[{Path(value_data).name}]({output_file_name})".strip()
145
216
  if isinstance(value_data, (str | int | float)):
146
217
  return f"{value_data} {unit}".strip()
@@ -326,9 +397,10 @@ class ReadParameters:
326
397
  if value_data is None:
327
398
  continue
328
399
 
400
+ design_type = names.is_design_type(telescope_model.name)
329
401
  file_flag = parameter_data.get("file", False)
330
402
  value = self._format_parameter_value(
331
- parameter, value_data, unit, file_flag, parameter_version
403
+ parameter, value_data, unit, file_flag, parameter_version, design_type
332
404
  )
333
405
 
334
406
  description = parameter_descriptions.get(parameter).get("description")
@@ -338,10 +410,10 @@ class ReadParameters:
338
410
  inst_class = parameter_descriptions.get(parameter).get("inst_class")
339
411
 
340
412
  matching_instrument = parameter_data["instrument"] == telescope_model.name
341
- if not names.is_design_type(telescope_model.name) and matching_instrument:
413
+ if not design_type and matching_instrument:
342
414
  parameter = f"***{parameter}***"
343
415
  parameter_version = f"***{parameter_version}***"
344
- if not re.match(r"^\[.*\]\(.*\)$", value.strip()):
416
+ if not self.is_markdown_link(value):
345
417
  value = f"***{value}***"
346
418
  description = f"***{description}***"
347
419
  short_description = f"***{short_description}***"
@@ -723,7 +795,7 @@ class ReadParameters:
723
795
  if not names.is_design_type(array_element) and matching_instrument:
724
796
  parameter = f"***{parameter}***"
725
797
  parameter_version = f"***{parameter_version}***"
726
- if not re.match(r"^\[.*\]\(.*\)$", value.strip()):
798
+ if not self.is_markdown_link(value):
727
799
  value = f"***{value}***"
728
800
  description = f"***{description}***"
729
801
  short_description = f"***{short_description}***"
@@ -750,6 +822,22 @@ class ReadParameters:
750
822
 
751
823
  return data
752
824
 
825
+ def is_markdown_link(self, value):
826
+ """
827
+ Return True if the string is a Markdown-style link: [text](target).
828
+
829
+ Parameters
830
+ ----------
831
+ value : str
832
+ The string to check.
833
+
834
+ Returns
835
+ -------
836
+ bool
837
+ True if the string is a Markdown link, False otherwise.
838
+ """
839
+ return bool(re.fullmatch(r"\[[^\]]*\]\([^)]+\)", value.strip()))
840
+
753
841
  def produce_calibration_reports(self):
754
842
  """Write calibration reports."""
755
843
  calibration_array_elements = self.db.get_array_elements(
@@ -4,7 +4,7 @@ import logging
4
4
  import stat
5
5
  from pathlib import Path
6
6
 
7
- from simtools.io_operations import io_handler
7
+ from simtools.io import io_handler
8
8
  from simtools.runners.runner_services import RunnerServices
9
9
 
10
10
  __all__ = ["CorsikaRunner", "MissingRequiredEntryInCorsikaConfigError"]
@@ -43,6 +43,7 @@ class CorsikaSimtelRunner:
43
43
  use_multipipe=False,
44
44
  sim_telarray_seeds=None,
45
45
  sequential=False,
46
+ calibration_runner_args=None,
46
47
  ):
47
48
  self._logger = logging.getLogger(__name__)
48
49
  self.corsika_config = (
@@ -55,6 +56,7 @@ class CorsikaSimtelRunner:
55
56
  self.sim_telarray_seeds = sim_telarray_seeds
56
57
  self.label = label
57
58
  self.sequential = "--sequential" if sequential else ""
59
+ self.calibration_runner_args = calibration_runner_args
58
60
 
59
61
  self.base_corsika_config.set_output_file_and_directory(use_multipipe)
60
62
  self.corsika_runner = CorsikaRunner(
@@ -124,11 +126,18 @@ class CorsikaSimtelRunner:
124
126
 
125
127
  with open(multipipe_file, "w", encoding="utf-8") as file:
126
128
  for simulator_array in self.simulator_array:
127
- run_command = simulator_array.make_run_command(
128
- run_number=run_number,
129
- input_file="-", # instruct sim_telarray to take input from standard output
130
- weak_pointing=self._determine_pointing_option(self.label),
131
- )
129
+ if self.calibration_runner_args:
130
+ run_command = simulator_array.make_run_command_for_calibration_simulations(
131
+ run_number=run_number,
132
+ input_file="-", # instruct sim_telarray to take input from standard output
133
+ calibration_runner_args=self.calibration_runner_args,
134
+ )
135
+ else:
136
+ run_command = simulator_array.make_run_command(
137
+ run_number=run_number,
138
+ input_file="-", # instruct sim_telarray to take input from standard output
139
+ weak_pointing=self._determine_pointing_option(self.label),
140
+ )
132
141
  file.write(f"{run_command}")
133
142
  file.write("\n")
134
143
  self._logger.info(f"Multipipe script: {multipipe_file}")
@@ -3,7 +3,7 @@
3
3
  import logging
4
4
  from pathlib import Path
5
5
 
6
- from simtools.io_operations import io_handler
6
+ from simtools.io import io_handler
7
7
 
8
8
  _logger = logging.getLogger(__name__)
9
9
 
@@ -139,11 +139,16 @@ class RunnerServices:
139
139
  zenith = self.corsika_config.get_config_parameter("THETAP")[0]
140
140
  azimuth = self.corsika_config.azimuth_angle
141
141
  run_number_string = self._get_run_number_string(info_for_file_name["run_number"])
142
- return (
142
+ prefix = (
143
143
  f"{info_for_file_name['primary']}_{run_number_string}_"
144
- f"za{round(zenith):02}deg_azm{azimuth:03}deg_"
145
- f"{info_for_file_name['site']}_{info_for_file_name['array_name']}_"
146
- f"{info_for_file_name['model_version']}{file_label}"
144
+ if info_for_file_name["primary"]
145
+ else f"{run_number_string}_"
146
+ )
147
+ return (
148
+ prefix
149
+ + f"za{round(zenith):02}deg_azm{azimuth:03}deg_"
150
+ + f"{info_for_file_name['site']}_{info_for_file_name['array_name']}_"
151
+ + f"{info_for_file_name['model_version']}{file_label}"
147
152
  )
148
153
 
149
154
  def _get_log_file_path(self, file_type, file_name):
@@ -0,0 +1,267 @@
1
+ """Tools for running applications in the simtools framework."""
2
+
3
+ import shutil
4
+ import subprocess
5
+ from pathlib import Path
6
+
7
+ import simtools.utils.general as gen
8
+ from simtools import dependencies
9
+ from simtools.io import ascii_handler
10
+
11
+
12
+ def run_applications(args_dict, db_config, logger):
13
+ """
14
+ Run simtools applications step-by-step as defined in a configuration file.
15
+
16
+ Parameters
17
+ ----------
18
+ args_dict : dict
19
+ Dictionary containing command line arguments.
20
+ db_config : dict
21
+ Database configuration
22
+ logger : logging.Logger
23
+ Logger for logging application output.
24
+ """
25
+ configurations, runtime_environment, log_file = _read_application_configuration(
26
+ args_dict["configuration_file"], args_dict.get("steps"), logger
27
+ )
28
+ run_time = (
29
+ read_runtime_environment(runtime_environment)
30
+ if not args_dict["ignore_runtime_environment"]
31
+ else []
32
+ )
33
+
34
+ with log_file.open("w", encoding="utf-8") as file:
35
+ file.write("Running simtools applications\n")
36
+ file.write(dependencies.get_version_string(db_config, run_time))
37
+
38
+ for config in configurations:
39
+ app = config.get("application")
40
+ if not config.get("run_application"):
41
+ logger.info(f"Skipping application: {app}")
42
+ continue
43
+ logger.info(f"Running application: {app}")
44
+ stdout, stderr = run_application(run_time, app, config.get("configuration"), logger)
45
+ file.write("=" * 80 + "\n")
46
+ file.write(f"Application: {app}\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n")
47
+
48
+
49
+ def run_application(runtime_environment, application, configuration, logger):
50
+ """
51
+ Run a simtools application and return stdout and stderr.
52
+
53
+ Allow to specify a runtime environment (e.g., Docker) and a working directory.
54
+
55
+ Parameters
56
+ ----------
57
+ runtime_environment : list
58
+ Command to run the application in the specified runtime environment.
59
+ application : str
60
+ Name of the application to run.
61
+ configuration : dict
62
+ Configuration for the application.
63
+ logger : logging.Logger
64
+ Logger for logging application output.
65
+
66
+ Returns
67
+ -------
68
+ tuple
69
+ stdout and stderr from the application run.
70
+
71
+ """
72
+ command = [application, *_convert_dict_to_args(configuration)]
73
+ if runtime_environment:
74
+ command = runtime_environment + command
75
+ try:
76
+ result = subprocess.run(
77
+ command,
78
+ check=True,
79
+ capture_output=True,
80
+ text=True,
81
+ )
82
+ except subprocess.CalledProcessError as exc:
83
+ logger.error(f"Error running application {application}: {exc.stderr}")
84
+ raise exc
85
+
86
+ return result.stdout, result.stderr
87
+
88
+
89
+ def _convert_dict_to_args(parameters):
90
+ """
91
+ Convert a dictionary of parameters to a list of command line arguments.
92
+
93
+ Parameters
94
+ ----------
95
+ parameters : dict
96
+ Dictionary containing parameters to convert.
97
+
98
+ Returns
99
+ -------
100
+ list
101
+ List of command line arguments.
102
+ """
103
+ args = []
104
+ for key, value in parameters.items():
105
+ if isinstance(value, bool):
106
+ if value:
107
+ args.append(f"--{key}")
108
+ elif isinstance(value, list):
109
+ args.extend([f"--{key}", *(str(item) for item in value)])
110
+ else:
111
+ args.extend([f"--{key}", str(value)])
112
+ return args
113
+
114
+
115
+ def _read_application_configuration(configuration_file, steps, logger):
116
+ """
117
+ Read application configuration from file and modify for setting workflows.
118
+
119
+ Strong assumptions on the structure of input and output files:
120
+
121
+ - configuration file is expected to be in './input/<workflow directory>/<yaml file>'
122
+ - output files will be written out to './output/<workflow directory>/'
123
+
124
+ Replaces the placeholders in the configuration file with the actual values.
125
+ Sets 'USE_PLAIN_OUTPUT_PATH' to True for all applications.
126
+
127
+ Parameters
128
+ ----------
129
+ configuration_file : str
130
+ Configuration file name.
131
+ steps : list
132
+ List of steps to be executed (None: all steps).
133
+ logger : Logger
134
+ Logger object.
135
+
136
+ Returns
137
+ -------
138
+ dict
139
+ Application configuration.
140
+ dict:
141
+ Runtime environment configuration.
142
+ Path
143
+ Path to the log file.
144
+
145
+ """
146
+ job_configuration = ascii_handler.collect_data_from_file(configuration_file)
147
+ configurations = job_configuration.get("applications")
148
+ output_path, setting_workflow = _set_input_output_directories(configuration_file)
149
+ logger.info(f"Setting workflow output path to {output_path}")
150
+ for step_count, config in enumerate(configurations, start=1):
151
+ config["run_application"] = step_count in steps if steps else True
152
+ config = gen.change_dict_keys_case(config, True)
153
+ config["configuration"] = _replace_placeholders_in_configuration(
154
+ config.get("configuration", {}),
155
+ output_path,
156
+ setting_workflow,
157
+ )
158
+ configurations[step_count - 1] = config
159
+
160
+ return (
161
+ configurations,
162
+ job_configuration.get("runtime_environment"),
163
+ output_path / "simtools.log",
164
+ )
165
+
166
+
167
+ def _replace_placeholders_in_configuration(
168
+ configuration, output_path, setting_workflow, place_holder="__SETTING_WORKFLOW__"
169
+ ):
170
+ """
171
+ Replace placeholders in the configuration dictionary.
172
+
173
+ Parameters
174
+ ----------
175
+ configuration : dict
176
+ Configuration dictionary.
177
+ output_path : Path
178
+ Path to the output directory.
179
+ setting_workflow : str
180
+ The setting workflow to replace the placeholder with.
181
+ place_holder : str
182
+ Placeholder to be replaced.
183
+
184
+ Returns
185
+ -------
186
+ dict
187
+ Configuration dictionary with placeholders replaced.
188
+ """
189
+ for key, value in configuration.items():
190
+ if isinstance(value, str):
191
+ configuration[key] = value.replace(place_holder, setting_workflow)
192
+ if isinstance(value, list):
193
+ configuration[key] = [
194
+ item.replace(place_holder, setting_workflow) if isinstance(item, str) else item
195
+ for item in value
196
+ ]
197
+ if output_path:
198
+ configuration["use_plain_output_path"] = True
199
+ configuration["output_path"] = str(output_path)
200
+
201
+ return configuration
202
+
203
+
204
+ def _set_input_output_directories(path):
205
+ """
206
+ Set input and output directories based on the configuration file path.
207
+
208
+ Tuned to simulation models setting workflows.
209
+
210
+ Parameters
211
+ ----------
212
+ path : str or Path
213
+ Path to the configuration file.
214
+
215
+ Returns
216
+ -------
217
+ tuple
218
+ The first part is the 'input' directory, the second part is the subdirectory name
219
+ """
220
+ path = Path(path).resolve()
221
+ try:
222
+ input_index = path.parts.index("input")
223
+ # Get all parts after 'input', excluding the filename
224
+ subdirs = path.parts[input_index + 1 : -1]
225
+ setting_workflow = "/".join(subdirs)
226
+ workflow_dir = path.parts[input_index]
227
+ except (ValueError, IndexError) as exc:
228
+ raise ValueError(f"Could not find subdirectory under 'input': {exc}") from exc
229
+
230
+ output_path = Path(str(workflow_dir).replace("input", "output")) / Path(setting_workflow)
231
+ output_path.mkdir(parents=True, exist_ok=True)
232
+ return output_path, "/".join(subdirs)
233
+
234
+
235
+ def read_runtime_environment(runtime_environment, workdir="/workdir/external/"):
236
+ """
237
+ Read the runtime environment (e.g. docker runtime) and generate the required command.
238
+
239
+ Parameters
240
+ ----------
241
+ runtime_environment : str or None
242
+ Path to the runtime environment configuration file.
243
+
244
+ Returns
245
+ -------
246
+ list
247
+ Runtime command.
248
+ """
249
+ if runtime_environment is None:
250
+ return []
251
+
252
+ engine = runtime_environment.get("container_engine", "docker")
253
+ if shutil.which(engine) is None:
254
+ raise RuntimeError(f"Container engine '{engine}' not found.")
255
+ cmd = [engine, "run", "--rm", "-v", f"{Path.cwd()}:{workdir}", "-w", workdir]
256
+
257
+ if options := runtime_environment.get("options"):
258
+ for opt in options:
259
+ cmd.extend(opt.split())
260
+
261
+ if env := runtime_environment.get("env_file"):
262
+ cmd += ["--env-file", env]
263
+ if net := runtime_environment.get("network"):
264
+ cmd += ["--network", net]
265
+
266
+ cmd.append(runtime_environment["image"])
267
+ return cmd