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
@@ -2,32 +2,38 @@
2
2
  Metadata collector for simtools.
3
3
 
4
4
  This should be the only module in simtools with knowledge on the
5
- implementation of the metadata model.
5
+ implementation of the observatory metadata model.
6
6
 
7
7
  """
8
+
8
9
  import datetime
9
10
  import getpass
10
11
  import logging
12
+ import uuid
13
+ from importlib.resources import files
11
14
  from pathlib import Path
12
15
 
13
- from astropy.table import Table
14
-
15
16
  import simtools.constants
16
17
  import simtools.utils.general as gen
17
18
  import simtools.version
18
19
  from simtools.data_model import metadata_model
19
20
  from simtools.io_operations import io_handler
21
+ from simtools.utils import names
20
22
 
21
23
  __all__ = ["MetadataCollector"]
22
24
 
23
25
 
24
26
  class MetadataCollector:
25
27
  """
26
- Collects and combines metadata associated to describe the current
27
- simtools activity and its data products. Collect as much metadata
28
- as possible from command line configuration, input data, environment,
29
- schema descriptions.
30
- Depends on the CTAO top-level metadata definition.
28
+ Collects metadata to describe the current simtools activity and its data products.
29
+
30
+ Collect metadata from command line configuration, input data, environment,
31
+ and schema descriptions. Depends on the CTAO top-level metadata definition.
32
+
33
+ Two dictionaries store two different types of metadata:
34
+
35
+ - top_level_meta: metadata for the current activity
36
+ - input_metadata: metadata from input data
31
37
 
32
38
  Parameters
33
39
  ----------
@@ -37,16 +43,23 @@ class MetadataCollector:
37
43
  Name of metadata file (only required when args_dict is None)
38
44
  data_model_name: str
39
45
  Name of data model parameter
40
-
46
+ observatory: str
47
+ Name of observatory (default: "cta")
48
+ clean_meta: bool
49
+ Clean metadata from None values and empty lists (default: True)
41
50
  """
42
51
 
43
- def __init__(self, args_dict, metadata_file_name=None, data_model_name=None):
44
- """
45
- Initialize metadata collector.
46
-
47
- """
48
-
52
+ def __init__(
53
+ self,
54
+ args_dict,
55
+ metadata_file_name=None,
56
+ data_model_name=None,
57
+ observatory="cta",
58
+ clean_meta=True,
59
+ ):
60
+ """Initialize metadata collector."""
49
61
  self._logger = logging.getLogger(__name__)
62
+ self.observatory = observatory
50
63
  self.io_handler = io_handler.IOHandler()
51
64
 
52
65
  self.args_dict = args_dict if args_dict else {}
@@ -60,25 +73,23 @@ class MetadataCollector:
60
73
  metadata_file_name=metadata_file_name
61
74
  )
62
75
  self.collect_meta_data()
76
+ if clean_meta:
77
+ self.top_level_meta = self.clean_meta_data(self.top_level_meta)
63
78
 
64
79
  def collect_meta_data(self):
65
- """
66
- Collect and verify product metadata from different sources.
67
-
68
- """
69
-
70
- self._fill_contact_meta(self.top_level_meta["cta"]["contact"])
71
- self._fill_product_meta(self.top_level_meta["cta"]["product"])
72
- self._fill_activity_meta(self.top_level_meta["cta"]["activity"])
73
- self._fill_process_meta(self.top_level_meta["cta"]["process"])
74
- self._fill_context_from_input_meta(self.top_level_meta["cta"]["context"])
75
- self._fill_associated_elements_from_args(
76
- self.top_level_meta["cta"]["context"]["associated_elements"]
77
- )
80
+ """Collect and verify product metadata for each main-level metadata type."""
81
+ meta_types = self.top_level_meta[self.observatory].keys()
82
+ for meta_type in meta_types:
83
+ try:
84
+ fill_method = getattr(self, f"_fill_{meta_type}_meta")
85
+ fill_method(self.top_level_meta[self.observatory][meta_type])
86
+ except AttributeError:
87
+ self._logger.debug(f"Method _fill_{meta_type}_meta not implemented")
78
88
 
79
89
  def get_data_model_schema_file_name(self):
80
90
  """
81
91
  Return data model schema file name.
92
+
82
93
  The schema file name is taken (in this order) from the command line,
83
94
  from the metadata file, from the data model name, or from the input
84
95
  metadata file.
@@ -89,38 +100,30 @@ class MetadataCollector:
89
100
  Name of schema file.
90
101
 
91
102
  """
92
-
93
103
  # from command line
94
- try:
95
- if self.args_dict["schema"]:
96
- self._logger.debug(f"Schema file from command line: {self.args_dict['schema']}")
97
- return self.args_dict["schema"]
98
- except KeyError:
99
- pass
104
+ if self.args_dict.get("schema"):
105
+ self._logger.debug(f"Schema file from command line: {self.args_dict['schema']}")
106
+ return self.args_dict["schema"]
100
107
 
101
108
  # from metadata
102
109
  try:
103
- if self.top_level_meta["cta"]["product"]["data"]["model"]["url"]:
104
- self._logger.debug(
105
- "Schema file from product metadata: "
106
- f"{self.top_level_meta['cta']['product']['data']['model']['url']}"
107
- )
108
- return self.top_level_meta["cta"]["product"]["data"]["model"]["url"]
110
+ url = self.top_level_meta[self.observatory]["product"]["data"]["model"]["url"]
111
+ if url:
112
+ self._logger.debug(f"Schema file from product metadata: {url}")
113
+ return url
109
114
  except KeyError:
110
115
  pass
111
116
 
112
117
  # from data model name
113
118
  if self.data_model_name:
114
119
  self._logger.debug(f"Schema file from data model name: {self.data_model_name}")
115
- return f"{simtools.constants.SCHEMA_URL}{self.data_model_name}.schema.yml"
120
+ return f"{files('simtools')}/schemas/model_parameters/{self.data_model_name}.schema.yml"
116
121
 
117
122
  # from input metadata
118
123
  try:
119
- self._logger.debug(
120
- "Schema file from input metadata: "
121
- f"{self.input_metadata['cta']['product']['data']['model']['url']}"
122
- )
123
- return self.input_metadata["cta"]["product"]["data"]["model"]["url"]
124
+ url = self.input_metadata[self.observatory]["product"]["data"]["model"]["url"]
125
+ self._logger.debug(f"Schema file from input metadata: {url}")
126
+ return url
124
127
  except KeyError:
125
128
  pass
126
129
 
@@ -137,109 +140,82 @@ class MetadataCollector:
137
140
  Data model schema dictionary.
138
141
 
139
142
  """
140
-
141
143
  try:
142
- return gen.collect_data_from_file_or_dict(file_name=self.schema_file, in_dict=None)
143
- except gen.InvalidConfigData:
144
+ return gen.collect_data_from_file(file_name=self.schema_file)
145
+ except TypeError:
144
146
  self._logger.debug(f"No valid schema file provided ({self.schema_file}).")
145
147
  return {}
146
148
 
147
- def _fill_contact_meta(self, contact_dict):
149
+ def get_site(self, from_input_meta=False):
148
150
  """
149
- Fill contact metadata fields.
151
+ Get site entry from metadata. Allow to get from collected or from input metadata.
150
152
 
151
153
  Parameters
152
154
  ----------
153
- contact_dict: dict
154
- Dictionary for contact metadata fields.
155
-
156
- """
155
+ from_input_meta: bool
156
+ Get site from input metadata (default: False)
157
157
 
158
- if contact_dict.get("name", None) is None:
159
- contact_dict["name"] = getpass.getuser()
158
+ Returns
159
+ -------
160
+ str
161
+ Site name
160
162
 
161
- def _fill_associated_elements_from_args(self, associated_elements_dict):
162
163
  """
163
- Append association metadata set through configurator.
164
+ try:
165
+ _site = (
166
+ self.top_level_meta[self.observatory]["instrument"]["site"]
167
+ if not from_input_meta
168
+ else self.input_metadata[self.observatory]["instrument"]["site"]
169
+ )
170
+ if _site is not None:
171
+ return names.validate_site_name(_site)
172
+ except KeyError:
173
+ pass
174
+ return None
164
175
 
165
- Note
166
- ----
167
- This function might go in future, as instrument
168
- information will not be given via command line.
176
+ def _fill_contact_meta(self, contact_dict):
177
+ """
178
+ Fill contact metadata fields. Get user name from system level if not given.
169
179
 
170
180
  Parameters
171
181
  ----------
172
- associated_elements_dict: dict
173
- Dictionary for associated elements field.
174
-
175
- Raises
176
- ------
177
- TypeError, KeyError
178
- if error reading association metadata from args.
179
- KeyError
180
- if metadata description cannot be filled.
181
-
182
+ contact_dict: dict
183
+ Dictionary for contact metadata fields.
182
184
  """
183
- self._logger.debug(f"Fill metadata from args: {self.args_dict}")
184
-
185
- _association = {}
186
-
187
- try:
188
- if "site" in self.args_dict:
189
- _association["site"] = self.args_dict["site"]
190
- if "telescope" in self.args_dict:
191
- _split_telescope_name = self.args_dict["telescope"].split("-")
192
- _association["class"] = _split_telescope_name[0]
193
- _association["type"] = _split_telescope_name[1]
194
- _association["subtype"] = _split_telescope_name[2]
195
- except (TypeError, KeyError):
196
- self._logger.error("Error reading association metadata from args")
197
- raise
198
-
199
- self._fill_context_sim_list(associated_elements_dict, _association)
185
+ if contact_dict.get("name", None) is None:
186
+ contact_dict["name"] = getpass.getuser()
200
187
 
201
- def _fill_context_from_input_meta(self, context_dict):
188
+ def _fill_context_meta(self, context_dict):
202
189
  """
203
- Read and validate input metadata from file and fill CONTEXT metadata fields.
190
+ Fill context metadata fields with product metadata from input data.
204
191
 
205
192
  Parameters
206
193
  ----------
207
194
  context_dict: dict
208
- Dictionary with context level metadata.
209
-
210
- Raises
211
- ------
212
- KeyError
213
- if corresponding fields cannot by accessed in the top-level or metadata dictionaries.
195
+ Dictionary for context metadata fields.
214
196
 
215
197
  """
216
-
217
- try:
218
- self._merge_config_dicts(context_dict, self.input_metadata["cta"]["context"])
219
- for key in ("document", "associated_elements", "associated_data"):
220
- self._copy_list_type_metadata(context_dict, self.input_metadata["cta"], key)
221
- except KeyError:
222
- self._logger.debug("No context metadata defined in input metadata file.")
223
-
224
- try:
225
- self._fill_context_sim_list(
226
- context_dict["associated_data"], self.input_metadata["cta"]["product"]
227
- )
198
+ try: # wide try..except as for some cases we expect that there is no product metadata
199
+ reduced_product_meta = {
200
+ key: value
201
+ for key, value in self.input_metadata[self.observatory]["product"].items()
202
+ if key in {"description", "id", "creation_time", "valid", "format", "filename"}
203
+ }
204
+ self._fill_context_sim_list(context_dict["associated_data"], reduced_product_meta)
228
205
  except (KeyError, TypeError):
229
206
  self._logger.debug("No input product metadata appended to associated data.")
230
207
 
231
- def _read_input_metadata_from_file(self, metadata_file_name=None, observatory="CTA"):
208
+ def _read_input_metadata_from_file(self, metadata_file_name=None):
232
209
  """
233
- Read and validate input metadata from file. In case of an ecsv file including a
234
- table, the metadata is read from the table meta data. Returns empty dict in case
235
- no file is given.
210
+ Read and validate input metadata from file.
211
+
212
+ In case of an ecsv file including a table, the metadata is read from the table meta data.
213
+ Returns empty dict in case no file is given.
236
214
 
237
215
  Parameter
238
216
  ---------
239
217
  metadata_file_name: str or Path
240
218
  Name of metadata file.
241
- observatory: str
242
- Observatory name.
243
219
 
244
220
  Returns
245
221
  -------
@@ -248,58 +224,30 @@ class MetadataCollector:
248
224
 
249
225
  Raises
250
226
  ------
251
- gen.InvalidConfigData, FileNotFoundError
227
+ gen.InvalidConfigDataError, FileNotFoundError
252
228
  if metadata cannot be read from file.
253
229
  KeyError:
254
- if metadata does not exist for the given observatory.
230
+ if metadata does not exist
255
231
 
256
232
  """
257
-
258
- try:
259
- metadata_file_name = (
260
- self.args_dict.get("input_meta", None)
261
- if metadata_file_name is None
262
- else metadata_file_name
263
- )
264
- except TypeError:
265
- pass
233
+ metadata_file_name = (
234
+ self.args_dict.get("input_meta", None) or self.args_dict.get("input", None)
235
+ if metadata_file_name is None
236
+ else metadata_file_name
237
+ )
266
238
 
267
239
  if metadata_file_name is None:
268
240
  self._logger.debug("No input metadata file defined.")
269
241
  return {}
270
242
 
271
- # metadata from yml or json file
243
+ self._logger.debug("Reading meta data from %s", metadata_file_name)
272
244
  if Path(metadata_file_name).suffix in (".yaml", ".yml", ".json"):
273
- try:
274
- self._logger.debug("Reading meta data from %s", metadata_file_name)
275
- _input_metadata = gen.collect_data_from_file_or_dict(
276
- file_name=metadata_file_name, in_dict=None
277
- )
278
- _json_type_metadata = {"Metadata", "metadata", "METADATA"}.intersection(
279
- _input_metadata
280
- )
281
- if len(_json_type_metadata) == 1:
282
- _input_metadata = _input_metadata[_json_type_metadata.pop()]
283
- elif len(_json_type_metadata) > 1:
284
- self._logger.error(
285
- "More than one metadata entry found in %s", metadata_file_name
286
- )
287
- raise gen.InvalidConfigData
288
- except (gen.InvalidConfigData, FileNotFoundError):
289
- self._logger.error("Failed reading metadata from %s", metadata_file_name)
290
- raise
291
- # metadata from table meta in ecsv file
245
+ _input_metadata = self._read_input_metadata_from_yml_or_json(metadata_file_name)
292
246
  elif Path(metadata_file_name).suffix == ".ecsv":
293
- try:
294
- _input_metadata = {observatory: Table.read(metadata_file_name).meta[observatory]}
295
- except (FileNotFoundError, KeyError):
296
- self._logger.error(
297
- "Failed reading metadata for %s from %s", observatory, metadata_file_name
298
- )
299
- raise
247
+ _input_metadata = self._read_input_metadata_from_ecsv(metadata_file_name)
300
248
  else:
301
249
  self._logger.error("Unknown metadata file format: %s", metadata_file_name)
302
- raise gen.InvalidConfigData
250
+ raise gen.InvalidConfigDataError
303
251
 
304
252
  metadata_model.validate_schema(_input_metadata, None)
305
253
 
@@ -308,10 +256,43 @@ class MetadataCollector:
308
256
  lower_case=True,
309
257
  )
310
258
 
259
+ def _read_input_metadata_from_ecsv(self, metadata_file_name):
260
+ """Read input metadata from ecsv file."""
261
+ from astropy.table import Table # pylint: disable=C0415
262
+
263
+ try:
264
+ return {
265
+ self.observatory.upper(): Table.read(metadata_file_name).meta[
266
+ self.observatory.upper()
267
+ ]
268
+ }
269
+ except (FileNotFoundError, KeyError, AttributeError) as exc:
270
+ self._logger.error(
271
+ "Failed reading metadata for %s from %s", self.observatory, metadata_file_name
272
+ )
273
+ raise exc
274
+
275
+ def _read_input_metadata_from_yml_or_json(self, metadata_file_name):
276
+ """Read input metadata from yml or json file."""
277
+ try:
278
+ _input_metadata = gen.collect_data_from_file(file_name=metadata_file_name)
279
+ _json_type_metadata = {"Metadata", "metadata", "METADATA"}.intersection(_input_metadata)
280
+ if len(_json_type_metadata) == 1:
281
+ _input_metadata = _input_metadata[_json_type_metadata.pop()]
282
+ if len(_json_type_metadata) > 1:
283
+ self._logger.error("More than one metadata entry found in %s", metadata_file_name)
284
+ raise gen.InvalidConfigDataError
285
+ except (gen.InvalidConfigDataError, FileNotFoundError) as exc:
286
+ self._logger.error("Failed reading metadata from %s", metadata_file_name)
287
+ raise exc
288
+ return _input_metadata
289
+
311
290
  def _fill_product_meta(self, product_dict):
312
291
  """
313
- Fill metadata for data products fields. If a schema file is given for the data products,
314
- try and read product:data:model metadata from there.
292
+ Fill metadata for data products fields.
293
+
294
+ If a schema file is given for the data products, try and read product:data:model metadata
295
+ from there.
315
296
 
316
297
  Parameters
317
298
  ----------
@@ -324,11 +305,10 @@ class MetadataCollector:
324
305
  if relevant fields are not defined in top level metadata dictionary.
325
306
 
326
307
  """
327
-
328
308
  self.schema_file = self.get_data_model_schema_file_name()
329
309
  self.schema_dict = self.get_data_model_schema_dict()
330
310
 
331
- product_dict["id"] = self.args_dict.get("activity_id", "UNDEFINED_ACTIVITY_ID")
311
+ product_dict["id"] = str(uuid.uuid4())
332
312
  product_dict["creation_time"] = datetime.datetime.now().isoformat(timespec="seconds")
333
313
  product_dict["description"] = self.schema_dict.get("description", None)
334
314
 
@@ -342,7 +322,7 @@ class MetadataCollector:
342
322
  pass
343
323
 
344
324
  # DATA:MODEL
345
- helper_dict = {"name": "name", "version": "version", "type": "base_schema"}
325
+ helper_dict = {"name": "name", "version": "version", "type": "meta_schema"}
346
326
  for key, value in helper_dict.items():
347
327
  product_dict["data"]["model"][key] = self.schema_dict.get(value, None)
348
328
  product_dict["data"]["model"]["url"] = self.schema_file
@@ -350,6 +330,28 @@ class MetadataCollector:
350
330
  product_dict["format"] = self.args_dict.get("output_file_format", None)
351
331
  product_dict["filename"] = str(self.args_dict.get("output_file", None))
352
332
 
333
+ def _fill_instrument_meta(self, instrument_dict):
334
+ """
335
+ Fill instrument metadata fields.
336
+
337
+ Note inconsistency in command line arguments for 'ID',
338
+ which is either 'instrument' or 'telescope'.
339
+
340
+ Parameters
341
+ ----------
342
+ instrument_dict: dict
343
+ Dictionary for instrument metadata fields.
344
+
345
+ """
346
+ instrument_dict["site"] = self.args_dict.get("site", None)
347
+ instrument_dict["ID"] = self.args_dict.get("instrument") or self.args_dict.get(
348
+ "telescope", None
349
+ )
350
+ if instrument_dict["ID"]:
351
+ instrument_dict["class"] = names.get_collection_name_from_array_element_name(
352
+ instrument_dict["ID"]
353
+ )
354
+
353
355
  def _fill_process_meta(self, process_dict):
354
356
  """
355
357
  Fill process fields in metadata.
@@ -360,12 +362,11 @@ class MetadataCollector:
360
362
  Dictionary for process metadata fields.
361
363
 
362
364
  """
363
-
364
365
  process_dict["type"] = "simulation"
365
366
 
366
367
  def _fill_activity_meta(self, activity_dict):
367
368
  """
368
- Fill activity (software) related metadata
369
+ Fill activity (software) related metadata.
369
370
 
370
371
  Parameters
371
372
  ----------
@@ -373,7 +374,6 @@ class MetadataCollector:
373
374
  Dictionary for top-level activity metadata.
374
375
 
375
376
  """
376
-
377
377
  activity_dict["name"] = self.args_dict.get("label", None)
378
378
  activity_dict["type"] = "software"
379
379
  activity_dict["id"] = self.args_dict.get("activity_id", "UNDEFINED_ACTIVITY_ID")
@@ -384,8 +384,9 @@ class MetadataCollector:
384
384
 
385
385
  def _merge_config_dicts(self, dict_high, dict_low, add_new_fields=False):
386
386
  """
387
- Merge two config dicts and replace values in dict_high which are Nonetype. Priority to \
388
- dict_high in case of conflicting entries.
387
+ Merge two config dicts and replace values in dict_high which are Nonetype.
388
+
389
+ Priority to dict_high in case of conflicting entries.
389
390
 
390
391
  Parameters
391
392
  ----------
@@ -397,11 +398,6 @@ class MetadataCollector:
397
398
  If true: add fields from dict_low to dict_high, if they don't exist in dict_high
398
399
 
399
400
  """
400
-
401
- if dict_high is None and dict_low:
402
- dict_high = dict_low
403
- return
404
-
405
401
  try:
406
402
  for k in dict_low:
407
403
  if k in dict_high:
@@ -416,14 +412,14 @@ class MetadataCollector:
416
412
  )
417
413
  elif add_new_fields:
418
414
  dict_high[k] = dict_low[k]
419
- except (KeyError, TypeError):
420
- self._logger.error("Error merging dictionaries")
421
- raise
415
+ except TypeError as exc:
416
+ raise TypeError("Error merging dictionaries") from exc
422
417
 
423
418
  def _fill_context_sim_list(self, meta_list, new_entry_dict):
424
419
  """
425
- Fill list-type entries into metadata. Take into account the first list entry is the default
426
- value filled with Nones.
420
+ Fill list-type entries into metadata.
421
+
422
+ Take into account the first list entry is the default value filled with Nones.
427
423
 
428
424
  Parameters
429
425
  ----------
@@ -438,7 +434,6 @@ class MetadataCollector:
438
434
  Updated meta list.
439
435
 
440
436
  """
441
-
442
437
  if len(new_entry_dict) == 0:
443
438
  return []
444
439
  try:
@@ -453,6 +448,7 @@ class MetadataCollector:
453
448
  def _process_metadata_from_file(self, meta_dict):
454
449
  """
455
450
  Process metadata from file to ensure compatibility with metadata model.
451
+
456
452
  Changes keys to lower case and removes line feeds from description fields.
457
453
 
458
454
  Parameters
@@ -466,11 +462,10 @@ class MetadataCollector:
466
462
  Metadata dictionary.
467
463
 
468
464
  """
469
-
470
465
  meta_dict = gen.change_dict_keys_case(meta_dict, True)
471
466
  try:
472
- meta_dict["cta"]["product"]["description"] = self._remove_line_feed(
473
- meta_dict["cta"]["product"]["description"]
467
+ meta_dict[self.observatory]["product"]["description"] = self._remove_line_feed(
468
+ meta_dict[self.observatory]["product"]["description"]
474
469
  )
475
470
  except (KeyError, AttributeError):
476
471
  pass
@@ -480,7 +475,7 @@ class MetadataCollector:
480
475
  @staticmethod
481
476
  def _remove_line_feed(string):
482
477
  """
483
- Remove all line feeds from a string
478
+ Remove all line feeds from a string.
484
479
 
485
480
  Parameters
486
481
  ----------
@@ -492,12 +487,12 @@ class MetadataCollector:
492
487
  str
493
488
  with line feeds removed
494
489
  """
495
-
496
490
  return string.replace("\n", " ").replace("\r", "").replace(" ", " ")
497
491
 
498
492
  def _copy_list_type_metadata(self, context_dict, _input_metadata, key):
499
493
  """
500
494
  Copy list-type metadata from file.
495
+
501
496
  Very fine tuned.
502
497
 
503
498
  Parameters
@@ -510,7 +505,6 @@ class MetadataCollector:
510
505
  Key for metadata entry.
511
506
 
512
507
  """
513
-
514
508
  try:
515
509
  for document in _input_metadata["context"][key]:
516
510
  self._fill_context_sim_list(context_dict[key], document)
@@ -532,8 +526,40 @@ class MetadataCollector:
532
526
  True if all entries are None, False otherwise.
533
527
 
534
528
  """
535
-
536
529
  if not isinstance(input_dict, dict):
537
530
  return input_dict is None
538
531
 
539
532
  return all(self._all_values_none(value) for value in input_dict.values())
533
+
534
+ def clean_meta_data(self, meta_dict):
535
+ """
536
+ Clean metadata dictionary from None values and empty lists.
537
+
538
+ Parameters
539
+ ----------
540
+ meta_dict: dict
541
+ Metadata dictionary.
542
+
543
+ """
544
+
545
+ def clean_list(value):
546
+ nested_list = [
547
+ self.clean_meta_data(item) if isinstance(item, dict) else item for item in value
548
+ ]
549
+ return [item for item in nested_list if item not in (None, "", [], {})]
550
+
551
+ cleaned = {}
552
+ for key, value in meta_dict.items():
553
+ if value in (None, []):
554
+ continue
555
+ if isinstance(value, dict):
556
+ nested = self.clean_meta_data(value)
557
+ if nested: # Only add if not empty
558
+ cleaned[key] = nested
559
+ elif isinstance(value, list):
560
+ nested_list = clean_list(value)
561
+ if nested_list: # Only add if not empty
562
+ cleaned[key] = nested_list
563
+ else:
564
+ cleaned[key] = value
565
+ return cleaned