gammasimtools 0.6.1__py3-none-any.whl → 0.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. gammasimtools-0.8.1.dist-info/METADATA +172 -0
  2. gammasimtools-0.8.1.dist-info/RECORD +346 -0
  3. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.1.dist-info}/WHEEL +1 -1
  4. gammasimtools-0.8.1.dist-info/entry_points.txt +31 -0
  5. simtools/_version.py +2 -2
  6. simtools/applications/calculate_trigger_rate.py +210 -0
  7. simtools/applications/convert_all_model_parameters_from_simtel.py +372 -0
  8. simtools/applications/{print_array_elements.py → convert_geo_coordinates_of_array_elements.py} +58 -63
  9. simtools/applications/convert_model_parameter_from_simtel.py +119 -0
  10. simtools/applications/{add_file_to_db.py → db_add_file_to_db.py} +70 -60
  11. simtools/applications/db_add_model_parameters_from_repository_to_db.py +184 -0
  12. simtools/applications/db_add_value_from_json_to_db.py +105 -0
  13. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +180 -0
  14. simtools/applications/db_get_array_layouts_from_db.py +162 -0
  15. simtools/applications/{get_file_from_db.py → db_get_file_from_db.py} +30 -34
  16. simtools/applications/db_get_parameter_from_db.py +131 -0
  17. simtools/applications/db_inspect_databases.py +52 -0
  18. simtools/applications/derive_mirror_rnda.py +39 -255
  19. simtools/applications/derive_psf_parameters.py +441 -0
  20. simtools/applications/generate_array_config.py +82 -0
  21. simtools/applications/generate_corsika_histograms.py +52 -52
  22. simtools/applications/generate_default_metadata.py +5 -8
  23. simtools/applications/generate_regular_arrays.py +117 -0
  24. simtools/applications/generate_simtel_array_histograms.py +97 -56
  25. simtools/applications/plot_array_layout.py +345 -115
  26. simtools/applications/production_generate_simulation_config.py +158 -0
  27. simtools/applications/production_scale_events.py +168 -0
  28. simtools/applications/simulate_light_emission.py +478 -0
  29. simtools/applications/simulate_prod.py +97 -175
  30. simtools/applications/submit_data_from_external.py +9 -12
  31. simtools/applications/submit_model_parameter_from_external.py +122 -0
  32. simtools/applications/validate_camera_efficiency.py +35 -102
  33. simtools/applications/validate_camera_fov.py +20 -19
  34. simtools/applications/{compare_cumulative_psf.py → validate_cumulative_psf.py} +45 -44
  35. simtools/applications/validate_file_using_schema.py +113 -47
  36. simtools/applications/validate_optics.py +17 -22
  37. simtools/camera_efficiency.py +193 -202
  38. simtools/configuration/commandline_parser.py +384 -96
  39. simtools/configuration/configurator.py +55 -71
  40. simtools/constants.py +5 -5
  41. simtools/corsika/corsika_config.py +482 -342
  42. simtools/corsika/corsika_histograms.py +226 -204
  43. simtools/corsika/corsika_histograms_visualize.py +23 -24
  44. simtools/corsika/primary_particle.py +159 -0
  45. simtools/data_model/data_reader.py +25 -20
  46. simtools/data_model/format_checkers.py +52 -0
  47. simtools/data_model/metadata_collector.py +210 -184
  48. simtools/data_model/metadata_model.py +115 -37
  49. simtools/data_model/model_data_writer.py +335 -26
  50. simtools/data_model/validate_data.py +366 -154
  51. simtools/db/db_array_elements.py +130 -0
  52. simtools/db/db_from_repo_handler.py +106 -0
  53. simtools/db/db_handler.py +1246 -0
  54. simtools/io_operations/hdf5_handler.py +3 -1
  55. simtools/io_operations/io_handler.py +32 -57
  56. simtools/job_execution/job_manager.py +82 -69
  57. simtools/layout/array_layout.py +325 -537
  58. simtools/layout/geo_coordinates.py +8 -11
  59. simtools/layout/telescope_position.py +163 -86
  60. simtools/model/array_model.py +305 -256
  61. simtools/model/calibration_model.py +50 -0
  62. simtools/model/camera.py +233 -493
  63. simtools/model/mirrors.py +61 -44
  64. simtools/model/model_parameter.py +602 -0
  65. simtools/model/model_utils.py +7 -35
  66. simtools/model/site_model.py +161 -0
  67. simtools/model/telescope_model.py +127 -621
  68. simtools/production_configuration/calculate_statistical_errors_grid_point.py +454 -0
  69. simtools/production_configuration/event_scaler.py +146 -0
  70. simtools/production_configuration/generate_simulation_config.py +193 -0
  71. simtools/production_configuration/interpolation_handler.py +197 -0
  72. simtools/ray_tracing/__init__.py +0 -0
  73. simtools/ray_tracing/mirror_panel_psf.py +280 -0
  74. simtools/{psf_analysis.py → ray_tracing/psf_analysis.py} +133 -47
  75. simtools/ray_tracing/ray_tracing.py +646 -0
  76. simtools/runners/__init__.py +0 -0
  77. simtools/runners/corsika_runner.py +240 -0
  78. simtools/runners/corsika_simtel_runner.py +225 -0
  79. simtools/runners/runner_services.py +307 -0
  80. simtools/runners/simtel_runner.py +224 -0
  81. simtools/schemas/array_elements.yml +137 -0
  82. simtools/schemas/integration_tests_config.metaschema.yml +93 -0
  83. simtools/schemas/metadata.metaschema.yml +6 -0
  84. simtools/schemas/model_parameter.metaschema.yml +78 -0
  85. simtools/schemas/{data.metaschema.yml → model_parameter_and_data_schema.metaschema.yml} +27 -44
  86. simtools/schemas/model_parameters/adjust_gain.schema.yml +37 -0
  87. simtools/schemas/model_parameters/altitude.schema.yml +37 -0
  88. simtools/schemas/model_parameters/array_coordinates.schema.yml +33 -0
  89. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +77 -0
  90. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +39 -0
  91. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +39 -0
  92. simtools/schemas/model_parameters/array_layouts.schema.yml +48 -0
  93. simtools/schemas/model_parameters/array_triggers.schema.yml +93 -0
  94. simtools/schemas/model_parameters/asum_clipping.schema.yml +38 -0
  95. simtools/schemas/model_parameters/asum_offset.schema.yml +35 -0
  96. simtools/schemas/model_parameters/asum_shaping.schema.yml +35 -0
  97. simtools/schemas/model_parameters/asum_threshold.schema.yml +38 -0
  98. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +32 -0
  99. simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +35 -0
  100. simtools/schemas/model_parameters/axes_offsets.schema.yml +53 -0
  101. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +40 -0
  102. simtools/schemas/model_parameters/camera_body_shape.schema.yml +45 -0
  103. simtools/schemas/model_parameters/camera_config_file.schema.yml +40 -0
  104. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +36 -0
  105. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +43 -0
  106. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +42 -0
  107. simtools/schemas/model_parameters/camera_depth.schema.yml +42 -0
  108. simtools/schemas/model_parameters/camera_filter.schema.yml +45 -0
  109. simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +29 -0
  110. simtools/schemas/model_parameters/camera_pixels.schema.yml +36 -0
  111. simtools/schemas/model_parameters/camera_transmission.schema.yml +41 -0
  112. simtools/schemas/model_parameters/channels_per_chip.schema.yml +36 -0
  113. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +35 -0
  114. simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +27 -0
  115. simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +38 -0
  116. simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +28 -0
  117. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +23 -0
  118. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +27 -0
  119. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +28 -0
  120. simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +27 -0
  121. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +38 -0
  122. simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +52 -0
  123. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +27 -0
  124. simtools/schemas/model_parameters/dark_events.schema.yml +32 -0
  125. simtools/schemas/model_parameters/default_trigger.schema.yml +35 -0
  126. simtools/schemas/model_parameters/design_model.schema.yml +31 -0
  127. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +32 -0
  128. simtools/schemas/model_parameters/disc_bins.schema.yml +39 -0
  129. simtools/schemas/model_parameters/disc_start.schema.yml +41 -0
  130. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +42 -0
  131. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +41 -0
  132. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +41 -0
  133. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +39 -0
  134. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +40 -0
  135. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +41 -0
  136. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +33 -0
  137. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +42 -0
  138. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +37 -0
  139. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +44 -0
  140. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +36 -0
  141. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +45 -0
  142. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +40 -0
  143. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +41 -0
  144. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +38 -0
  145. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +38 -0
  146. simtools/schemas/model_parameters/dish_shape_length.schema.yml +41 -0
  147. simtools/schemas/model_parameters/dsum_clipping.schema.yml +38 -0
  148. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +38 -0
  149. simtools/schemas/model_parameters/dsum_offset.schema.yml +37 -0
  150. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +33 -0
  151. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +39 -0
  152. simtools/schemas/model_parameters/dsum_prescale.schema.yml +44 -0
  153. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +38 -0
  154. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +45 -0
  155. simtools/schemas/model_parameters/dsum_shaping.schema.yml +44 -0
  156. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +32 -0
  157. simtools/schemas/model_parameters/dsum_threshold.schema.yml +43 -0
  158. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +42 -0
  159. simtools/schemas/model_parameters/effective_focal_length.schema.yml +61 -0
  160. simtools/schemas/model_parameters/epsg_code.schema.yml +37 -0
  161. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +35 -0
  162. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +46 -0
  163. simtools/schemas/model_parameters/fadc_bins.schema.yml +40 -0
  164. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +50 -0
  165. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +38 -0
  166. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +42 -0
  167. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +49 -0
  168. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +47 -0
  169. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +51 -0
  170. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +37 -0
  171. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +43 -0
  172. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +49 -0
  173. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +43 -0
  174. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +39 -0
  175. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +42 -0
  176. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +40 -0
  177. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +50 -0
  178. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +42 -0
  179. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +41 -0
  180. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +42 -0
  181. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +43 -0
  182. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +39 -0
  183. simtools/schemas/model_parameters/fadc_mhz.schema.yml +31 -0
  184. simtools/schemas/model_parameters/fadc_noise.schema.yml +41 -0
  185. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +40 -0
  186. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +39 -0
  187. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +50 -0
  188. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +43 -0
  189. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +43 -0
  190. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +42 -0
  191. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +41 -0
  192. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +42 -0
  193. simtools/schemas/model_parameters/flatfielding.schema.yml +37 -0
  194. simtools/schemas/model_parameters/focal_length.schema.yml +45 -0
  195. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +158 -0
  196. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +29 -0
  197. simtools/schemas/model_parameters/focus_offset.schema.yml +66 -0
  198. simtools/schemas/model_parameters/gain_variation.schema.yml +43 -0
  199. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +34 -0
  200. simtools/schemas/model_parameters/geomag_rotation.schema.yml +37 -0
  201. simtools/schemas/model_parameters/geomag_vertical.schema.yml +34 -0
  202. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +36 -0
  203. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +34 -0
  204. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +34 -0
  205. simtools/schemas/model_parameters/laser_events.schema.yml +36 -0
  206. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +35 -0
  207. simtools/schemas/model_parameters/laser_photons.schema.yml +32 -0
  208. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +34 -0
  209. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +34 -0
  210. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +33 -0
  211. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +33 -0
  212. simtools/schemas/model_parameters/laser_var_photons.schema.yml +33 -0
  213. simtools/schemas/model_parameters/laser_wavelength.schema.yml +33 -0
  214. simtools/schemas/model_parameters/led_events.schema.yml +34 -0
  215. simtools/schemas/model_parameters/led_photons.schema.yml +34 -0
  216. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +32 -0
  217. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +33 -0
  218. simtools/schemas/model_parameters/led_var_photons.schema.yml +34 -0
  219. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +41 -0
  220. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +43 -0
  221. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +35 -0
  222. simtools/schemas/model_parameters/min_photons.schema.yml +32 -0
  223. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +36 -0
  224. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +64 -0
  225. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +64 -0
  226. simtools/schemas/model_parameters/mirror_class.schema.yml +41 -0
  227. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +51 -0
  228. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +42 -0
  229. simtools/schemas/model_parameters/mirror_list.schema.yml +38 -0
  230. simtools/schemas/model_parameters/mirror_offset.schema.yml +41 -0
  231. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +39 -0
  232. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +61 -0
  233. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +40 -0
  234. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +46 -0
  235. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +51 -0
  236. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +37 -0
  237. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +79 -0
  238. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +47 -0
  239. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +34 -0
  240. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +33 -0
  241. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +35 -0
  242. simtools/schemas/model_parameters/nsb_skymap.schema.yml +39 -0
  243. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +50 -0
  244. simtools/schemas/model_parameters/num_gains.schema.yml +34 -0
  245. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +33 -0
  246. simtools/schemas/model_parameters/optics_properties.schema.yml +31 -0
  247. simtools/schemas/model_parameters/parabolic_dish.schema.yml +32 -0
  248. simtools/schemas/model_parameters/pedestal_events.schema.yml +32 -0
  249. simtools/schemas/model_parameters/photon_delay.schema.yml +38 -0
  250. simtools/schemas/model_parameters/photons_per_run.schema.yml +33 -0
  251. simtools/schemas/model_parameters/pixel_cells.schema.yml +35 -0
  252. simtools/schemas/model_parameters/pixels_parallel.schema.yml +54 -0
  253. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +40 -0
  254. simtools/schemas/model_parameters/pm_average_gain.schema.yml +34 -0
  255. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +40 -0
  256. simtools/schemas/model_parameters/pm_gain_index.schema.yml +36 -0
  257. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +41 -0
  258. simtools/schemas/model_parameters/pm_transit_time.schema.yml +63 -0
  259. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +39 -0
  260. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +42 -0
  261. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +33 -0
  262. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +33 -0
  263. simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +29 -0
  264. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +168 -0
  265. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +36 -0
  266. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +34 -0
  267. simtools/schemas/model_parameters/qe_variation.schema.yml +43 -0
  268. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +42 -0
  269. simtools/schemas/model_parameters/random_focal_length.schema.yml +45 -0
  270. simtools/schemas/model_parameters/random_generator.schema.yml +36 -0
  271. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +35 -0
  272. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +36 -0
  273. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +36 -0
  274. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +34 -0
  275. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +34 -0
  276. simtools/schemas/model_parameters/sampled_output.schema.yml +31 -0
  277. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +34 -0
  278. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +79 -0
  279. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +42 -0
  280. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +41 -0
  281. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +33 -0
  282. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +36 -0
  283. simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +29 -0
  284. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +168 -0
  285. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +36 -0
  286. simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +35 -0
  287. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +37 -0
  288. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +40 -0
  289. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +40 -0
  290. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +41 -0
  291. simtools/schemas/model_parameters/tailcut_scale.schema.yml +40 -0
  292. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +31 -0
  293. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +35 -0
  294. simtools/schemas/model_parameters/telescope_random_error.schema.yml +34 -0
  295. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +37 -0
  296. simtools/schemas/model_parameters/telescope_transmission.schema.yml +113 -0
  297. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +41 -0
  298. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +36 -0
  299. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +36 -0
  300. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +37 -0
  301. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +38 -0
  302. simtools/schemas/model_parameters/transit_time_error.schema.yml +45 -0
  303. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +36 -0
  304. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +32 -0
  305. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +53 -0
  306. simtools/schemas/model_parameters/trigger_pixels.schema.yml +40 -0
  307. simtools/simtel/simtel_config_reader.py +353 -0
  308. simtools/simtel/simtel_config_writer.py +244 -63
  309. simtools/simtel/{simtel_events.py → simtel_io_events.py} +26 -25
  310. simtools/simtel/simtel_io_histogram.py +661 -0
  311. simtools/simtel/simtel_io_histograms.py +569 -0
  312. simtools/simtel/simulator_array.py +145 -0
  313. simtools/simtel/{simtel_runner_camera_efficiency.py → simulator_camera_efficiency.py} +76 -52
  314. simtools/simtel/simulator_light_emission.py +473 -0
  315. simtools/simtel/simulator_ray_tracing.py +262 -0
  316. simtools/simulator.py +220 -446
  317. simtools/testing/__init__.py +0 -0
  318. simtools/testing/assertions.py +151 -0
  319. simtools/testing/configuration.py +226 -0
  320. simtools/testing/helpers.py +42 -0
  321. simtools/testing/validate_output.py +240 -0
  322. simtools/utils/general.py +340 -437
  323. simtools/utils/geometry.py +12 -12
  324. simtools/utils/names.py +258 -644
  325. simtools/utils/value_conversion.py +176 -0
  326. simtools/version.py +2 -0
  327. simtools/visualization/legend_handlers.py +135 -152
  328. simtools/visualization/plot_camera.py +379 -0
  329. simtools/visualization/visualize.py +346 -167
  330. gammasimtools-0.6.1.dist-info/METADATA +0 -180
  331. gammasimtools-0.6.1.dist-info/RECORD +0 -91
  332. gammasimtools-0.6.1.dist-info/entry_points.txt +0 -23
  333. simtools/applications/db_development_tools/add_new_parameter_to_db.py +0 -81
  334. simtools/applications/db_development_tools/add_unit_to_parameter_in_db.py +0 -59
  335. simtools/applications/db_development_tools/mark_non_optics_parameters_non_applicable.py +0 -102
  336. simtools/applications/get_parameter.py +0 -92
  337. simtools/applications/make_regular_arrays.py +0 -160
  338. simtools/applications/produce_array_config.py +0 -136
  339. simtools/applications/production.py +0 -313
  340. simtools/applications/sim_showers_for_trigger_rates.py +0 -187
  341. simtools/applications/tune_psf.py +0 -334
  342. simtools/corsika/corsika_default_config.py +0 -282
  343. simtools/corsika/corsika_runner.py +0 -450
  344. simtools/corsika_simtel/corsika_simtel_runner.py +0 -197
  345. simtools/db_handler.py +0 -1480
  346. simtools/ray_tracing.py +0 -525
  347. simtools/simtel/simtel_histograms.py +0 -414
  348. simtools/simtel/simtel_runner.py +0 -244
  349. simtools/simtel/simtel_runner_array.py +0 -293
  350. simtools/simtel/simtel_runner_ray_tracing.py +0 -277
  351. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.1.dist-info}/LICENSE +0 -0
  352. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.1.dist-info}/top_level.txt +0 -0
  353. /simtools/{corsika_simtel → db}/__init__.py +0 -0
File without changes
@@ -0,0 +1,151 @@
1
+ """Functions asserting certain conditions are met (used e.g., in integration tests)."""
2
+
3
+ import json
4
+ import logging
5
+ from collections import defaultdict
6
+ from pathlib import Path
7
+
8
+ import numpy as np
9
+ import yaml
10
+
11
+ _logger = logging.getLogger(__name__)
12
+
13
+
14
+ def assert_file_type(file_type, file_name):
15
+ """
16
+ Assert that the file is of the given type.
17
+
18
+ Parameters
19
+ ----------
20
+ file_type: str
21
+ File type (json, yaml).
22
+ file_name: str
23
+ File name.
24
+
25
+ """
26
+ if file_type == "json":
27
+ try:
28
+ with open(file_name, encoding="utf-8") as file:
29
+ json.load(file)
30
+ return True
31
+ except (json.JSONDecodeError, FileNotFoundError):
32
+ return False
33
+ if file_type in ("yaml", "yml"):
34
+ if Path(file_name).suffix[1:] not in ("yaml", "yml"):
35
+ return False
36
+ try:
37
+ with open(file_name, encoding="utf-8") as file:
38
+ yaml.safe_load(file)
39
+ return True
40
+ except (yaml.YAMLError, FileNotFoundError):
41
+ return False
42
+
43
+ # no dedicated tests for other file types, checking suffix only
44
+ _logger.info(f"File type test is checking suffix only for {file_name} (suffix: {file_type}))")
45
+ return Path(file_name).suffix[1:] == file_type
46
+
47
+
48
+ def assert_n_showers_and_energy_range(file):
49
+ """
50
+ Assert the number of showers and the energy range.
51
+
52
+ The number of showers should be consistent with the required one (up to 1% tolerance)
53
+ and the energies simulated are required to be within the configured ones.
54
+
55
+ Parameters
56
+ ----------
57
+ file: Path
58
+ Path to the sim_telarray file.
59
+
60
+ """
61
+ from eventio.simtel.simtelfile import SimTelFile # pylint: disable=import-outside-toplevel
62
+
63
+ simulated_energies = []
64
+ simulation_config = {}
65
+ with SimTelFile(file) as f:
66
+ simulation_config = f.mc_run_headers[0]
67
+ for event in f.iter_mc_events():
68
+ simulated_energies.append(event["mc_shower"]["energy"])
69
+
70
+ # The relative tolerance is set to 1% because ~0.5% shower simulations do not
71
+ # succeed, without resulting in an error. This tolerance therefore is not an issue.
72
+ consistent_n_showers = np.isclose(
73
+ len(np.unique(simulated_energies)), simulation_config["n_showers"], rtol=1e-2
74
+ )
75
+ consistent_energy_range = all(
76
+ simulation_config["E_range"][0] <= energy <= simulation_config["E_range"][1]
77
+ for energy in simulated_energies
78
+ )
79
+
80
+ return consistent_n_showers and consistent_energy_range
81
+
82
+
83
+ def assert_expected_output(file, expected_output):
84
+ """
85
+ Assert that the expected output is present in the sim_telarray file.
86
+
87
+ Parameters
88
+ ----------
89
+ file: Path
90
+ Path to the sim_telarray file.
91
+ expected_output: dict
92
+ Expected output values.
93
+
94
+ """
95
+ from eventio.simtel.simtelfile import SimTelFile # pylint: disable=import-outside-toplevel
96
+
97
+ item_to_check = defaultdict(list)
98
+ with SimTelFile(file) as f:
99
+ for event in f:
100
+ if "pe_sum" in expected_output:
101
+ item_to_check["pe_sum"].extend(
102
+ event["photoelectron_sums"]["n_pe"][event["photoelectron_sums"]["n_pe"] > 0]
103
+ )
104
+ if "trigger_time" in expected_output:
105
+ item_to_check["trigger_time"].extend(event["trigger_information"]["trigger_times"])
106
+ if "photons" in expected_output:
107
+ item_to_check["photons"].extend(
108
+ event["photoelectron_sums"]["photons_atm_qe"][
109
+ event["photoelectron_sums"]["photons"] > 0
110
+ ]
111
+ )
112
+
113
+ for key, value in expected_output.items():
114
+ if len(item_to_check[key]) == 0:
115
+ _logger.error(f"No data found for {key}")
116
+ return False
117
+
118
+ if not value[0] < np.mean(item_to_check[key]) < value[1]:
119
+ _logger.error(
120
+ f"Mean of {key} is not in the expected range, got {np.mean(item_to_check[key])}"
121
+ )
122
+ return False
123
+
124
+ return True
125
+
126
+
127
+ def check_output_from_sim_telarray(file, expected_output):
128
+ """
129
+ Check that the sim_telarray simulation result is reasonable and matches the expected output.
130
+
131
+ Parameters
132
+ ----------
133
+ file: Path
134
+ Path to the sim_telarray file.
135
+ expected_output: dict
136
+ Expected output values.
137
+
138
+ Raises
139
+ ------
140
+ ValueError
141
+ If the file is not a zstd compressed file.
142
+ """
143
+ if file.suffix != ".zst":
144
+ raise ValueError(
145
+ f"Expected output file {file} is not a zstd compressed file "
146
+ f"(i.e., a sim_telarray file)."
147
+ )
148
+
149
+ return assert_n_showers_and_energy_range(file=file) and assert_expected_output(
150
+ file=file, expected_output=expected_output
151
+ )
@@ -0,0 +1,226 @@
1
+ """Integration test configuration."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import pytest
7
+ import yaml
8
+
9
+ import simtools.utils.general as gen
10
+
11
+ _logger = logging.getLogger(__name__)
12
+
13
+
14
+ def get_list_of_test_configurations(config_files):
15
+ """
16
+ Return list of test configuration dictionaries or test names.
17
+
18
+ Read all configuration files for testing.
19
+ Add "--help" and "--version" calls for all applications.
20
+
21
+ Parameters
22
+ ----------
23
+ config_files: list
24
+ List of integration test configuration files.
25
+
26
+ Returns
27
+ -------
28
+ list:
29
+ list of test names or of configuration dictionaries.
30
+
31
+ """
32
+ _logger.debug(f"Configuration files: {config_files}")
33
+
34
+ configs = _read_configs_from_files(config_files)
35
+
36
+ # list of all applications
37
+ # (needs to be sorted for pytest-xdist, see Known Limitations in their website)
38
+ _applications = sorted({item["APPLICATION"] for item in configs if "APPLICATION" in item})
39
+ for app in _applications:
40
+ configs.extend(
41
+ [
42
+ {"APPLICATION": app, "TEST_NAME": "auto-help", "CONFIGURATION": {"HELP": True}},
43
+ {
44
+ "APPLICATION": app,
45
+ "TEST_NAME": "auto-version",
46
+ "CONFIGURATION": {"VERSION": True},
47
+ },
48
+ {"APPLICATION": app, "TEST_NAME": "auto-no_config"},
49
+ ]
50
+ )
51
+
52
+ return (
53
+ configs,
54
+ [
55
+ f"{item.get('APPLICATION', 'no-app-name')}_{item.get('TEST_NAME', 'no-test-name')}"
56
+ for item in configs
57
+ ],
58
+ )
59
+
60
+
61
+ def _read_configs_from_files(config_files):
62
+ """Read test configuration from files."""
63
+ configs = []
64
+ for config_file in config_files:
65
+ # read config file
66
+ # remove new line characters from config - otherwise issues
67
+ # with especially long file names
68
+ _dict = gen.remove_substring_recursively_from_dict(
69
+ gen.collect_data_from_file(file_name=config_file), substring="\n"
70
+ )
71
+ configs.append(_dict.get("CTA_SIMPIPE", None))
72
+ return configs
73
+
74
+
75
+ def configure(config, tmp_test_directory, request):
76
+ """
77
+ Prepare configuration and command for integration tests.
78
+
79
+ Parameters
80
+ ----------
81
+ config: dict
82
+ Configuration dictionary.
83
+ tmp_test_directory: str
84
+ Temporary test directory (from pytest fixture).
85
+ request: request
86
+ Request object.
87
+
88
+ Returns
89
+ -------
90
+ str: command to run the application test.
91
+ str: config file model version.
92
+
93
+ """
94
+ tmp_output_path = create_tmp_output_path(tmp_test_directory, config)
95
+ model_version_requested = request.config.getoption("--model_version")
96
+
97
+ if "CONFIGURATION" in config:
98
+ _skip_test_for_model_version(config, model_version_requested)
99
+
100
+ config_file, config_string, config_file_model_version = _prepare_test_options(
101
+ config["CONFIGURATION"],
102
+ output_path=tmp_output_path,
103
+ model_version=model_version_requested,
104
+ )
105
+ else:
106
+ config_file = None
107
+ config_string = None
108
+ config_file_model_version = None
109
+
110
+ cmd = get_application_command(
111
+ app=config.get("APPLICATION", None),
112
+ config_file=config_file,
113
+ config_string=config_string,
114
+ )
115
+ return cmd, config_file_model_version
116
+
117
+
118
+ def _skip_test_for_model_version(config, model_version_requested):
119
+ """Skip test if model version requested is not supported."""
120
+ if config.get("MODEL_VERSION_USE_CURRENT") is None or model_version_requested is None:
121
+ return
122
+ model_version_config = config["CONFIGURATION"]["MODEL_VERSION"]
123
+ if model_version_requested != model_version_config:
124
+ pytest.skip(
125
+ f"Model version requested {model_version_requested} not supported for this test"
126
+ )
127
+
128
+
129
+ def _prepare_test_options(config, output_path, model_version=None):
130
+ """
131
+ Prepare test configuration.
132
+
133
+ This means either to write a temporary config file
134
+ or to return a single string for single boolean options (e.g., --version).
135
+ Change output path and file to paths provided with output_path.
136
+
137
+ Parameters
138
+ ----------
139
+ config: dict
140
+ Dictionary with the configuration for the application test.
141
+ output_path: str
142
+ Output path.
143
+ model_version: str
144
+ Model versions (default: use those given in config files)
145
+
146
+ Returns
147
+ -------
148
+ config_file: str
149
+ Path to the temporary configuration file.
150
+ config_string: str
151
+ Command line configuration as single string.
152
+ config_file_model_version: str
153
+ Configuration file model version
154
+
155
+ """
156
+ if len(config) == 1 and next(iter(config.values())) is True:
157
+ return None, "--" + next(iter(config.keys())).lower(), None
158
+
159
+ tmp_config_file = output_path / "tmp_config.yml"
160
+ config_file_model_version = config.get("MODEL_VERSION")
161
+ if model_version is not None and "MODEL_VERSION" in config:
162
+ config.update({"MODEL_VERSION": model_version})
163
+ if "OUTPUT_PATH" in config:
164
+ config.update({"OUTPUT_PATH": str(Path(output_path).joinpath(config["OUTPUT_PATH"]))})
165
+ config.update({"USE_PLAIN_OUTPUT_PATH": True})
166
+ if "DATA_DIRECTORY" in config:
167
+ config.update({"DATA_DIRECTORY": str(Path(output_path).joinpath(config["DATA_DIRECTORY"]))})
168
+
169
+ _logger.info(f"Writing config file: {tmp_config_file}")
170
+ with open(tmp_config_file, "w", encoding="utf-8") as file:
171
+ yaml.safe_dump(config, file, sort_keys=False)
172
+
173
+ return tmp_config_file, None, config_file_model_version
174
+
175
+
176
+ def get_application_command(app, config_file=None, config_string=None):
177
+ """
178
+ Return the command to run the application with the given config file.
179
+
180
+ Parameters
181
+ ----------
182
+ app: str
183
+ Name of the application.
184
+ config_file: str
185
+ Configuration file.
186
+ config_string: str
187
+ Configuration string (e.g., '--version')
188
+
189
+ Returns
190
+ -------
191
+ str: command to run the application test.
192
+
193
+ """
194
+ cmd = app if "simtools-" in app else f"python simtools/applications/{app}.py"
195
+ if config_string:
196
+ return f"{cmd} {config_string}"
197
+ if config_file is not None:
198
+ return f"{cmd} --config {config_file}"
199
+ return cmd
200
+
201
+
202
+ def create_tmp_output_path(tmp_test_directory, config):
203
+ """
204
+ Create temporary output path.
205
+
206
+ Parameters
207
+ ----------
208
+ tmp_test_directory: str
209
+ Temporary directory.
210
+ config: dict
211
+ Configuration dictionary.
212
+
213
+ Returns
214
+ -------
215
+ str: path to the temporary output directory.
216
+
217
+ """
218
+ try:
219
+ tmp_output_path = Path(tmp_test_directory).joinpath(
220
+ config["APPLICATION"] + "-" + config["TEST_NAME"]
221
+ )
222
+ except KeyError as exc:
223
+ raise KeyError(f"No application defined in configuration {config}.") from exc
224
+ tmp_output_path.mkdir(parents=True, exist_ok=True)
225
+ _logger.info(f"Temporary output path: {tmp_output_path}")
226
+ return tmp_output_path
@@ -0,0 +1,42 @@
1
+ """Helper functions for integration testing."""
2
+
3
+ import os
4
+
5
+ import pytest
6
+
7
+
8
+ def skip_camera_efficiency(config):
9
+ """Skip camera efficiency tests if the old version of testeff is used."""
10
+ if "camera-efficiency" in config["APPLICATION"]:
11
+ if not _new_testeff_version():
12
+ pytest.skip(
13
+ "Any applications calling the old version of testeff are skipped "
14
+ "due to a limitation of the old testeff not allowing to specify "
15
+ "the include directory. Please update your sim_telarray tarball."
16
+ )
17
+ full_test_name = f"{config['APPLICATION']}_{config['TEST_NAME']}"
18
+ if "simtools-validate-camera-efficiency_SSTS" == full_test_name:
19
+ pytest.skip(
20
+ "The test simtools-validate-camera-efficiency_SSTS is skipped "
21
+ "since the fake SST mirrors are not yet implemented (#1155)"
22
+ )
23
+
24
+
25
+ def _new_testeff_version():
26
+ """
27
+ Testeff has been updated to allow to specify the include directory.
28
+
29
+ This test checks if the new version is used.
30
+ """
31
+ testeff_path = os.path.join(os.getenv("SIMTOOLS_SIMTEL_PATH"), "sim_telarray/testeff.c")
32
+ try:
33
+ with open(testeff_path, encoding="utf-8") as file:
34
+ file_content = file.read()
35
+ if (
36
+ "/* Combine the include paths such that those from '-I...' options */"
37
+ in file_content
38
+ ):
39
+ return True
40
+ return False
41
+ except FileNotFoundError as exc:
42
+ raise FileNotFoundError("The testeff executable could not be found.") from exc
@@ -0,0 +1,240 @@
1
+ """Compare application output to reference output."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import numpy as np
7
+ from astropy.table import Table
8
+
9
+ import simtools.utils.general as gen
10
+ from simtools.testing import assertions
11
+
12
+ _logger = logging.getLogger(__name__)
13
+
14
+
15
+ def validate_all_tests(config, request, config_file_model_version):
16
+ """
17
+ Validate test output for all integration tests.
18
+
19
+ Parameters
20
+ ----------
21
+ config: dict
22
+ Integration test configuration dictionary.
23
+ request: request
24
+ Request object.
25
+ config_file_model_version: str
26
+ Model version from the configuration file.
27
+
28
+ """
29
+ if request.config.getoption("--model_version") is None:
30
+ validate_application_output(config)
31
+ elif config_file_model_version is not None:
32
+ _from_command_line = request.config.getoption("--model_version")
33
+ _from_config_file = config_file_model_version
34
+ if _from_command_line == _from_config_file:
35
+ validate_application_output(config)
36
+
37
+
38
+ def validate_application_output(config):
39
+ """
40
+ Validate application output against expected output.
41
+
42
+ Expected output is defined in configuration file.
43
+
44
+ Parameters
45
+ ----------
46
+ config: dict
47
+ dictionary with the configuration for the application test.
48
+
49
+ """
50
+ if "INTEGRATION_TESTS" not in config:
51
+ return
52
+
53
+ for integration_test in config["INTEGRATION_TESTS"]:
54
+ _logger.info(f"Testing application output: {integration_test}")
55
+ if "REFERENCE_OUTPUT_FILE" in integration_test:
56
+ _validate_reference_output_file(config, integration_test)
57
+
58
+ if "OUTPUT_FILE" in integration_test:
59
+ _validate_output_path_and_file(config, integration_test)
60
+
61
+ if "FILE_TYPE" in integration_test:
62
+ assert assertions.assert_file_type(
63
+ integration_test["FILE_TYPE"],
64
+ Path(config["CONFIGURATION"]["OUTPUT_PATH"]).joinpath(
65
+ config["CONFIGURATION"]["OUTPUT_FILE"]
66
+ ),
67
+ )
68
+
69
+
70
+ def _validate_reference_output_file(config, integration_test):
71
+ """Compare with reference output file."""
72
+ assert compare_files(
73
+ integration_test["REFERENCE_OUTPUT_FILE"],
74
+ Path(config["CONFIGURATION"]["OUTPUT_PATH"]).joinpath(
75
+ config["CONFIGURATION"]["OUTPUT_FILE"]
76
+ ),
77
+ integration_test.get("TOLERANCE", 1.0e-5),
78
+ integration_test.get("TEST_COLUMNS", None),
79
+ )
80
+
81
+
82
+ def _validate_output_path_and_file(config, integration_test):
83
+ """Check if output path and file exist."""
84
+ _logger.info(f"PATH {config['CONFIGURATION']['OUTPUT_PATH']}")
85
+ _logger.info(f"File {integration_test['OUTPUT_FILE']}")
86
+
87
+ data_path = config["CONFIGURATION"].get(
88
+ "DATA_DIRECTORY", config["CONFIGURATION"]["OUTPUT_PATH"]
89
+ )
90
+ output_file_path = Path(data_path) / integration_test["OUTPUT_FILE"]
91
+
92
+ _logger.info(f"Checking path: {output_file_path}")
93
+ assert output_file_path.exists()
94
+
95
+ expected_output = [
96
+ d["EXPECTED_OUTPUT"] for d in config["INTEGRATION_TESTS"] if "EXPECTED_OUTPUT" in d
97
+ ]
98
+ if expected_output and "log_hist" not in integration_test["OUTPUT_FILE"]:
99
+ # Get the expected output from the configuration file
100
+ expected_output = expected_output[0]
101
+ _logger.info(
102
+ f"Checking the output of {integration_test['OUTPUT_FILE']} "
103
+ "complies with the expected output: "
104
+ f"{expected_output}"
105
+ )
106
+ assert assertions.check_output_from_sim_telarray(output_file_path, expected_output)
107
+
108
+
109
+ def compare_files(file1, file2, tolerance=1.0e-5, test_columns=None):
110
+ """
111
+ Compare two files of file type ecsv, json or yaml.
112
+
113
+ Parameters
114
+ ----------
115
+ file1: str
116
+ First file to compare
117
+ file2: str
118
+ Second file to compare
119
+ tolerance: float
120
+ Tolerance for comparing numerical values.
121
+ test_columns: list
122
+ List of columns to compare. If None, all columns are compared.
123
+
124
+ Returns
125
+ -------
126
+ bool
127
+ True if the files are equal, False otherwise.
128
+
129
+ """
130
+ _file1_suffix = Path(file1).suffix
131
+ _file2_suffix = Path(file2).suffix
132
+ if _file1_suffix != _file2_suffix:
133
+ raise ValueError(f"File suffixes do not match: {file1} and {file2}")
134
+ if _file1_suffix == ".ecsv":
135
+ return compare_ecsv_files(file1, file2, tolerance, test_columns)
136
+ if _file1_suffix in (".json", ".yaml", ".yml"):
137
+ return compare_json_or_yaml_files(file1, file2)
138
+
139
+ _logger.warning(f"Unknown file type for files: {file1} and {file2}")
140
+ return False
141
+
142
+
143
+ def compare_json_or_yaml_files(file1, file2, tolerance=1.0e-2):
144
+ """
145
+ Compare two json or yaml files.
146
+
147
+ Take into account float comparison for sim_telarray string-embedded floats.
148
+
149
+ Parameters
150
+ ----------
151
+ file1: str
152
+ First file to compare
153
+ file2: str
154
+ Second file to compare
155
+ tolerance: float
156
+ Tolerance for comparing numerical values.
157
+
158
+ Returns
159
+ -------
160
+ bool
161
+ True if the files are equal, False otherwise.
162
+
163
+ """
164
+ data1 = gen.collect_data_from_file(file1)
165
+ data2 = gen.collect_data_from_file(file2)
166
+
167
+ _logger.debug(f"Comparing json/yaml files: {file1} and {file2}")
168
+
169
+ if data1 == data2:
170
+ return True
171
+
172
+ if "value" in data1 and isinstance(data1["value"], str):
173
+ value_list_1 = gen.convert_string_to_list(data1.pop("value"))
174
+ value_list_2 = gen.convert_string_to_list(data2.pop("value"))
175
+ return np.allclose(value_list_1, value_list_2, rtol=tolerance)
176
+ return data1 == data2
177
+
178
+
179
+ def compare_ecsv_files(file1, file2, tolerance=1.0e-5, test_columns=None):
180
+ """
181
+ Compare two ecsv files.
182
+
183
+ The comparison is successful if:
184
+
185
+ - same number of rows
186
+ - numerical values in columns are close
187
+
188
+ The comparison can be restricted to a subset of columns with some additional
189
+ cuts applied. This is configured through the test_columns parameter. This is
190
+ a list of dictionaries, where each dictionary contains the following
191
+ key-value pairs:
192
+ - TEST_COLUMN_NAME: column name to compare.
193
+ - CUT_COLUMN_NAME: column for filtering.
194
+ - CUT_CONDITION: condition for filtering.
195
+
196
+ Parameters
197
+ ----------
198
+ file1: str
199
+ First file to compare
200
+ file2: str
201
+ Second file to compare
202
+ tolerance: float
203
+ Tolerance for comparing numerical values.
204
+ test_columns: list
205
+ List of columns to compare. If None, all columns are compared.
206
+
207
+ """
208
+ _logger.info(f"Comparing files: {file1} and {file2}")
209
+ table1 = Table.read(file1, format="ascii.ecsv")
210
+ table2 = Table.read(file2, format="ascii.ecsv")
211
+
212
+ if test_columns is None:
213
+ test_columns = [{"TEST_COLUMN_NAME": col} for col in table1.colnames]
214
+
215
+ def generate_mask(table, column, condition):
216
+ """Generate a boolean mask based on the condition (note the usage of eval)."""
217
+ return (
218
+ eval(f"table['{column}'] {condition}") # pylint: disable=eval-used
219
+ if condition
220
+ else np.ones(len(table), dtype=bool)
221
+ )
222
+
223
+ for col_dict in test_columns:
224
+ col_name = col_dict["TEST_COLUMN_NAME"]
225
+ mask1 = generate_mask(
226
+ table1, col_dict.get("CUT_COLUMN_NAME", ""), col_dict.get("CUT_CONDITION", "")
227
+ )
228
+ mask2 = generate_mask(
229
+ table2, col_dict.get("CUT_COLUMN_NAME", ""), col_dict.get("CUT_CONDITION", "")
230
+ )
231
+ table1_masked, table2_masked = table1[mask1], table2[mask2]
232
+
233
+ if len(table1_masked) != len(table2_masked):
234
+ return False
235
+
236
+ if np.issubdtype(table1_masked[col_name].dtype, np.floating):
237
+ if not np.allclose(table1_masked[col_name], table2_masked[col_name], rtol=tolerance):
238
+ return False
239
+
240
+ return True