gammasimtools 0.15.0__py3-none-any.whl → 0.17.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 (248) hide show
  1. {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/METADATA +5 -33
  2. {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/RECORD +243 -229
  3. {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/entry_points.txt +8 -3
  5. simtools/_version.py +2 -2
  6. simtools/applications/calculate_trigger_rate.py +10 -10
  7. simtools/applications/convert_all_model_parameters_from_simtel.py +16 -16
  8. simtools/applications/convert_model_parameter_from_simtel.py +1 -1
  9. simtools/applications/derive_ctao_array_layouts.py +5 -5
  10. simtools/applications/derive_psf_parameters.py +12 -9
  11. simtools/applications/docs_produce_array_element_report.py +3 -3
  12. simtools/applications/docs_produce_calibration_reports.py +49 -0
  13. simtools/applications/docs_produce_simulation_configuration_report.py +50 -0
  14. simtools/applications/{generate_simtel_array_histograms.py → generate_sim_telarray_histograms.py} +2 -2
  15. simtools/applications/generate_simtel_event_data.py +36 -46
  16. simtools/applications/merge_tables.py +104 -0
  17. simtools/applications/plot_array_layout.py +145 -258
  18. simtools/applications/production_derive_corsika_limits.py +35 -167
  19. simtools/applications/production_derive_statistics.py +159 -0
  20. simtools/applications/production_generate_grid.py +197 -0
  21. simtools/applications/simulate_light_emission.py +6 -13
  22. simtools/applications/simulate_prod.py +45 -21
  23. simtools/applications/simulate_prod_htcondor_generator.py +0 -1
  24. simtools/applications/submit_array_layouts.py +93 -0
  25. simtools/applications/validate_cumulative_psf.py +6 -4
  26. simtools/applications/validate_file_using_schema.py +7 -3
  27. simtools/applications/validate_optics.py +5 -4
  28. simtools/applications/verify_simulation_model_production_tables.py +52 -0
  29. simtools/camera/camera_efficiency.py +17 -42
  30. simtools/configuration/commandline_parser.py +32 -37
  31. simtools/configuration/configurator.py +10 -4
  32. simtools/corsika/corsika_config.py +120 -17
  33. simtools/corsika/primary_particle.py +46 -13
  34. simtools/data_model/format_checkers.py +9 -0
  35. simtools/data_model/metadata_collector.py +7 -3
  36. simtools/data_model/model_data_writer.py +3 -0
  37. simtools/data_model/schema.py +27 -16
  38. simtools/data_model/validate_data.py +27 -7
  39. simtools/db/db_handler.py +21 -15
  40. simtools/db/db_model_upload.py +2 -2
  41. simtools/io_operations/io_handler.py +2 -2
  42. simtools/io_operations/io_table_handler.py +345 -0
  43. simtools/job_execution/htcondor_script_generator.py +2 -2
  44. simtools/job_execution/job_manager.py +7 -121
  45. simtools/layout/array_layout.py +1 -0
  46. simtools/layout/array_layout_utils.py +385 -0
  47. simtools/model/array_model.py +68 -29
  48. simtools/model/model_parameter.py +76 -51
  49. simtools/model/model_repository.py +134 -0
  50. simtools/model/model_utils.py +43 -1
  51. simtools/model/site_model.py +3 -2
  52. simtools/model/telescope_model.py +4 -4
  53. simtools/production_configuration/{calculate_statistical_errors_grid_point.py → calculate_statistical_uncertainties_grid_point.py} +101 -116
  54. simtools/production_configuration/derive_corsika_limits.py +239 -111
  55. simtools/production_configuration/derive_corsika_limits_grid.py +189 -0
  56. simtools/production_configuration/derive_production_statistics.py +155 -0
  57. simtools/production_configuration/derive_production_statistics_handler.py +152 -0
  58. simtools/production_configuration/generate_production_grid.py +364 -0
  59. simtools/production_configuration/interpolation_handler.py +303 -96
  60. simtools/ray_tracing/mirror_panel_psf.py +16 -20
  61. simtools/ray_tracing/psf_analysis.py +2 -2
  62. simtools/ray_tracing/ray_tracing.py +12 -7
  63. simtools/reporting/docs_read_parameters.py +426 -81
  64. simtools/runners/corsika_runner.py +11 -1
  65. simtools/runners/corsika_simtel_runner.py +84 -90
  66. simtools/runners/runner_services.py +22 -8
  67. simtools/runners/simtel_runner.py +27 -10
  68. simtools/schemas/model_parameter.metaschema.yml +4 -0
  69. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +1 -0
  70. simtools/schemas/model_parameters/adjust_gain.schema.yml +2 -2
  71. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +2 -2
  72. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +2 -2
  73. simtools/schemas/model_parameters/array_window.schema.yml +2 -2
  74. simtools/schemas/model_parameters/asum_offset.schema.yml +2 -2
  75. simtools/schemas/model_parameters/asum_shaping.schema.yml +2 -2
  76. simtools/schemas/model_parameters/asum_threshold.schema.yml +2 -2
  77. simtools/schemas/model_parameters/axes_offsets.schema.yml +2 -2
  78. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +2 -2
  79. simtools/schemas/model_parameters/camera_body_shape.schema.yml +2 -2
  80. simtools/schemas/model_parameters/camera_config_file.schema.yml +2 -2
  81. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +2 -2
  82. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +2 -2
  83. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +2 -2
  84. simtools/schemas/model_parameters/camera_depth.schema.yml +2 -2
  85. simtools/schemas/model_parameters/camera_filter.schema.yml +2 -2
  86. simtools/schemas/model_parameters/camera_pixels.schema.yml +2 -2
  87. simtools/schemas/model_parameters/camera_transmission.schema.yml +2 -2
  88. simtools/schemas/model_parameters/channels_per_chip.schema.yml +2 -2
  89. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +2 -2
  90. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +90 -1
  91. simtools/schemas/model_parameters/default_trigger.schema.yml +2 -2
  92. simtools/schemas/model_parameters/design_model.schema.yml +2 -2
  93. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +2 -2
  94. simtools/schemas/model_parameters/disc_bins.schema.yml +2 -2
  95. simtools/schemas/model_parameters/disc_start.schema.yml +2 -2
  96. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +2 -2
  97. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +2 -2
  98. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +2 -2
  99. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +2 -2
  100. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +2 -2
  101. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +2 -2
  102. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +2 -2
  103. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +2 -2
  104. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +2 -2
  105. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +2 -2
  106. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +2 -2
  107. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +2 -2
  108. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +2 -2
  109. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +2 -2
  110. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +2 -2
  111. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +2 -2
  112. simtools/schemas/model_parameters/dish_shape_length.schema.yml +2 -2
  113. simtools/schemas/model_parameters/dsum_clipping.schema.yml +2 -2
  114. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +2 -2
  115. simtools/schemas/model_parameters/dsum_offset.schema.yml +2 -2
  116. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +2 -2
  117. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +2 -2
  118. simtools/schemas/model_parameters/dsum_prescale.schema.yml +2 -2
  119. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +2 -2
  120. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +2 -2
  121. simtools/schemas/model_parameters/dsum_shaping.schema.yml +2 -2
  122. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +2 -2
  123. simtools/schemas/model_parameters/dsum_threshold.schema.yml +44 -3
  124. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +2 -2
  125. simtools/schemas/model_parameters/effective_focal_length.schema.yml +2 -2
  126. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +2 -2
  127. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +2 -2
  128. simtools/schemas/model_parameters/fadc_bins.schema.yml +2 -2
  129. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +2 -2
  130. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +2 -2
  131. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +2 -2
  132. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +2 -2
  133. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +2 -2
  134. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +2 -2
  135. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +2 -2
  136. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +2 -2
  137. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +2 -2
  138. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +2 -2
  139. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +2 -2
  140. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +2 -2
  141. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +2 -2
  142. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +2 -2
  143. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +2 -2
  144. simtools/schemas/model_parameters/fadc_mhz.schema.yml +2 -2
  145. simtools/schemas/model_parameters/fadc_noise.schema.yml +2 -2
  146. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +2 -2
  147. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +2 -2
  148. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +2 -2
  149. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +2 -2
  150. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +2 -2
  151. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +2 -2
  152. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +2 -2
  153. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +2 -2
  154. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  155. simtools/schemas/model_parameters/flatfielding.schema.yml +2 -2
  156. simtools/schemas/model_parameters/focal_length.schema.yml +2 -2
  157. simtools/schemas/model_parameters/focus_offset.schema.yml +2 -2
  158. simtools/schemas/model_parameters/gain_variation.schema.yml +2 -2
  159. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +2 -2
  160. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +2 -2
  161. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +2 -2
  162. simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
  163. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +2 -2
  164. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +2 -2
  165. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +2 -2
  166. simtools/schemas/model_parameters/min_photons.schema.yml +2 -2
  167. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +2 -2
  168. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +2 -2
  169. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +2 -2
  170. simtools/schemas/model_parameters/mirror_class.schema.yml +2 -2
  171. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +2 -2
  172. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +2 -2
  173. simtools/schemas/model_parameters/mirror_list.schema.yml +2 -2
  174. simtools/schemas/model_parameters/mirror_offset.schema.yml +2 -2
  175. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +2 -2
  176. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +2 -2
  177. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +2 -2
  178. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +2 -2
  179. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +2 -2
  180. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +2 -2
  181. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +2 -2
  182. simtools/schemas/model_parameters/num_gains.schema.yml +2 -2
  183. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +2 -2
  184. simtools/schemas/model_parameters/optics_properties.schema.yml +2 -2
  185. simtools/schemas/model_parameters/pedestal_events.schema.yml +7 -3
  186. simtools/schemas/model_parameters/photon_delay.schema.yml +2 -2
  187. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +2 -2
  188. simtools/schemas/model_parameters/pm_average_gain.schema.yml +2 -2
  189. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +2 -2
  190. simtools/schemas/model_parameters/pm_gain_index.schema.yml +2 -2
  191. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +2 -2
  192. simtools/schemas/model_parameters/pm_transit_time.schema.yml +2 -2
  193. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +2 -2
  194. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +2 -2
  195. simtools/schemas/model_parameters/qe_variation.schema.yml +2 -2
  196. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +2 -2
  197. simtools/schemas/model_parameters/random_focal_length.schema.yml +2 -2
  198. simtools/schemas/model_parameters/random_generator.schema.yml +2 -2
  199. simtools/schemas/model_parameters/random_mono_probability.schema.yml +2 -2
  200. simtools/schemas/model_parameters/sampled_output.schema.yml +2 -2
  201. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +2 -2
  202. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +2 -2
  203. simtools/schemas/model_parameters/tailcut_scale.schema.yml +2 -2
  204. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +2 -2
  205. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +2 -2
  206. simtools/schemas/model_parameters/telescope_random_error.schema.yml +2 -2
  207. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +2 -2
  208. simtools/schemas/model_parameters/telescope_transmission.schema.yml +2 -2
  209. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +2 -2
  210. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +2 -2
  211. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +2 -2
  212. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +2 -2
  213. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +2 -2
  214. simtools/schemas/model_parameters/transit_time_error.schema.yml +2 -2
  215. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +2 -2
  216. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +2 -2
  217. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +2 -2
  218. simtools/schemas/model_parameters/trigger_pixels.schema.yml +2 -2
  219. simtools/schemas/production_configuration_metrics.schema.yml +2 -2
  220. simtools/simtel/simtel_config_reader.py +21 -17
  221. simtools/simtel/simtel_config_writer.py +258 -66
  222. simtools/simtel/simtel_io_event_reader.py +301 -194
  223. simtools/simtel/simtel_io_event_writer.py +207 -227
  224. simtools/simtel/simtel_io_file_info.py +62 -0
  225. simtools/simtel/simtel_io_histogram.py +10 -14
  226. simtools/simtel/simtel_io_histograms.py +2 -2
  227. simtools/simtel/simtel_io_metadata.py +106 -0
  228. simtools/simtel/simulator_array.py +28 -14
  229. simtools/simtel/simulator_camera_efficiency.py +12 -6
  230. simtools/simtel/simulator_light_emission.py +85 -45
  231. simtools/simtel/simulator_ray_tracing.py +16 -6
  232. simtools/simulator.py +286 -89
  233. simtools/testing/configuration.py +5 -0
  234. simtools/testing/helpers.py +18 -0
  235. simtools/testing/sim_telarray_metadata.py +212 -0
  236. simtools/testing/validate_output.py +16 -6
  237. simtools/utils/general.py +18 -27
  238. simtools/utils/names.py +32 -10
  239. simtools/visualization/plot_array_layout.py +242 -0
  240. simtools/visualization/plot_pixels.py +681 -0
  241. simtools/visualization/visualize.py +5 -221
  242. simtools/applications/production_generate_simulation_config.py +0 -162
  243. simtools/applications/production_scale_events.py +0 -185
  244. simtools/layout/ctao_array_layouts.py +0 -172
  245. simtools/production_configuration/event_scaler.py +0 -120
  246. simtools/production_configuration/generate_simulation_config.py +0 -158
  247. {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/licenses/LICENSE +0 -0
  248. {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,385 @@
1
+ """Retrieve, merge, and write layout dictionaries."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import simtools.utils.general as gen
7
+ from simtools.data_model import data_reader
8
+ from simtools.data_model.metadata_collector import MetadataCollector
9
+ from simtools.data_model.model_data_writer import ModelDataWriter
10
+ from simtools.io_operations import io_handler
11
+ from simtools.model.array_model import ArrayModel
12
+ from simtools.model.site_model import SiteModel
13
+ from simtools.utils import names
14
+
15
+ _logger = logging.getLogger(__name__)
16
+
17
+
18
+ def retrieve_ctao_array_layouts(site, repository_url, branch_name="main"):
19
+ """
20
+ Retrieve array layouts from CTAO common identifiers repository.
21
+
22
+ Parameters
23
+ ----------
24
+ site : str
25
+ Site identifier.
26
+ repository_url : str
27
+ URL or path to CTAO common identifiers
28
+ branch_name : str
29
+ Repository branch to use for CTAO common identifiers.
30
+
31
+ Returns
32
+ -------
33
+ dict
34
+ Array layouts for all CTAO sites.
35
+ """
36
+ _logger.info(f"Retrieving array layouts from {repository_url} on branch {branch_name}.")
37
+
38
+ if gen.is_url(repository_url):
39
+ array_element_ids = gen.collect_data_from_http(
40
+ url=f"{repository_url}/{branch_name}/array-element-ids.json"
41
+ )
42
+ sub_arrays = gen.collect_data_from_http(
43
+ url=f"{repository_url}/{branch_name}/subarray-ids.json"
44
+ )
45
+ else:
46
+ array_element_ids = gen.collect_data_from_file(
47
+ Path(repository_url) / "array-element-ids.json"
48
+ )
49
+ sub_arrays = gen.collect_data_from_file(Path(repository_url) / "subarray-ids.json")
50
+
51
+ return _get_ctao_layouts_per_site(site, sub_arrays, array_element_ids)
52
+
53
+
54
+ def _get_ctao_layouts_per_site(site, sub_arrays, array_element_ids):
55
+ """
56
+ Get array layouts for CTAO sites.
57
+
58
+ Parameters
59
+ ----------
60
+ site : str
61
+ Site identifier.
62
+ sub_arrays : dict
63
+ Sub-array definitions.
64
+ array_element_ids : dict
65
+ Array element definitions.
66
+
67
+ Returns
68
+ -------
69
+ dict
70
+ Array layouts for CTAO sites.
71
+ """
72
+ layouts_per_site = []
73
+
74
+ for array in sub_arrays.get("subarrays", []):
75
+ elements = []
76
+ for ids in array.get("array_element_ids", []):
77
+ element_name = _get_ctao_array_element_name(ids, array_element_ids)
78
+ if names.get_site_from_array_element_name(element_name) != site:
79
+ break
80
+ elements.append(element_name)
81
+ if len(elements) > 0:
82
+ array_layout = {
83
+ "name": array.get("name"),
84
+ "elements": elements,
85
+ }
86
+ layouts_per_site.append(array_layout)
87
+
88
+ _logger.info(f"CTAO array layout definition: {layouts_per_site}")
89
+ return layouts_per_site
90
+
91
+
92
+ def _get_ctao_array_element_name(ids, array_element_ids):
93
+ """Return array element name for common identifier."""
94
+ for element in array_element_ids.get("array_elements", []):
95
+ if element.get("id") == ids:
96
+ return element.get("name")
97
+ return None
98
+
99
+
100
+ def merge_array_layouts(layouts_1, layouts_2):
101
+ """
102
+ Compare two array layout dictionaries and merge them.
103
+
104
+ Parameters
105
+ ----------
106
+ layouts_1 : dict
107
+ Array layout dictionary 1.
108
+ layouts_2 : dict
109
+ Array layout dictionary 2.
110
+
111
+ Returns
112
+ -------
113
+ dict
114
+ Merged array layout dictionary based on layout_1.
115
+ """
116
+ merged_layout = layouts_1
117
+ for layout_2 in layouts_2:
118
+ layout_found = False
119
+ for layout_1 in layouts_1.get("value", {}):
120
+ if sorted(layout_1["elements"]) == sorted(layout_2["elements"]):
121
+ print(
122
+ f"Equal telescope list: simtools '{layout_1['name']}' "
123
+ f"and CTAO '{layout_2['name']}'"
124
+ )
125
+ layout_1["name"] = layout_2["name"]
126
+ layout_found = True
127
+ if not layout_found:
128
+ merged_layout["value"].append(
129
+ {
130
+ "name": layout_2["name"],
131
+ "elements": layout_2["elements"],
132
+ }
133
+ )
134
+ _logger.info(f"Adding {layout_2['name']} with {layout_2['elements']}")
135
+ return merged_layout
136
+
137
+
138
+ def write_array_layouts(array_layouts, args_dict, db_config):
139
+ """
140
+ Write array layouts as model parameter.
141
+
142
+ Parameters
143
+ ----------
144
+ args_dict : dict
145
+ Command line arguments.
146
+ array_layouts : dict
147
+ Array layouts to be written.
148
+ db_config : dict
149
+ Database configuration.
150
+ """
151
+ site = args_dict.get("site") or array_layouts.get("site")
152
+ _logger.info(f"Writing updated array layouts to the database for site {site}.")
153
+
154
+ io_handler_instance = io_handler.IOHandler()
155
+ io_handler_instance.set_paths(
156
+ output_path=args_dict["output_path"],
157
+ use_plain_output_path=args_dict["use_plain_output_path"],
158
+ )
159
+ output_file = io_handler_instance.get_output_file(
160
+ f"array-layouts-{args_dict['updated_parameter_version']}.json"
161
+ )
162
+
163
+ ModelDataWriter.dump_model_parameter(
164
+ parameter_name="array_layouts",
165
+ value=array_layouts["value"],
166
+ instrument=site,
167
+ parameter_version=args_dict.get("updated_parameter_version"),
168
+ output_file=output_file,
169
+ use_plain_output_path=args_dict["use_plain_output_path"],
170
+ db_config=db_config,
171
+ )
172
+ MetadataCollector.dump(
173
+ args_dict,
174
+ output_file,
175
+ add_activity_name=True,
176
+ )
177
+
178
+
179
+ def validate_array_layouts_with_db(production_table, array_layouts):
180
+ """
181
+ Validate array layouts against the production table in the database.
182
+
183
+ Confirm that every telescope defined in the array layouts exist in the
184
+ production table.
185
+
186
+ Parameters
187
+ ----------
188
+ production_table : dict
189
+ Production table from the database.
190
+ array_layouts : dict
191
+ Array layouts to be validated.
192
+
193
+ Returns
194
+ -------
195
+ dict
196
+ Validated array layouts.
197
+ """
198
+ db_elements = set(production_table.get("parameters", {}).keys())
199
+
200
+ invalid_array_elements = [
201
+ e
202
+ for layout in array_layouts.get("value", [])
203
+ for e in layout.get("elements", [])
204
+ if e not in db_elements
205
+ ]
206
+
207
+ if invalid_array_elements:
208
+ raise ValueError(f"Invalid array elements found: {invalid_array_elements}. ")
209
+
210
+ return array_layouts
211
+
212
+
213
+ def get_array_layouts_from_parameter_file(
214
+ file_path, model_version, db_config, coordinate_system="ground"
215
+ ):
216
+ """
217
+ Retrieve array layouts from parameter file.
218
+
219
+ Parameters
220
+ ----------
221
+ file_path : str or Path
222
+ Path to the array layout parameter file.
223
+ model_version : str
224
+ Model version to retrieve.
225
+ db_config : dict
226
+ Database configuration.
227
+ coordinate_system : str
228
+ Coordinate system to use for the array elements (default is "ground").
229
+
230
+ Returns
231
+ -------
232
+ list
233
+ List of dictionaries containing array layout names and their elements.
234
+ """
235
+ array_layouts = gen.collect_data_from_file(file_path)
236
+ try:
237
+ value = array_layouts["value"]
238
+ except KeyError as exc:
239
+ raise ValueError("Missing 'value' key in layout file.") from exc
240
+ site = array_layouts.get("site")
241
+
242
+ layouts = []
243
+ for layout in value:
244
+ layouts.append(
245
+ _get_array_layout_dict(
246
+ db_config, model_version, site, None, layout["name"], coordinate_system
247
+ )
248
+ )
249
+ return layouts
250
+
251
+
252
+ def get_array_layouts_from_db(
253
+ layout_name, site, model_version, db_config, coordinate_system="ground"
254
+ ):
255
+ """
256
+ Retrieve all array layouts from the database and return as list of astropy tables.
257
+
258
+ Parameters
259
+ ----------
260
+ layout_name : str
261
+ Name of the array layout to retrieve (for None, all layouts are retrieved).
262
+ site : str
263
+ Site identifier.
264
+ model_version : str
265
+ Model version to retrieve.
266
+ db_config : dict
267
+ Database configuration.
268
+ coordinate_system : str
269
+ Coordinate system to use for the array elements (default is "ground").
270
+
271
+ Returns
272
+ -------
273
+ list
274
+ List of dictionaries containing array layout names and their elements.
275
+ """
276
+ layout_names = []
277
+ if layout_name:
278
+ layout_names.append(layout_name)
279
+ else:
280
+ site_model = SiteModel(site=site, model_version=model_version, mongo_db_config=db_config)
281
+ layout_names = site_model.get_list_of_array_layouts()
282
+
283
+ layouts = []
284
+ for _layout_name in layout_names:
285
+ layouts.append(
286
+ _get_array_layout_dict(
287
+ db_config, model_version, site, None, _layout_name, coordinate_system
288
+ )
289
+ )
290
+ if len(layouts) == 1:
291
+ return layouts[0]
292
+ return layouts
293
+
294
+
295
+ def get_array_layouts_using_telescope_lists_from_db(
296
+ telescope_lists, site, model_version, db_config, coordinate_system="ground"
297
+ ):
298
+ """
299
+ Retrieve array layouts from the database using telescope lists.
300
+
301
+ Parameters
302
+ ----------
303
+ telescope_lists : list
304
+ List of telescope lists to retrieve array layouts for.
305
+ site : str
306
+ Site identifier.
307
+ model_version : str
308
+ Model version to retrieve.
309
+ db_config : dict
310
+ Database configuration.
311
+ coordinate_system : str
312
+ Coordinate system to use for the array elements (default is "ground").
313
+
314
+ Returns
315
+ -------
316
+ list
317
+ List of dictionaries containing array layout names and their elements.
318
+
319
+ """
320
+ layouts = []
321
+ for telescope_list in telescope_lists:
322
+ _site = site
323
+ if _site is None:
324
+ sites = {names.get_site_from_array_element_name(t) for t in telescope_list}
325
+ if len(sites) != 1:
326
+ raise ValueError(
327
+ f"Telescope list contains elements from multiple sites: {sites}."
328
+ "Please specify a site."
329
+ )
330
+ _site = sites.pop()
331
+
332
+ layouts.append(
333
+ _get_array_layout_dict(
334
+ db_config, model_version, _site, telescope_list, None, coordinate_system
335
+ )
336
+ )
337
+ return layouts
338
+
339
+
340
+ def get_array_layouts_from_file(file_path):
341
+ """
342
+ Retrieve array layout(s) from astropy table file(s).
343
+
344
+ Parameters
345
+ ----------
346
+ file_path : str or Path or list of str or list of Path
347
+ Path(s) to array layout files(s).
348
+
349
+ Returns
350
+ -------
351
+ list
352
+ List of dictionaries containing array layout names and their elements.
353
+ """
354
+ if isinstance(file_path, str | Path):
355
+ file_path = [file_path]
356
+
357
+ layouts = []
358
+ for _file in file_path:
359
+ layouts.append(
360
+ {
361
+ "name": (Path(_file).name).split(".")[0],
362
+ "array_elements": data_reader.read_table_from_file(file_name=_file),
363
+ }
364
+ )
365
+ return layouts
366
+
367
+
368
+ def _get_array_layout_dict(
369
+ db_config, model_version, site, telescope_list, layout_name, coordinate_system
370
+ ):
371
+ """Return array layout dictionary for a given telescope list."""
372
+ array_model = ArrayModel(
373
+ mongo_db_config=db_config,
374
+ model_version=model_version,
375
+ site=site,
376
+ array_elements=telescope_list,
377
+ layout_name=layout_name,
378
+ )
379
+ return {
380
+ "name": layout_name if layout_name else "list",
381
+ "site": site,
382
+ "array_elements": array_model.export_array_elements_as_table(
383
+ coordinate_system=coordinate_system
384
+ ),
385
+ }
@@ -36,6 +36,10 @@ class ArrayModel:
36
36
  array_elements: Union[str, Path, List[str]], optional
37
37
  Array element definitions (list of array element or path to file with
38
38
  the array element positions).
39
+ sim_telarray_seeds : dict, optional
40
+ Dictionary with configuration for sim_telarray random instrument setup.
41
+ simtel_path: str, Path, optional
42
+ Path to the sim_telarray installation directory.
39
43
  """
40
44
 
41
45
  def __init__(
@@ -46,6 +50,8 @@ class ArrayModel:
46
50
  site: str | None = None,
47
51
  layout_name: str | None = None,
48
52
  array_elements: str | Path | list[str] | None = None,
53
+ sim_telarray_seeds: dict | None = None,
54
+ simtel_path: str | Path | None = None,
49
55
  ):
50
56
  """Initialize ArrayModel."""
51
57
  self._logger = logging.getLogger(__name__)
@@ -65,6 +71,8 @@ class ArrayModel:
65
71
 
66
72
  self._telescope_model_files_exported = False
67
73
  self._array_model_file_exported = False
74
+ self.sim_telarray_seeds = sim_telarray_seeds
75
+ self.simtel_path = simtel_path
68
76
 
69
77
  def _initialize(self, site: str, array_elements_config: str | Path | list[str]):
70
78
  """
@@ -116,6 +124,26 @@ class ArrayModel:
116
124
  telescope_model = self._build_telescope_models(site_model, array_elements)
117
125
  return array_elements, site_model, telescope_model
118
126
 
127
+ @property
128
+ def config_file_path(self) -> Path:
129
+ """
130
+ Return the path of the array config file for sim_telarray.
131
+
132
+ Returns
133
+ -------
134
+ Path
135
+ Path of the exported config file for sim_telarray.
136
+ """
137
+ if self._config_file_path is None:
138
+ config_file_name = names.simtel_config_file_name(
139
+ array_name=self.layout_name,
140
+ site=self.site_model.site,
141
+ model_version=self.model_version,
142
+ label=self.label,
143
+ )
144
+ self._config_file_path = self.get_config_directory().joinpath(config_file_name)
145
+ return self._config_file_path
146
+
119
147
  @property
120
148
  def number_of_telescopes(self) -> int:
121
149
  """
@@ -140,6 +168,34 @@ class ArrayModel:
140
168
  """
141
169
  return self.site_model.site
142
170
 
171
+ @property
172
+ def model_version(self):
173
+ """Model version."""
174
+ return self._model_version
175
+
176
+ @model_version.setter
177
+ def model_version(self, model_version):
178
+ """
179
+ Set model version.
180
+
181
+ Parameters
182
+ ----------
183
+ _model_version: str or list
184
+ Model version (e.g., "6.0.0").
185
+ If a list is passed, it must contain exactly one element,
186
+ and only that element will be used.
187
+
188
+ Raises
189
+ ------
190
+ ValueError
191
+ If more than one model version is passed.
192
+ """
193
+ if isinstance(model_version, list):
194
+ raise ValueError(
195
+ f"Only one model version can be passed to {self.__class__.__name__}, not a list."
196
+ )
197
+ self._model_version = model_version
198
+
143
199
  def _build_telescope_models(self, site_model: SiteModel, array_elements: dict) -> dict:
144
200
  """
145
201
  Build the the telescope models for all telescopes of this array.
@@ -187,7 +243,7 @@ class ArrayModel:
187
243
  )
188
244
  if name not in exported_models:
189
245
  self._logger.debug(f"Exporting configuration file for telescope {name}")
190
- tel_model.export_config_file()
246
+ tel_model.write_sim_telarray_config_file()
191
247
  exported_models.append(name)
192
248
  else:
193
249
  self._logger.debug(
@@ -196,29 +252,23 @@ class ArrayModel:
196
252
 
197
253
  self._telescope_model_files_exported = True
198
254
 
199
- def export_simtel_array_config_file(self):
255
+ def export_sim_telarray_config_file(self):
200
256
  """Export sim_telarray configuration file for the array into the model directory."""
201
- # Setting file name and the location
202
- config_file_name = names.simtel_config_file_name(
203
- array_name=self.layout_name,
204
- site=self.site_model.site,
205
- model_version=self.model_version,
206
- label=self.label,
207
- )
208
- self._config_file_path = self.get_config_directory().joinpath(config_file_name)
257
+ self.site_model.export_model_files()
209
258
 
210
- # Writing parameters to the file
211
- self._logger.info(f"Writing array configuration file into {self._config_file_path}")
259
+ self._logger.info(f"Writing array configuration file into {self.config_file_path}")
212
260
  simtel_writer = SimtelConfigWriter(
213
261
  site=self.site_model.site,
214
262
  layout_name=self.layout_name,
215
263
  model_version=self.model_version,
216
264
  label=self.label,
265
+ simtel_path=self.simtel_path,
217
266
  )
218
267
  simtel_writer.write_array_config_file(
219
- config_file_path=self._config_file_path,
268
+ config_file_path=self.config_file_path,
220
269
  telescope_model=self.telescope_model,
221
270
  site_model=self.site_model,
271
+ sim_telarray_seeds=self.sim_telarray_seeds,
222
272
  )
223
273
  self._array_model_file_exported = True
224
274
 
@@ -231,21 +281,7 @@ class ArrayModel:
231
281
  if not self._telescope_model_files_exported:
232
282
  self.export_simtel_telescope_config_files()
233
283
  if not self._array_model_file_exported:
234
- self.export_simtel_array_config_file()
235
-
236
- def get_config_file(self) -> Path:
237
- """
238
- Return the path of the array config file for sim_telarray.
239
-
240
- A new config file is produced if the file is not updated.
241
-
242
- Returns
243
- -------
244
- Path
245
- Path of the exported config file for sim_telarray.
246
- """
247
- self.export_all_simtel_config_files()
248
- return self._config_file_path
284
+ self.export_sim_telarray_config_file()
249
285
 
250
286
  def get_config_directory(self) -> Path:
251
287
  """
@@ -257,7 +293,9 @@ class ArrayModel:
257
293
  Path of the config directory path for sim_telarray.
258
294
  """
259
295
  if self._config_file_directory is None:
260
- self._config_file_directory = self.io_handler.get_output_directory(self.label, "model")
296
+ self._config_file_directory = self.io_handler.get_output_directory(
297
+ self.label, f"model/{self.model_version}"
298
+ )
261
299
  return self._config_file_directory
262
300
 
263
301
  def _load_array_element_positions_from_file(
@@ -331,6 +369,7 @@ class ArrayModel:
331
369
  "type": "float64",
332
370
  "file": False,
333
371
  "meta_parameter": False,
372
+ "model_parameter_schema_version": "0.1.0",
334
373
  }
335
374
 
336
375
  def _get_array_elements_from_list(self, array_elements_list: list[str]) -> dict: