gammasimtools 0.12.0__py3-none-any.whl → 0.14.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. {gammasimtools-0.12.0.dist-info → gammasimtools-0.14.0.dist-info}/METADATA +3 -3
  2. {gammasimtools-0.12.0.dist-info → gammasimtools-0.14.0.dist-info}/RECORD +257 -263
  3. {gammasimtools-0.12.0.dist-info → gammasimtools-0.14.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.12.0.dist-info → gammasimtools-0.14.0.dist-info}/entry_points.txt +4 -1
  5. simtools/_version.py +2 -2
  6. simtools/applications/convert_all_model_parameters_from_simtel.py +77 -88
  7. simtools/applications/convert_geo_coordinates_of_array_elements.py +1 -1
  8. simtools/applications/db_add_file_to_db.py +15 -0
  9. simtools/applications/db_add_value_from_json_to_db.py +18 -1
  10. simtools/applications/db_get_parameter_from_db.py +52 -22
  11. simtools/applications/derive_ctao_array_layouts.py +120 -0
  12. simtools/applications/derive_photon_electron_spectrum.py +30 -2
  13. simtools/applications/docs_produce_array_element_report.py +42 -26
  14. simtools/applications/docs_produce_model_parameter_reports.py +28 -21
  15. simtools/applications/generate_simtel_event_data.py +117 -0
  16. simtools/applications/plot_tabular_data.py +14 -2
  17. simtools/applications/print_version.py +81 -0
  18. simtools/applications/production_derive_corsika_limits.py +240 -0
  19. simtools/applications/production_scale_events.py +59 -36
  20. simtools/applications/run_application.py +47 -18
  21. simtools/applications/simulate_light_emission.py +115 -247
  22. simtools/applications/simulate_prod_htcondor_generator.py +2 -2
  23. simtools/applications/submit_data_from_external.py +1 -1
  24. simtools/applications/submit_model_parameter_from_external.py +2 -1
  25. simtools/camera/single_photon_electron_spectrum.py +169 -17
  26. simtools/constants.py +7 -0
  27. simtools/data_model/metadata_collector.py +159 -61
  28. simtools/data_model/model_data_writer.py +18 -61
  29. simtools/data_model/schema.py +2 -1
  30. simtools/data_model/validate_data.py +5 -3
  31. simtools/db/db_handler.py +123 -33
  32. simtools/dependencies.py +38 -3
  33. simtools/layout/array_layout.py +1 -0
  34. simtools/layout/ctao_array_layouts.py +172 -0
  35. simtools/model/array_model.py +3 -4
  36. simtools/model/model_parameter.py +30 -118
  37. simtools/production_configuration/derive_corsika_limits.py +328 -0
  38. simtools/production_configuration/event_scaler.py +2 -2
  39. simtools/ray_tracing/mirror_panel_psf.py +1 -1
  40. simtools/reporting/docs_auto_report_generator.py +217 -0
  41. simtools/reporting/docs_read_parameters.py +298 -143
  42. simtools/schemas/application_workflow.metaschema.yml +3 -0
  43. simtools/schemas/metadata.metaschema.yml +7 -6
  44. simtools/schemas/model_parameter.metaschema.yml +13 -4
  45. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +19 -5
  46. simtools/schemas/model_parameters/adjust_gain.schema.yml +1 -1
  47. simtools/schemas/model_parameters/altitude.schema.yml +1 -1
  48. simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
  49. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +3 -3
  50. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +3 -3
  51. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +3 -3
  52. simtools/schemas/model_parameters/array_layouts.schema.yml +3 -0
  53. simtools/schemas/model_parameters/array_window.schema.yml +1 -1
  54. simtools/schemas/model_parameters/asum_clipping.schema.yml +1 -1
  55. simtools/schemas/model_parameters/asum_offset.schema.yml +1 -1
  56. simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
  57. simtools/schemas/model_parameters/asum_threshold.schema.yml +1 -1
  58. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +1 -1
  59. simtools/schemas/model_parameters/axes_offsets.schema.yml +2 -2
  60. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +1 -1
  61. simtools/schemas/model_parameters/camera_body_shape.schema.yml +1 -1
  62. simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
  63. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +1 -1
  64. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +1 -1
  65. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
  66. simtools/schemas/model_parameters/camera_depth.schema.yml +1 -1
  67. simtools/schemas/model_parameters/camera_filter.schema.yml +1 -1
  68. simtools/schemas/model_parameters/camera_pixels.schema.yml +1 -1
  69. simtools/schemas/model_parameters/camera_transmission.schema.yml +1 -1
  70. simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
  71. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +1 -1
  72. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +1 -1
  73. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +1 -1
  74. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +1 -1
  75. simtools/schemas/model_parameters/dark_events.schema.yml +1 -1
  76. simtools/schemas/model_parameters/disc_bins.schema.yml +1 -1
  77. simtools/schemas/model_parameters/disc_start.schema.yml +1 -1
  78. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +1 -1
  79. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +1 -1
  80. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +1 -1
  81. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +1 -1
  82. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +1 -1
  83. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +1 -1
  84. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +1 -1
  85. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +1 -1
  86. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +1 -1
  87. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +1 -1
  88. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -1
  89. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +1 -1
  90. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +1 -1
  91. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +1 -1
  92. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +1 -1
  93. simtools/schemas/model_parameters/dish_shape_length.schema.yml +1 -1
  94. simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -1
  95. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +1 -1
  96. simtools/schemas/model_parameters/dsum_offset.schema.yml +1 -1
  97. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +1 -1
  98. simtools/schemas/model_parameters/dsum_prescale.schema.yml +2 -2
  99. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +1 -1
  100. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +1 -1
  101. simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
  102. simtools/schemas/model_parameters/dsum_threshold.schema.yml +1 -1
  103. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +1 -1
  104. simtools/schemas/model_parameters/effective_focal_length.schema.yml +5 -5
  105. simtools/schemas/model_parameters/epsg_code.schema.yml +1 -1
  106. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +1 -1
  107. simtools/schemas/model_parameters/fadc_bins.schema.yml +1 -1
  108. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
  109. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +2 -2
  110. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +1 -1
  111. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +1 -1
  112. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +1 -1
  113. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
  114. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +2 -2
  115. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +1 -1
  116. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +1 -1
  117. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +1 -1
  118. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +4 -4
  119. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +1 -1
  120. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +1 -1
  121. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +1 -1
  122. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +1 -1
  123. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +1 -1
  124. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +1 -1
  125. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +1 -1
  126. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +4 -4
  127. simtools/schemas/model_parameters/fadc_mhz.schema.yml +1 -1
  128. simtools/schemas/model_parameters/fadc_noise.schema.yml +1 -1
  129. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +1 -1
  130. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +1 -1
  131. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +1 -1
  132. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +1 -1
  133. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +1 -1
  134. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +1 -1
  135. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +1 -1
  136. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  137. simtools/schemas/model_parameters/focal_length.schema.yml +1 -1
  138. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +20 -20
  139. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +1 -1
  140. simtools/schemas/model_parameters/focus_offset.schema.yml +4 -4
  141. simtools/schemas/model_parameters/gain_variation.schema.yml +1 -1
  142. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +1 -1
  143. simtools/schemas/model_parameters/geomag_rotation.schema.yml +1 -1
  144. simtools/schemas/model_parameters/geomag_vertical.schema.yml +1 -1
  145. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +1 -1
  146. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
  147. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
  148. simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
  149. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +1 -1
  150. simtools/schemas/model_parameters/laser_photons.schema.yml +1 -1
  151. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +1 -1
  152. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +1 -1
  153. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +1 -1
  154. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +1 -1
  155. simtools/schemas/model_parameters/laser_var_photons.schema.yml +1 -1
  156. simtools/schemas/model_parameters/laser_wavelength.schema.yml +1 -1
  157. simtools/schemas/model_parameters/led_events.schema.yml +1 -1
  158. simtools/schemas/model_parameters/led_photons.schema.yml +1 -1
  159. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +1 -1
  160. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +1 -1
  161. simtools/schemas/model_parameters/led_var_photons.schema.yml +1 -1
  162. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
  163. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +1 -1
  164. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
  165. simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
  166. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +1 -1
  167. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +4 -4
  168. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +4 -4
  169. simtools/schemas/model_parameters/mirror_class.schema.yml +1 -1
  170. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +1 -1
  171. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +1 -1
  172. simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
  173. simtools/schemas/model_parameters/mirror_offset.schema.yml +1 -1
  174. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +3 -3
  175. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +3 -3
  176. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +1 -1
  177. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +45 -0
  178. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +2 -2
  179. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +1 -1
  180. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +5 -5
  181. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +1 -1
  182. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
  183. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +1 -1
  184. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +1 -1
  185. simtools/schemas/model_parameters/{nsb_skymap.schema.yml → nsb_sky_map.schema.yml} +1 -1
  186. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +2 -2
  187. simtools/schemas/model_parameters/num_gains.schema.yml +1 -1
  188. simtools/schemas/model_parameters/pedestal_events.schema.yml +1 -1
  189. simtools/schemas/model_parameters/photon_delay.schema.yml +1 -1
  190. simtools/schemas/model_parameters/photons_per_run.schema.yml +1 -1
  191. simtools/schemas/model_parameters/pixel_cells.schema.yml +1 -1
  192. simtools/schemas/model_parameters/pixels_parallel.schema.yml +1 -1
  193. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +1 -1
  194. simtools/schemas/model_parameters/pm_average_gain.schema.yml +1 -1
  195. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +1 -1
  196. simtools/schemas/model_parameters/pm_gain_index.schema.yml +1 -1
  197. simtools/schemas/model_parameters/pm_transit_time.schema.yml +4 -4
  198. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +1 -1
  199. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +8 -4
  200. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +1 -1
  201. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +1 -1
  202. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +20 -20
  203. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +1 -1
  204. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
  205. simtools/schemas/model_parameters/qe_variation.schema.yml +1 -1
  206. simtools/schemas/model_parameters/random_focal_length.schema.yml +2 -2
  207. simtools/schemas/model_parameters/random_mono_probability.schema.yml +38 -0
  208. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +1 -1
  209. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +4 -1
  210. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +4 -1
  211. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +1 -1
  212. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +1 -1
  213. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +5 -5
  214. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
  215. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
  216. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +1 -1
  217. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +1 -1
  218. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +20 -20
  219. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +1 -1
  220. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
  221. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +1 -1
  222. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +1 -1
  223. simtools/schemas/model_parameters/stars.schema.yml +36 -0
  224. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
  225. simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
  226. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +1 -1
  227. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +1 -1
  228. simtools/schemas/model_parameters/telescope_random_error.schema.yml +1 -1
  229. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +1 -1
  230. simtools/schemas/model_parameters/telescope_transmission.schema.yml +6 -6
  231. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +1 -1
  232. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +1 -1
  233. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +1 -1
  234. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +1 -1
  235. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +1 -1
  236. simtools/schemas/model_parameters/transit_time_error.schema.yml +1 -1
  237. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +1 -1
  238. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +1 -1
  239. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +4 -4
  240. simtools/schemas/model_parameters/trigger_pixels.schema.yml +1 -1
  241. simtools/schemas/plot_configuration.metaschema.yml +162 -0
  242. simtools/schemas/production_tables.schema.yml +1 -1
  243. simtools/simtel/simtel_config_reader.py +85 -34
  244. simtools/simtel/simtel_config_writer.py +70 -38
  245. simtools/simtel/simtel_io_event_reader.py +278 -0
  246. simtools/simtel/simtel_io_event_writer.py +317 -0
  247. simtools/simtel/simtel_table_reader.py +4 -0
  248. simtools/simtel/simulator_light_emission.py +181 -67
  249. simtools/simulator.py +2 -2
  250. simtools/testing/configuration.py +17 -0
  251. simtools/utils/general.py +83 -16
  252. simtools/utils/geometry.py +19 -0
  253. simtools/utils/names.py +14 -3
  254. simtools/visualization/plot_tables.py +25 -20
  255. simtools/visualization/visualize.py +73 -25
  256. simtools/_dev_version/__init__.py +0 -9
  257. simtools/applications/__init__.py +0 -0
  258. simtools/applications/production_derive_limits.py +0 -95
  259. simtools/configuration/__init__.py +0 -0
  260. simtools/corsika/__init__.py +0 -0
  261. simtools/data_model/__init__.py +0 -0
  262. simtools/db/__init__.py +0 -0
  263. simtools/io_operations/__init__.py +0 -0
  264. simtools/job_execution/__init__.py +0 -0
  265. simtools/layout/__init__.py +0 -0
  266. simtools/model/__init__.py +0 -0
  267. simtools/production_configuration/limits_calculation.py +0 -202
  268. simtools/ray_tracing/__init__.py +0 -0
  269. simtools/runners/__init__.py +0 -0
  270. simtools/simtel/__init__.py +0 -0
  271. simtools/simtel/simtel_io_events.py +0 -265
  272. simtools/testing/__init__.py +0 -0
  273. simtools/utils/__init__.py +0 -0
  274. simtools/visualization/__init__.py +0 -0
  275. {gammasimtools-0.12.0.dist-info → gammasimtools-0.14.0.dist-info/licenses}/LICENSE +0 -0
  276. {gammasimtools-0.12.0.dist-info → gammasimtools-0.14.0.dist-info}/top_level.txt +0 -0
@@ -7,10 +7,12 @@ import tempfile
7
7
  from io import BytesIO
8
8
  from pathlib import Path
9
9
 
10
+ import numpy as np
10
11
  from astropy.table import Table
12
+ from scipy.optimize import curve_fit
11
13
 
12
14
  import simtools.data_model.model_data_writer as writer
13
- from simtools.constants import SCHEMA_PATH
15
+ from simtools.constants import MODEL_PARAMETER_SCHEMA_URL, SCHEMA_PATH
14
16
  from simtools.data_model import validate_data
15
17
  from simtools.data_model.metadata_collector import MetadataCollector
16
18
  from simtools.io_operations import io_handler
@@ -44,12 +46,24 @@ class SinglePhotonElectronSpectrum:
44
46
  )
45
47
  self.io_handler = io_handler.IOHandler()
46
48
  self.data = "" # Single photon electron spectrum data (as string)
49
+ self.args_dict["metadata_product_data_name"] = "single_pe_spectrum"
50
+ self.args_dict["metadata_product_data_url"] = (
51
+ MODEL_PARAMETER_SCHEMA_URL + "/pm_photoelectron_spectrum.schema.yml"
52
+ )
47
53
  self.metadata = MetadataCollector(args_dict=self.args_dict)
48
54
 
49
55
  def derive_single_pe_spectrum(self):
50
56
  """Derive single photon electron spectrum."""
57
+ afterpulse_fitted_spectrum = (
58
+ self.fit_afterpulse_spectrum() if self.args_dict.get("fit_afterpulse") else None
59
+ )
60
+
51
61
  if self.args_dict.get("use_norm_spe"):
52
- return self._derive_spectrum_norm_spe()
62
+ return self._derive_spectrum_norm_spe(
63
+ input_spectrum=self.args_dict["input_spectrum"],
64
+ afterpulse_spectrum=self.args_dict.get("afterpulse_spectrum"),
65
+ afterpulse_fitted_spectrum=afterpulse_fitted_spectrum,
66
+ )
53
67
 
54
68
  raise NotImplementedError(
55
69
  "Derivation of single photon electron spectrum using a simtool is not yet implemented."
@@ -83,15 +97,27 @@ class SinglePhotonElectronSpectrum:
83
97
 
84
98
  writer.ModelDataWriter.dump(
85
99
  args_dict=self.args_dict,
86
- metadata=self.metadata.top_level_meta,
100
+ metadata=self.metadata,
87
101
  product_data=table,
88
102
  validate_schema_file=None,
89
103
  )
90
104
 
91
- def _derive_spectrum_norm_spe(self):
105
+ def _derive_spectrum_norm_spe(
106
+ self, input_spectrum, afterpulse_spectrum, afterpulse_fitted_spectrum
107
+ ):
92
108
  """
93
109
  Derive single photon electron spectrum using sim_telarray tool 'norm_spe'.
94
110
 
111
+ Parameters
112
+ ----------
113
+ input_spectrum : str
114
+ Input file with amplitude spectrum
115
+ (prompt spectrum only if afterpulse spectrum is given).
116
+ afterpulse_spectrum : str
117
+ Input file with afterpulse spectrum.
118
+ afterpulse_fitted_spectrum : astro.Table
119
+ Fitted afterpulse spectrum data.
120
+
95
121
  Returns
96
122
  -------
97
123
  int
@@ -103,11 +129,13 @@ class SinglePhotonElectronSpectrum:
103
129
  If the command execution fails.
104
130
  """
105
131
  tmp_input_file = self._get_input_data(
106
- input_file=self.args_dict["input_spectrum"],
132
+ input_file=input_spectrum,
133
+ input_table=None,
107
134
  frequency_column=self.prompt_column,
108
135
  )
109
136
  tmp_ap_file = self._get_input_data(
110
- input_file=self.args_dict.get("afterpulse_spectrum"),
137
+ input_file=afterpulse_spectrum,
138
+ input_table=afterpulse_fitted_spectrum,
111
139
  frequency_column=self.afterpulse_column,
112
140
  )
113
141
 
@@ -115,13 +143,14 @@ class SinglePhotonElectronSpectrum:
115
143
  f"{self.args_dict['simtel_path']}/sim_telarray/bin/norm_spe",
116
144
  "-r",
117
145
  f"{self.args_dict['step_size']},{self.args_dict['max_amplitude']}",
118
- tmp_input_file.name,
119
146
  ]
120
147
  if tmp_ap_file:
121
- command.insert(1, "-a")
122
- command.insert(2, f"{tmp_ap_file.name}")
148
+ command.extend(["-a", f"{tmp_ap_file.name}"])
149
+ command.extend(["-s", f"{self.args_dict['scale_afterpulse_spectrum']}"])
150
+ command.extend(["-t", f"{self.args_dict['afterpulse_amplitude_range'][0]}"])
151
+ command.append(tmp_input_file.name)
123
152
 
124
- self._logger.debug(f"Running norm_spe command: {' '.join(command)}")
153
+ self._logger.info(f"Running norm_spe command: {' '.join(command)}")
125
154
  try:
126
155
  result = subprocess.run(command, capture_output=True, text=True, check=True)
127
156
  except subprocess.CalledProcessError as exc:
@@ -138,24 +167,37 @@ class SinglePhotonElectronSpectrum:
138
167
  self.data = result.stdout
139
168
  return result.returncode
140
169
 
141
- def _get_input_data(self, input_file, frequency_column):
170
+ def _get_input_data(self, input_file, input_table, frequency_column):
142
171
  """
143
- Return input data for norm_spe command.
172
+ Return input data in the format required by the norm_spe tool as temporary file.
173
+
174
+ The norm_spe tool requires the data to be space separated values of the amplitude spectrum,
175
+ with two columns: amplitude and frequency.
176
+ Input is validated using the single_pe_spectrum schema (legacy input is not validated).
144
177
 
145
- Input data need to be space separated values of the amplitude spectrum.
178
+ Parameters
179
+ ----------
180
+ input_file : str
181
+ Input file with amplitude spectrum.
182
+ input_table : astro.Table
183
+ Input table with amplitude spectrum.
184
+ frequency_column : str
185
+ Column name of the frequency data.
146
186
  """
147
- input_data = ""
148
187
  if not input_file:
149
188
  return None
150
189
  input_file = Path(input_file)
151
190
 
152
- if input_file.suffix == ".ecsv":
191
+ input_data = ""
192
+ if input_file.suffix == ".ecsv" or input_table:
153
193
  data_validator = validate_data.DataValidator(
154
- schema_file=self.input_schema, data_file=input_file
194
+ schema_file=self.input_schema,
195
+ data_table=input_table,
196
+ data_file=input_file if input_table is None else None,
155
197
  )
156
198
  table = data_validator.validate_and_transform()
157
199
  input_data = "\n".join(f"{row['amplitude']} {row[frequency_column]}" for row in table)
158
- else:
200
+ else: # legacy format
159
201
  with open(input_file, encoding="utf-8") as f:
160
202
  input_data = (
161
203
  f.read().replace(",", " ")
@@ -166,3 +208,113 @@ class SinglePhotonElectronSpectrum:
166
208
  with tempfile.NamedTemporaryFile(delete=False, mode="w", encoding="utf-8") as tmpfile:
167
209
  tmpfile.write(input_data)
168
210
  return tmpfile
211
+
212
+ def fit_afterpulse_spectrum(self):
213
+ """
214
+ Fit afterpulse spectrum with a exponential decay function.
215
+
216
+ Assume input to be in ecsv format with columns 'amplitude', 'frequency (afterpulsing)',
217
+ and 'frequency stdev (afterpulsing)'.
218
+
219
+ Returns
220
+ -------
221
+ astro.Table
222
+ Table with fitted afterpulse spectrum data.
223
+ """
224
+ ap_min = self.args_dict["afterpulse_amplitude_range"][0]
225
+ fix_k = self.args_dict.get("afterpulse_decay_factor_fixed_value")
226
+
227
+ x, y, y_err = self._read_afterpulse_spectrum_for_fit(
228
+ self.args_dict.get("afterpulse_spectrum"), ap_min
229
+ )
230
+ fit_func, p0, bounds = self.afterpulse_fit_function(fix_k=fix_k)
231
+
232
+ result = curve_fit(fit_func, x, y, sigma=y_err, p0=p0, bounds=bounds, absolute_sigma=True)
233
+ params, covariance = result[0], result[1]
234
+ param_errors = np.sqrt(np.diag(covariance))
235
+ predicted = fit_func(x, *params)
236
+ self._afterpulse_fit_statistics(x, y, y_err, params, param_errors, predicted, fix_k)
237
+
238
+ # table with fitted afterpulse spectrum
239
+ x_fit = np.arange(
240
+ ap_min, self.args_dict["afterpulse_amplitude_range"][1], self.args_dict["step_size"]
241
+ )
242
+ y_fit = fit_func(x_fit, *params)
243
+ return Table([x_fit, y_fit], names=["amplitude", self.afterpulse_column])
244
+
245
+ def afterpulse_fit_function(self, fix_k):
246
+ """
247
+ Afterpulse fit function: exponential decay with linear term in the exponent.
248
+
249
+ Starting values and bounds are set for the other parameters using values typical
250
+ for LSTN-design. Allows to fix the K parameter.
251
+
252
+ Parameters
253
+ ----------
254
+ fix_K : float
255
+ Fixed value for K parameter.
256
+
257
+ Returns
258
+ -------
259
+ function
260
+ Exponential decay function with linear term in the exponent.
261
+ """
262
+
263
+ def exp_decay(x, a, b, k):
264
+ return a * np.exp(-1.0 / (b * (k / (x + k))) * x)
265
+
266
+ p0 = [1e-5, 8.0] # Initial guess for [A, B] typical LSTN values
267
+ bounds_lower = [0, 0]
268
+ bounds_upper = [1.0, 20.0]
269
+
270
+ if fix_k is None:
271
+ p0.append(25.0)
272
+ bounds_lower.append(5.0)
273
+ bounds_upper.append(35.0)
274
+ return exp_decay, p0, (bounds_lower, bounds_upper)
275
+
276
+ def exp_decay_fixed_k(x, a, b):
277
+ return exp_decay(x, a, b, k=fix_k)
278
+
279
+ return exp_decay_fixed_k, p0, (bounds_lower, bounds_upper)
280
+
281
+ def _afterpulse_fit_statistics(self, x, y, y_err, params, param_errors, predicted, fix_k):
282
+ """Print and return afterpulse fit statistics."""
283
+ chi2 = np.sum(((y - predicted) / y_err) ** 2)
284
+ ndf = len(x) - len(params)
285
+
286
+ result = {
287
+ "params": params.tolist(),
288
+ "errors": param_errors.tolist(),
289
+ "chi2_ndf": chi2 / ndf if ndf > 0 else np.nan,
290
+ }
291
+ if fix_k is not None:
292
+ result["params"].append(fix_k)
293
+ result["errors"].append(0.0)
294
+
295
+ self._logger.info(f"Fit results: {result}")
296
+ return result
297
+
298
+ def _read_afterpulse_spectrum_for_fit(self, afterpulse_spectrum, fit_min_pe):
299
+ """
300
+ Read afterpulse spectrum data for fitting.
301
+
302
+ Parameters
303
+ ----------
304
+ afterpulse_spectrum : str
305
+ Afterpulse spectrum data file.
306
+ fit_min_pe : float
307
+ Minimum amplitude for fitting.
308
+
309
+ Returns
310
+ -------
311
+ tuple
312
+ Tuple with x, y, y_err data for fitting.
313
+ """
314
+ table = Table.read(afterpulse_spectrum, format="ascii.ecsv")
315
+ x = table["amplitude"]
316
+ y = table[self.afterpulse_column]
317
+ y_err = table["frequency stdev (afterpulsing)"]
318
+ mask = (x >= fit_min_pe) & (y > 0)
319
+ x_fit, y_fit, y_err_fit = x[mask], y[mask], y_err[mask]
320
+ return x_fit, y_fit, y_err_fit
simtools/constants.py CHANGED
@@ -6,6 +6,8 @@ from importlib.resources import files
6
6
  SCHEMA_PATH = files("simtools") / "schemas"
7
7
  # Path to metadata jsonschema
8
8
  METADATA_JSON_SCHEMA = SCHEMA_PATH / "metadata.metaschema.yml"
9
+ # Path to plotting configuration json schema
10
+ PLOT_CONFIG_SCHEMA = SCHEMA_PATH / "plot_configuration.metaschema.yml"
9
11
  # Path to model parameter metaschema
10
12
  MODEL_PARAMETER_METASCHEMA = SCHEMA_PATH / "model_parameter.metaschema.yml"
11
13
  # Path to model parameter description metaschema
@@ -14,3 +16,8 @@ MODEL_PARAMETER_DESCRIPTION_METASCHEMA = (
14
16
  )
15
17
  # Path to model parameter schema files
16
18
  MODEL_PARAMETER_SCHEMA_PATH = SCHEMA_PATH / "model_parameters"
19
+ # URL to model parameter schema files
20
+ MODEL_PARAMETER_SCHEMA_URL = (
21
+ "https://raw.githubusercontent.com/gammasim/simtools/main/src/simtools/schemas/"
22
+ "/model_parameters"
23
+ )
@@ -11,6 +11,8 @@ import logging
11
11
  import uuid
12
12
  from pathlib import Path
13
13
 
14
+ import yaml
15
+
14
16
  import simtools.constants
15
17
  import simtools.utils.general as gen
16
18
  import simtools.version
@@ -68,9 +70,7 @@ class MetadataCollector:
68
70
  self.top_level_meta = gen.change_dict_keys_case(
69
71
  data_dict=metadata_model.get_default_metadata_dict(), lower_case=True
70
72
  )
71
- self.input_metadata = self._read_input_metadata_from_file(
72
- metadata_file_name=metadata_file_name
73
- )
73
+ self.input_metadata = self._read_input_metadata_from_file(metadata_file_name)
74
74
  self.collect_meta_data()
75
75
  if clean_meta:
76
76
  self.top_level_meta = self.clean_meta_data(self.top_level_meta)
@@ -103,6 +103,74 @@ class MetadataCollector:
103
103
  pass
104
104
  return self.top_level_meta
105
105
 
106
+ @staticmethod
107
+ def dump(args_dict, output_file, add_activity_name=False):
108
+ """
109
+ Write metadata to file (static method).
110
+
111
+ Parameters
112
+ ----------
113
+ args_dict: dict
114
+ Command line parameters
115
+ output_file: str or Path
116
+ Name of output file.
117
+ add_activity_name: bool
118
+ Add activity name to file name.
119
+ """
120
+ collector = MetadataCollector(args_dict)
121
+ collector.write(output_file, add_activity_name=add_activity_name)
122
+
123
+ def write(self, yml_file=None, keys_lower_case=False, add_activity_name=False):
124
+ """
125
+ Write toplevel metadata to file (yaml file format).
126
+
127
+ Parameters
128
+ ----------
129
+ metadata: dict
130
+ Metadata to be stored
131
+ yml_file: str
132
+ Name of output file.
133
+ keys_lower_case: bool
134
+ Write yaml keys in lower case.
135
+ add_activity_name: bool
136
+ Add activity name to file name.
137
+
138
+ Returns
139
+ -------
140
+ str
141
+ Name of output file
142
+
143
+ Raises
144
+ ------
145
+ FileNotFoundError
146
+ If yml_file not found.
147
+ TypeError
148
+ If yml_file is not defined.
149
+ """
150
+ metadata = self.get_top_level_metadata()
151
+ activity_name = metadata.get("cta", {}).get("activity", {}).get("name", "").rstrip(".")
152
+ suffix = f".{activity_name}.meta.yml" if add_activity_name else ".meta.yml"
153
+
154
+ if yml_file is None:
155
+ raise TypeError("No output file for metadata defined")
156
+
157
+ try:
158
+ yml_file = names.file_name_with_version(yml_file, suffix)
159
+ with open(yml_file, "w", encoding="UTF-8") as file:
160
+ yaml.safe_dump(
161
+ gen.change_dict_keys_case(
162
+ gen.remove_substring_recursively_from_dict(metadata, substring="\n"),
163
+ keys_lower_case,
164
+ ),
165
+ file,
166
+ sort_keys=False,
167
+ explicit_start=True,
168
+ )
169
+ self._logger.info(f"Writing metadata to {yml_file}")
170
+ return yml_file
171
+ except FileNotFoundError as exc:
172
+ raise FileNotFoundError(f"Error writing metadata to {yml_file}") from exc
173
+
106
174
  def get_data_model_schema_file_name(self):
107
175
  """
108
176
  Return data model schema file name.
@@ -136,12 +204,12 @@ class MetadataCollector:
136
204
  self._logger.debug(f"Schema file from data model name: {self.data_model_name}")
137
205
  return str(schema.get_model_parameter_schema_file(self.data_model_name))
138
206
 
139
- # from input metadata
207
+ # from first entry in input metadata (least preferred)
140
208
  try:
141
- url = self.input_metadata[self.observatory]["product"]["data"]["model"]["url"]
209
+ url = self.input_metadata[0][self.observatory]["product"]["data"]["model"]["url"]
142
210
  self._logger.debug(f"Schema file from input metadata: {url}")
143
211
  return url
144
- except KeyError:
212
+ except (KeyError, TypeError):
145
213
  pass
146
214
 
147
215
  self._logger.warning("No schema file found.")
@@ -170,7 +238,7 @@ class MetadataCollector:
170
238
  Parameters
171
239
  ----------
172
240
  from_input_meta: bool
173
- Get site from input metadata (default: False)
241
+ Get site from first entry of input metadata (default: False)
174
242
 
175
243
  Returns
176
244
  -------
@@ -182,11 +250,11 @@ class MetadataCollector:
182
250
  _site = (
183
251
  self.top_level_meta[self.observatory]["instrument"]["site"]
184
252
  if not from_input_meta
185
- else self.input_metadata[self.observatory]["instrument"]["site"]
253
+ else self.input_metadata[0][self.observatory]["instrument"]["site"]
186
254
  )
187
255
  if _site is not None:
188
256
  return names.validate_site_name(_site)
189
- except KeyError:
257
+ except (KeyError, TypeError):
190
258
  pass
191
259
  return None
192
260
 
@@ -202,7 +270,13 @@ class MetadataCollector:
202
270
  contact_dict["name"] = contact_dict.get("name") or self.args_dict.get("user_name")
203
271
  if contact_dict["name"] is None:
204
272
  self._logger.warning("No user name provided, take user info from system level.")
205
- contact_dict["name"] = getpass.getuser()
273
+ try:
274
+ contact_dict["name"] = getpass.getuser()
275
+ except Exception as exc: # pylint: disable=broad-except
276
+ contact_dict["name"] = "UNKNOWN_USER"
277
+ self._logger.warning(
278
+ f"Failed to get user name: {exc}, setting it to {contact_dict['name']} "
279
+ )
206
280
  meta_dict = {
207
281
  "email": "user_mail",
208
282
  "orcid": "user_orcid",
@@ -221,17 +295,28 @@ class MetadataCollector:
221
295
  Dictionary for context metadata fields.
222
296
 
223
297
  """
224
- try: # wide try..except as for some cases we expect that there is no product metadata
225
- reduced_product_meta = {
226
- key: value
227
- for key, value in self.input_metadata[self.observatory]["product"].items()
228
- if key in {"description", "id", "creation_time", "valid", "format", "filename"}
229
- }
230
- self._fill_context_sim_list(context_dict["associated_data"], reduced_product_meta)
231
- except (KeyError, TypeError):
232
- self._logger.debug("No input product metadata appended to associated data.")
298
+ input_metadata = (
299
+ self.input_metadata if isinstance(self.input_metadata, list) else [self.input_metadata]
300
+ )
233
301
 
234
- def _read_input_metadata_from_file(self, metadata_file_name=None):
302
+ for metadata in input_metadata:
303
+ try: # wide try..except as for some cases we expect that there is no product metadata
304
+ reduced_product_meta = {
305
+ key: value
306
+ for key, value in metadata[self.observatory]["product"].items()
307
+ if key in {"description", "id", "creation_time", "valid", "format", "filename"}
308
+ }
309
+ if metadata[self.observatory].get("activity", {}).get("name"):
310
+ reduced_product_meta["activity_name"] = metadata[self.observatory][
311
+ "activity"
312
+ ].get("name")
313
+ context_dict["associated_data"] = self._fill_context_sim_list(
314
+ context_dict["associated_data"], reduced_product_meta
315
+ )
316
+ except (KeyError, TypeError):
317
+ self._logger.debug("No input product metadata appended to associated data.")
318
+
319
+ def _read_input_metadata_from_file(self, metadata_file_name_expression=None):
235
320
  """
236
321
  Read and validate input metadata from file.
237
322
 
@@ -240,8 +325,8 @@ class MetadataCollector:
240
325
 
241
326
  Parameter
242
327
  ---------
243
- metadata_file_name: str or Path
244
- Name of metadata file.
328
+ metadata_file_name_expression: str or Path
329
+ Name of metadata file (regular expressions allowed).
245
330
 
246
331
  Returns
247
332
  -------
@@ -256,31 +341,32 @@ class MetadataCollector:
256
341
  if metadata does not exist
257
342
 
258
343
  """
259
- metadata_file_name = (
260
- self.args_dict.get("input_meta", None) or self.args_dict.get("input", None)
261
- if metadata_file_name is None
262
- else metadata_file_name
344
+ metadata_file_names = (
345
+ metadata_file_name_expression
346
+ or self.args_dict.get("input_meta")
347
+ or self.args_dict.get("input")
263
348
  )
264
349
 
265
- if metadata_file_name is None:
350
+ try:
351
+ metadata_files = gen.resolve_file_patterns(metadata_file_names)
352
+ except ValueError:
266
353
  self._logger.debug("No input metadata file defined.")
267
- return {}
268
-
269
- self._logger.debug("Reading meta data from %s", metadata_file_name)
270
- if Path(metadata_file_name).suffix in (".yaml", ".yml", ".json"):
271
- _input_metadata = self._read_input_metadata_from_yml_or_json(metadata_file_name)
272
- elif Path(metadata_file_name).suffix == ".ecsv":
273
- _input_metadata = self._read_input_metadata_from_ecsv(metadata_file_name)
274
- else:
275
- self._logger.error("Unknown metadata file format: %s", metadata_file_name)
276
- raise gen.InvalidConfigDataError
354
+ return None
355
+
356
+ metadata = []
357
+ for metadata_file in metadata_files:
358
+ self._logger.debug(f"Reading meta data from {metadata_file}")
359
+ if Path(metadata_file).suffix in (".yaml", ".yml", ".json"):
360
+ _input_metadata = self._read_input_metadata_from_yml_or_json(metadata_file)
361
+ elif Path(metadata_file).suffix == ".ecsv":
362
+ _input_metadata = self._read_input_metadata_from_ecsv(metadata_file)
363
+ else:
364
+ raise gen.InvalidConfigDataError(f"Unknown metadata file format: {metadata_file}")
277
365
 
278
- schema.validate_dict_using_schema(_input_metadata, schema_file=METADATA_JSON_SCHEMA)
366
+ schema.validate_dict_using_schema(_input_metadata, schema_file=METADATA_JSON_SCHEMA)
367
+ metadata.append(gen.change_dict_keys_case(_input_metadata, lower_case=True))
279
368
 
280
- return gen.change_dict_keys_case(
281
- self._process_metadata_from_file(_input_metadata),
282
- lower_case=True,
283
- )
369
+ return metadata
284
370
 
285
371
  def _read_input_metadata_from_ecsv(self, metadata_file_name):
286
372
  """Read input metadata from ecsv file."""
@@ -348,13 +434,23 @@ class MetadataCollector:
348
434
  pass
349
435
 
350
436
  # DATA:MODEL
351
- helper_dict = {"name": "name", "version": "version", "type": "meta_schema"}
352
- for key, value in helper_dict.items():
353
- product_dict["data"]["model"][key] = self.schema_dict.get(value, None)
354
- product_dict["data"]["model"]["url"] = self.schema_file
437
+ product_dict["data"]["model"]["name"] = (
438
+ self.schema_dict.get("name")
439
+ or self.args_dict.get("metadata_product_data_name")
440
+ or "undefined_model_name"
441
+ )
442
+ product_dict["data"]["model"]["version"] = self.schema_dict.get("version", "0.0.0")
443
+ product_dict["data"]["model"]["type"] = self.schema_dict.get("meta_schema", None)
444
+ product_dict["data"]["model"]["url"] = self.schema_file or self.args_dict.get(
445
+ "metadata_product_data_url"
446
+ )
355
447
 
356
- product_dict["format"] = self.args_dict.get("output_file_format", None)
357
- product_dict["filename"] = str(self.args_dict.get("output_file", None))
448
+ product_dict["filename"] = str(self.args_dict.get("output_file", ""))
449
+ product_dict["format"] = (
450
+ self.args_dict.get("output_file_format")
451
+ or Path(product_dict["filename"]).suffix.lstrip(".")
452
+ or None
453
+ )
358
454
 
359
455
  def _fill_instrument_meta(self, instrument_dict):
360
456
  """
@@ -369,14 +465,17 @@ class MetadataCollector:
369
465
  Dictionary for instrument metadata fields.
370
466
 
371
467
  """
372
- instrument_dict["site"] = self.args_dict.get("site", None)
373
- instrument_dict["ID"] = self.args_dict.get("instrument") or self.args_dict.get(
374
- "telescope", None
375
- )
468
+ instrument_dict["site"] = self.args_dict.get("site")
469
+ instrument_dict["ID"] = self.args_dict.get("instrument") or self.args_dict.get("telescope")
376
470
  if instrument_dict["ID"]:
377
471
  instrument_dict["class"] = names.get_collection_name_from_array_element_name(
378
472
  instrument_dict["ID"], False
379
473
  )
474
+ instrument_dict["type"] = (
475
+ names.get_array_element_type_from_name(instrument_dict["ID"])
476
+ if not instrument_dict.get("type")
477
+ else instrument_dict["type"]
478
+ )
380
479
 
381
480
  def _fill_process_meta(self, process_dict):
382
481
  """
@@ -460,15 +559,14 @@ class MetadataCollector:
460
559
  Updated meta list.
461
560
 
462
561
  """
463
- if len(new_entry_dict) == 0:
562
+ if not new_entry_dict:
464
563
  return []
465
- try:
466
- if self._all_values_none(meta_list[0]):
467
- meta_list[0] = new_entry_dict
468
- else:
469
- meta_list.append(new_entry_dict)
470
- except (TypeError, IndexError):
471
- meta_list = [new_entry_dict]
564
+ if meta_list is None or not meta_list:
565
+ return [new_entry_dict]
566
+ if self._all_values_none(meta_list[0]):
567
+ meta_list[0] = new_entry_dict
568
+ else:
569
+ meta_list.append(new_entry_dict)
472
570
  return meta_list
473
571
 
474
572
  def _process_metadata_from_file(self, meta_dict):
@@ -533,7 +631,7 @@ class MetadataCollector:
533
631
  """
534
632
  try:
535
633
  for document in _input_metadata["context"][key]:
536
- self._fill_context_sim_list(context_dict[key], document)
634
+ context_dict[key] = self._fill_context_sim_list(context_dict[key], document)
537
635
  except KeyError:
538
636
  pass
539
637