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
@@ -6,7 +6,6 @@ from pathlib import Path
6
6
 
7
7
  import astropy.units as u
8
8
  import numpy as np
9
- import yaml
10
9
  from astropy.io.registry.base import IORegistryError
11
10
 
12
11
  import simtools.utils.general as gen
@@ -95,7 +94,7 @@ class ModelDataWriter:
95
94
  Dictionary with configuration parameters (including output file name and path).
96
95
  output_file: string or Path
97
96
  Name of output file (args["output_file"] is used if this parameter is not set).
98
- metadata: dict
97
+ metadata: MetadataCollector object
99
98
  Metadata to be written.
100
99
  product_data: astropy Table
101
100
  Model data to be written
@@ -174,11 +173,11 @@ class ModelDataWriter:
174
173
  if metadata_input_dict is not None:
175
174
  metadata_input_dict["output_file"] = output_file
176
175
  metadata_input_dict["output_file_format"] = Path(output_file).suffix.lstrip(".")
177
- metadata = MetadataCollector(args_dict=metadata_input_dict).get_top_level_metadata()
178
- writer.write_metadata_to_yml(
179
- metadata=metadata, yml_file=output_path / f"{Path(output_file).stem}"
176
+ metadata = MetadataCollector(args_dict=metadata_input_dict)
177
+ metadata.write(output_path / Path(output_file))
178
+ unique_id = (
179
+ metadata.get_top_level_metadata().get("cta", {}).get("product", {}).get("id")
180
180
  )
181
- unique_id = metadata.get("cta", {}).get("product", {}).get("id")
182
181
 
183
182
  _json_dict = writer.get_validated_parameter_dict(
184
183
  parameter_name, value, instrument, parameter_version, unique_id
@@ -270,6 +269,7 @@ class ModelDataWriter:
270
269
  "unit": unit,
271
270
  "type": self._get_parameter_type(),
272
271
  "file": self._parameter_is_a_file(),
272
+ "meta_parameter": False,
273
273
  }
274
274
  return self.validate_and_transform(
275
275
  product_data_dict=data_dict,
@@ -364,7 +364,7 @@ class ModelDataWriter:
364
364
  ----------
365
365
  product_data: astropy Table
366
366
  Model data to be written
367
- metadata: dict
367
+ metadata: MetadataCollector object
368
368
  Metadata to be written.
369
369
 
370
370
  Raises
@@ -377,7 +377,9 @@ class ModelDataWriter:
377
377
  return
378
378
 
379
379
  if metadata is not None:
380
- product_data.meta.update(gen.change_dict_keys_case(metadata, False))
380
+ product_data.meta.update(
381
+ gen.change_dict_keys_case(metadata.get_top_level_metadata(), False)
382
+ )
381
383
 
382
384
  self._logger.info(f"Writing data to {self.product_data_file}")
383
385
  if isinstance(product_data, dict) and Path(self.product_data_file).suffix == ".json":
@@ -390,6 +392,8 @@ class ModelDataWriter:
390
392
  except IORegistryError:
391
393
  self._logger.error(f"Error writing model data to {self.product_data_file}.")
392
394
  raise
395
+ if metadata is not None:
396
+ metadata.write(self.product_data_file, add_activity_name=True)
393
397
 
394
398
  def write_dict_to_model_parameter_json(self, file_name, data_dict):
395
399
  """
@@ -423,7 +427,7 @@ class ModelDataWriter:
423
427
  """
424
428
  Prepare data dictionary for writing to json file.
425
429
 
426
- Ensure sim_telarray style lists as strings.
430
+ Ensure sim_telarray style lists as strings 'type' and 'unit' entries.
427
431
  Replace "None" with "null" for unit field.
428
432
 
429
433
  Parameters
@@ -438,64 +442,17 @@ class ModelDataWriter:
438
442
 
439
443
  """
440
444
  try:
441
- data_dict["value"] = gen.convert_list_to_string(data_dict["value"])
442
- data_dict["unit"] = gen.convert_list_to_string(data_dict["unit"], comma_separated=True)
443
- data_dict["type"] = gen.convert_list_to_string(
444
- data_dict["type"], comma_separated=True, collapse_list=True
445
- )
446
445
  if isinstance(data_dict["unit"], str):
447
446
  data_dict["unit"] = data_dict["unit"].replace("None", "null")
447
+ elif isinstance(data_dict["unit"], list):
448
+ data_dict["unit"] = [
449
+ unit.replace("None", "null") if isinstance(unit, str) else unit
450
+ for unit in data_dict["unit"]
451
+ ]
448
452
  except KeyError:
449
453
  pass
450
454
  return data_dict
451
455
 
452
- def write_metadata_to_yml(self, metadata, yml_file=None, keys_lower_case=False):
453
- """
454
- Write model metadata file (yaml file format).
455
-
456
- Parameters
457
- ----------
458
- metadata: dict
459
- Metadata to be stored
460
- yml_file: str
461
- Name of output file.
462
- keys_lower_case: bool
463
- Write yaml keys in lower case.
464
-
465
- Returns
466
- -------
467
- str
468
- Name of output file
469
-
470
- Raises
471
- ------
472
- FileNotFoundError
473
- If yml_file not found.
474
- TypeError
475
- If yml_file is not defined.
476
- """
477
- try:
478
- yml_file = names.file_name_with_version(
479
- yml_file or self.product_data_file, ".metadata.yml"
480
- )
481
- with open(yml_file, "w", encoding="UTF-8") as file:
482
- yaml.safe_dump(
483
- gen.change_dict_keys_case(metadata, keys_lower_case),
484
- file,
485
- sort_keys=False,
486
- )
487
- self._logger.info(f"Writing metadata to {yml_file}")
488
- return yml_file
489
- except FileNotFoundError:
490
- self._logger.error(f"Error writing model data to {yml_file}")
491
- raise
492
- except AttributeError:
493
- self._logger.error("No metadata defined for writing")
494
- raise
495
- except TypeError:
496
- self._logger.error("No output file for metadata defined")
497
- raise
498
-
499
456
  @staticmethod
500
457
  def _astropy_data_format(product_data_format):
501
458
  """
@@ -108,7 +108,7 @@ def validate_dict_using_schema(data, schema_file=None, json_schema=None):
108
108
  """
109
109
  if json_schema is None and schema_file is None:
110
110
  _logger.warning(f"No schema provided for validation of {data}")
111
- return
111
+ return None
112
112
  if json_schema is None:
113
113
  json_schema = load_schema(
114
114
  schema_file,
@@ -131,6 +131,7 @@ def validate_dict_using_schema(data, schema_file=None, json_schema=None):
131
131
  raise FileNotFoundError(f"Meta schema URL does not exist: {data['meta_schema_url']}")
132
132
 
133
133
  _logger.debug(f"Successful validation of data using schema ({json_schema.get('name')})")
134
+ return data
134
135
 
135
136
 
136
137
  def load_schema(schema_file=None, schema_version=None):
@@ -220,7 +220,7 @@ class DataValidator:
220
220
  json_schema=self._get_data_description(index).get("json_schema"),
221
221
  )
222
222
  else:
223
- self._check_data_type(np.array(value).dtype, index)
223
+ self._check_data_type(np.array(value).dtype, index, value)
224
224
 
225
225
  if self.data_dict.get("type") not in ("string", "dict", "file"):
226
226
  self._check_for_not_a_number(value, index)
@@ -436,7 +436,7 @@ class DataValidator:
436
436
 
437
437
  return u.Unit(reference_unit)
438
438
 
439
- def _check_data_type(self, dtype, column_name):
439
+ def _check_data_type(self, dtype, column_name, value=None):
440
440
  """
441
441
  Check column data type.
442
442
 
@@ -446,6 +446,8 @@ class DataValidator:
446
446
  data type
447
447
  column_name: str
448
448
  column name
449
+ value: value
450
+ value to be tested (optional)
449
451
 
450
452
  Raises
451
453
  ------
@@ -456,7 +458,7 @@ class DataValidator:
456
458
  reference_dtype = self._get_data_description(column_name).get("type", None)
457
459
  if not gen.validate_data_type(
458
460
  reference_dtype=reference_dtype,
459
- value=None,
461
+ value=value,
460
462
  dtype=dtype,
461
463
  allow_subtypes=(not self.check_exact_data_type),
462
464
  ):
simtools/db/db_handler.py CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import logging
4
4
  import re
5
+ from collections import defaultdict
5
6
  from pathlib import Path
6
7
  from threading import Lock
7
8
 
@@ -13,7 +14,8 @@ from pymongo import MongoClient
13
14
 
14
15
  from simtools.data_model import validate_data
15
16
  from simtools.io_operations import io_handler
16
- from simtools.utils import names, value_conversion
17
+ from simtools.simtel import simtel_table_reader
18
+ from simtools.utils import general, names, value_conversion
17
19
 
18
20
  __all__ = ["DatabaseHandler"]
19
21
 
@@ -113,6 +115,7 @@ class DatabaseHandler:
113
115
  direct_connection = self.mongo_db_config["db_server"] in (
114
116
  "localhost",
115
117
  "simtools-mongodb",
118
+ "mongodb",
116
119
  )
117
120
  return MongoClient(
118
121
  self.mongo_db_config["db_server"],
@@ -177,48 +180,62 @@ class DatabaseHandler:
177
180
  def get_model_parameter(
178
181
  self,
179
182
  parameter,
180
- parameter_version,
181
183
  site,
182
184
  array_element_name,
185
+ parameter_version=None,
186
+ model_version=None,
183
187
  ):
184
188
  """
185
- Get a model parameter using the parameter version.
189
+ Get a single model parameter using model or parameter version.
190
+
191
+ Note that this function should not be called in a loop for many parameters,
192
+ as it each call queries the database.
186
193
 
187
194
  Parameters
188
195
  ----------
189
196
  parameter: str
190
197
  Name of the parameter.
191
- parameter_version: str
192
- Version of the parameter.
193
198
  site: str
194
199
  Site name.
195
200
  array_element_name: str
196
- Name of the array element model (e.g. MSTN, SSTS).
201
+ Name of the array element model.
202
+ parameter_version: str
203
+ Version of the parameter.
204
+ model_version: str
205
+ Version of the model.
197
206
 
198
207
  Returns
199
208
  -------
200
209
  dict containing the parameter
201
210
 
202
211
  """
212
+ collection_name = names.get_collection_name_from_parameter_name(parameter)
213
+ if model_version:
214
+ production_table = self._read_production_table_from_mongo_db(
215
+ collection_name, model_version
216
+ )
217
+ array_element_list = self._get_array_element_list(
218
+ array_element_name, site, production_table, collection_name
219
+ )
220
+ for array_element in reversed(array_element_list):
221
+ parameter_version = (
222
+ production_table["parameters"].get(array_element, {}).get(parameter)
223
+ )
224
+ if parameter_version:
225
+ array_element_name = array_element
226
+ break
227
+
203
228
  query = {
204
229
  "parameter_version": parameter_version,
205
230
  "parameter": parameter,
206
231
  }
207
- if array_element_name is not None:
232
+ if array_element_name:
208
233
  query["instrument"] = array_element_name
209
- if site is not None:
234
+ if site:
210
235
  query["site"] = site
211
- return self._read_mongo_db(
212
- query=query, collection_name=names.get_collection_name_from_parameter_name(parameter)
213
- )
236
+ return self._read_mongo_db(query=query, collection_name=collection_name)
214
237
 
215
- def get_model_parameters(
216
- self,
217
- site,
218
- array_element_name,
219
- collection,
220
- model_version=None,
221
- ):
238
+ def get_model_parameters(self, site, array_element_name, collection, model_version):
222
239
  """
223
240
  Get model parameters using the model version.
224
241
 
@@ -239,22 +256,48 @@ class DatabaseHandler:
239
256
  -------
240
257
  dict containing the parameters
241
258
  """
242
- model_versions = (
243
- self.get_model_versions(collection) if model_version is None else [model_version]
244
- )
245
-
246
259
  pars = {}
247
- for _model_version in model_versions:
248
- production_table = self._read_production_table_from_mongo_db(collection, _model_version)
249
- array_element_list = self._get_array_element_list(
250
- array_element_name, site, production_table, collection
260
+ production_table = self._read_production_table_from_mongo_db(collection, model_version)
261
+ array_element_list = self._get_array_element_list(
262
+ array_element_name, site, production_table, collection
263
+ )
264
+ for array_element in array_element_list:
265
+ pars.update(
266
+ self._get_parameter_for_model_version(
267
+ array_element, model_version, site, collection, production_table
268
+ )
251
269
  )
252
- for array_element in array_element_list:
253
- pars.update(
254
- self._get_parameter_for_model_version(
255
- array_element, _model_version, site, collection, production_table
256
- )
270
+ return pars
271
+
272
+ def get_model_parameters_for_all_model_versions(self, site, array_element_name, collection):
273
+ """
274
+ Get model parameters for all model versions.
275
+
276
+ Parameters
277
+ ----------
278
+ site: str
279
+ Site name.
280
+ array_element_name: str
281
+ Name of the array element model (e.g. LSTN-01, MSTx-FlashCam, ILLN-01).
282
+ collection: str
283
+ Collection of array element (e.g. telescopes, calibration_devices).
284
+
285
+ Returns
286
+ -------
287
+ dict containing the parameters with model version as first key
288
+ """
289
+ pars = defaultdict(dict)
290
+ for _model_version in self.get_model_versions(collection):
291
+ try:
292
+ parameter_data = self.get_model_parameters(
293
+ site, array_element_name, collection, _model_version
257
294
  )
295
+ pars[_model_version].update(parameter_data)
296
+ except KeyError:
297
+ self._logger.debug(
298
+ f"Skipping model version {_model_version} - {array_element_name} not found"
299
+ )
300
+ continue
258
301
  return pars
259
302
 
260
303
  def _get_parameter_for_model_version(
@@ -331,9 +374,54 @@ class DatabaseHandler:
331
374
  return [collection for collection in collections if not collection.startswith("fs.")]
332
375
  return collections
333
376
 
377
+ def export_model_file(
378
+ self,
379
+ parameter,
380
+ site,
381
+ array_element_name,
382
+ model_version=None,
383
+ parameter_version=None,
384
+ export_file_as_table=False,
385
+ ):
386
+ """
387
+ Export single model file from the DB identified by the parameter name.
388
+
389
+ The parameter can be identified by model or parameter version.
390
+ Files can be exported as astropy tables (ecsv format).
391
+
392
+ Parameters
393
+ ----------
394
+ parameter: str
395
+ Name of the parameter.
396
+ site: str
397
+ Site name.
398
+ array_element_name: str
399
+ Name of the array element model (e.g. MSTN, SSTS).
400
+ parameter_version: str
401
+ Version of the parameter.
402
+ model_version: str
403
+ Version of the model.
404
+ export_file_as_table: bool
405
+ If True, export the file as an astropy table (ecsv format).
406
+ """
407
+ parameters = self.get_model_parameter(
408
+ parameter,
409
+ site,
410
+ array_element_name,
411
+ parameter_version=parameter_version,
412
+ model_version=model_version,
413
+ )
414
+ self.export_model_files(parameters=parameters, dest=self.io_handler.get_output_directory())
415
+ if export_file_as_table:
416
+ return simtel_table_reader.read_simtel_table(
417
+ parameter,
418
+ self.io_handler.get_output_directory().joinpath(parameters[parameter]["value"]),
419
+ )
420
+ return None
421
+
334
422
  def export_model_files(self, parameters=None, file_names=None, dest=None, db_name=None):
335
423
  """
336
- Export files from the DB to the model directory.
424
+ Export models files from the DB to given directory.
337
425
 
338
426
  The files to be exported can be specified by file_name or retrieved from the database
339
427
  using the parameters dictionary.
@@ -711,10 +799,12 @@ class DatabaseHandler:
711
799
  f"corresponding to the {par_dict['parameter']} parameter, must be provided."
712
800
  )
713
801
  file_path = Path(file_prefix).joinpath(par_dict["value"])
802
+ if not general.is_utf8_file(file_path):
803
+ raise ValueError(f"File is not UTF-8 encoded: {file_path}")
714
804
  files_to_add_to_db.add(f"{file_path}")
715
805
 
716
806
  self._logger.info(
717
- f"Adding a new entry to DB {db_name} and collection {db_name}:\n{par_dict}"
807
+ f"Adding a new entry to DB {db_name} and collection {collection_name}:\n{par_dict}"
718
808
  )
719
809
  collection.insert_one(par_dict)
720
810
 
simtools/dependencies.py CHANGED
@@ -81,18 +81,53 @@ def get_sim_telarray_version():
81
81
 
82
82
  def get_corsika_version():
83
83
  """
84
- Get the version of the corsika package.
84
+ Get the version of the CORSIKA package.
85
85
 
86
86
  Returns
87
87
  -------
88
88
  str
89
- Version of the corsika package.
89
+ Version of the CORSIKA package.
90
90
  """
91
+ version = None
92
+ sim_telarray_path = os.getenv("SIMTOOLS_SIMTEL_PATH")
93
+ if sim_telarray_path is None:
94
+ _logger.warning("Environment variable SIMTOOLS_SIMTEL_PATH is not set.")
95
+ return None
96
+ corsika_command = Path(sim_telarray_path) / "corsika-run" / "corsika"
97
+
98
+ # Below I do not use the standard context manager because
99
+ # it makes mocking in the tests significantly more difficult
100
+ process = subprocess.Popen( # pylint: disable=consider-using-with
101
+ corsika_command,
102
+ stdout=subprocess.PIPE,
103
+ stderr=subprocess.PIPE,
104
+ stdin=subprocess.PIPE,
105
+ text=True,
106
+ )
107
+
108
+ # Capture output until it waits for input
109
+ while True:
110
+ line = process.stdout.readline()
111
+ if not line:
112
+ break
113
+ # Extract the version from the line "NUMBER OF VERSION : 7.7550"
114
+ if "NUMBER OF VERSION" in line:
115
+ version = line.split(":")[1].strip()
116
+ break
117
+ # Check for a specific prompt or indication that the program is waiting for input
118
+ if "DATA CARDS FOR RUN STEERING ARE EXPECTED FROM STANDARD INPUT" in line:
119
+ break
120
+
121
+ process.terminate()
122
+ # Check it's a valid version string
123
+ if version and re.match(r"\d+\.\d+", version):
124
+ return version
91
125
  try:
92
126
  build_opts = get_build_options()
93
127
  except (FileNotFoundError, TypeError):
94
- _logger.warning("CORSIKA version not implemented yet.")
128
+ _logger.warning("Could not get CORSIKA version.")
95
129
  return None
130
+ _logger.debug("Getting the CORSIKA version from the build options.")
96
131
  return build_opts.get("corsika_version")
97
132
 
98
133
 
@@ -641,6 +641,7 @@ class ArrayLayout:
641
641
  "unit": "m",
642
642
  "type": "float64",
643
643
  "file": False,
644
+ "meta_parameter": False,
644
645
  }
645
646
 
646
647
  def get_number_of_telescopes(self):
@@ -0,0 +1,172 @@
1
+ """Retrieve, merge, and write layouts from CTAO common identifiers repository."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import simtools.utils.general as gen
7
+ from simtools.data_model.metadata_collector import MetadataCollector
8
+ from simtools.data_model.model_data_writer import ModelDataWriter
9
+ from simtools.io_operations import io_handler
10
+ from simtools.utils import names
11
+
12
+ _logger = logging.getLogger(__name__)
13
+
14
+
15
+ def retrieve_array_layouts(site, repository_url, branch_name="main"):
16
+ """
17
+ Retrieve array layouts from CTAO common identifiers repository.
18
+
19
+ Parameters
20
+ ----------
21
+ site : str
22
+ Site identifier.
23
+ repository_url : str
24
+ URL or path to CTAO common identifiers
25
+ branch_name : str
26
+ Repository branch to use for CTAO common identifiers.
27
+
28
+ Returns
29
+ -------
30
+ dict
31
+ Array layouts for all CTAO sites.
32
+ """
33
+ _logger.info(f"Retrieving array layouts from {repository_url} on branch {branch_name}.")
34
+
35
+ if gen.is_url(repository_url):
36
+ array_element_ids = gen.collect_data_from_http(
37
+ url=f"{repository_url}/{branch_name}/array-element-ids.json"
38
+ )
39
+ sub_arrays = gen.collect_data_from_http(
40
+ url=f"{repository_url}/{branch_name}/subarray-ids.json"
41
+ )
42
+ else:
43
+ array_element_ids = gen.collect_data_from_file(
44
+ Path(repository_url) / "array-element-ids.json"
45
+ )
46
+ sub_arrays = gen.collect_data_from_file(Path(repository_url) / "subarray-ids.json")
47
+
48
+ return _get_layouts_per_site(site, sub_arrays, array_element_ids)
49
+
50
+
51
+ def _get_layouts_per_site(site, sub_arrays, array_element_ids):
52
+ """
53
+ Get array layouts for CTAO sites.
54
+
55
+ Parameters
56
+ ----------
57
+ site : str
58
+ Site identifier.
59
+ sub_arrays : dict
60
+ Sub-array definitions.
61
+ array_element_ids : dict
62
+ Array element definitions.
63
+
64
+ Returns
65
+ -------
66
+ dict
67
+ Array layouts for CTAO sites.
68
+ """
69
+ layouts_per_site = []
70
+
71
+ for array in sub_arrays.get("subarrays", []):
72
+ elements = []
73
+ for ids in array.get("array_element_ids", []):
74
+ element_name = _get_array_element_name(ids, array_element_ids)
75
+ if names.get_site_from_array_element_name(element_name) != site:
76
+ break
77
+ elements.append(element_name)
78
+ if len(elements) > 0:
79
+ array_layout = {
80
+ "name": array.get("name"),
81
+ "elements": elements,
82
+ }
83
+ layouts_per_site.append(array_layout)
84
+
85
+ _logger.info(f"CTAO array layout definition: {layouts_per_site}")
86
+ return layouts_per_site
87
+
88
+
89
+ def _get_array_element_name(ids, array_element_ids):
90
+ """Return array element name for common identifier."""
91
+ for element in array_element_ids.get("array_elements", []):
92
+ if element.get("id") == ids:
93
+ return element.get("name")
94
+ return None
95
+
96
+
97
+ def merge_array_layouts(layouts_1, layouts_2):
98
+ """
99
+ Compare array layout dictionaries and merge them.
100
+
101
+ Parameters
102
+ ----------
103
+ layouts_1 : dict
104
+ Array layout dictionary 1.
105
+ layouts_2 : dict
106
+ Array layout dictionary 2.
107
+
108
+ Returns
109
+ -------
110
+ dict
111
+ Merged array layout dictionary based on layout_1.
112
+ """
113
+ merged_layout = layouts_1
114
+ for layout_2 in layouts_2:
115
+ layout_found = False
116
+ for layout_1 in layouts_1.get("value", {}):
117
+ if sorted(layout_1["elements"]) == sorted(layout_2["elements"]):
118
+ print(
119
+ f"Equal telescope list: simtools '{layout_1['name']}' "
120
+ f"and CTAO '{layout_2['name']}'"
121
+ )
122
+ layout_1["name"] = layout_2["name"]
123
+ layout_found = True
124
+ if not layout_found:
125
+ merged_layout["value"].append(
126
+ {
127
+ "name": layout_2["name"],
128
+ "elements": layout_2["elements"],
129
+ }
130
+ )
131
+ _logger.info(f"Adding {layout_2['name']} with {layout_2['elements']}")
132
+ return merged_layout
133
+
134
+
135
+ def write_array_layouts(array_layouts, args_dict, db_config):
136
+ """
137
+ Write array layouts as model parameter.
138
+
139
+ Parameters
140
+ ----------
141
+ args_dict : dict
142
+ Command line arguments.
143
+ array_layouts : dict
144
+ Array layouts to be written.
145
+ db_config : dict
146
+ Database configuration.
147
+ """
148
+ _logger.info(f"Writing updated array layouts to the database for site {args_dict['site']}.")
149
+
150
+ io_handler_instance = io_handler.IOHandler()
151
+ io_handler_instance.set_paths(
152
+ output_path=args_dict["output_path"],
153
+ use_plain_output_path=args_dict["use_plain_output_path"],
154
+ )
155
+ output_file = io_handler_instance.get_output_file(
156
+ f"array-layouts-{args_dict['updated_parameter_version']}.json"
157
+ )
158
+
159
+ ModelDataWriter.dump_model_parameter(
160
+ parameter_name="array_layouts",
161
+ value=array_layouts["value"],
162
+ instrument=args_dict["site"],
163
+ parameter_version=args_dict.get("updated_parameter_version"),
164
+ output_file=output_file,
165
+ use_plain_output_path=args_dict["use_plain_output_path"],
166
+ db_config=db_config,
167
+ )
168
+ MetadataCollector.dump(
169
+ args_dict,
170
+ output_file,
171
+ add_activity_name=True,
172
+ )