gammasimtools 0.15.0__py3-none-any.whl → 0.16.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 (223) hide show
  1. {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/METADATA +2 -32
  2. {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/RECORD +222 -214
  3. {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/entry_points.txt +5 -2
  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_psf_parameters.py +12 -9
  10. simtools/applications/docs_produce_array_element_report.py +3 -3
  11. simtools/applications/docs_produce_calibration_reports.py +49 -0
  12. simtools/applications/docs_produce_simulation_configuration_report.py +50 -0
  13. simtools/applications/{generate_simtel_array_histograms.py → generate_sim_telarray_histograms.py} +2 -2
  14. simtools/applications/production_derive_corsika_limits.py +63 -10
  15. simtools/applications/production_derive_statistics.py +125 -0
  16. simtools/applications/production_generate_grid.py +197 -0
  17. simtools/applications/production_generate_simulation_config.py +0 -10
  18. simtools/applications/simulate_light_emission.py +5 -13
  19. simtools/applications/simulate_prod.py +16 -4
  20. simtools/applications/validate_cumulative_psf.py +6 -4
  21. simtools/applications/validate_file_using_schema.py +7 -3
  22. simtools/applications/validate_optics.py +5 -4
  23. simtools/camera/camera_efficiency.py +14 -39
  24. simtools/configuration/commandline_parser.py +4 -3
  25. simtools/configuration/configurator.py +10 -0
  26. simtools/corsika/corsika_config.py +103 -5
  27. simtools/data_model/format_checkers.py +9 -0
  28. simtools/data_model/model_data_writer.py +3 -0
  29. simtools/data_model/schema.py +27 -16
  30. simtools/data_model/validate_data.py +27 -7
  31. simtools/db/db_handler.py +10 -4
  32. simtools/layout/array_layout.py +1 -0
  33. simtools/model/array_model.py +63 -29
  34. simtools/model/model_parameter.py +76 -51
  35. simtools/model/model_utils.py +43 -1
  36. simtools/model/site_model.py +3 -2
  37. simtools/model/telescope_model.py +4 -4
  38. simtools/production_configuration/calculate_statistical_errors_grid_point.py +0 -4
  39. simtools/production_configuration/{event_scaler.py → derive_production_statistics.py} +24 -20
  40. simtools/production_configuration/derive_production_statistics_handler.py +119 -0
  41. simtools/production_configuration/generate_production_grid.py +364 -0
  42. simtools/production_configuration/generate_simulation_config.py +9 -9
  43. simtools/production_configuration/interpolation_handler.py +16 -11
  44. simtools/ray_tracing/mirror_panel_psf.py +16 -20
  45. simtools/ray_tracing/psf_analysis.py +2 -2
  46. simtools/ray_tracing/ray_tracing.py +5 -1
  47. simtools/reporting/docs_read_parameters.py +361 -58
  48. simtools/runners/corsika_runner.py +11 -1
  49. simtools/runners/corsika_simtel_runner.py +80 -89
  50. simtools/runners/runner_services.py +17 -4
  51. simtools/runners/simtel_runner.py +27 -10
  52. simtools/schemas/model_parameter.metaschema.yml +4 -0
  53. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +1 -0
  54. simtools/schemas/model_parameters/adjust_gain.schema.yml +2 -2
  55. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +2 -2
  56. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +2 -2
  57. simtools/schemas/model_parameters/array_window.schema.yml +2 -2
  58. simtools/schemas/model_parameters/asum_offset.schema.yml +2 -2
  59. simtools/schemas/model_parameters/asum_shaping.schema.yml +2 -2
  60. simtools/schemas/model_parameters/asum_threshold.schema.yml +2 -2
  61. simtools/schemas/model_parameters/axes_offsets.schema.yml +2 -2
  62. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +2 -2
  63. simtools/schemas/model_parameters/camera_body_shape.schema.yml +2 -2
  64. simtools/schemas/model_parameters/camera_config_file.schema.yml +2 -2
  65. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +2 -2
  66. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +2 -2
  67. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +2 -2
  68. simtools/schemas/model_parameters/camera_depth.schema.yml +2 -2
  69. simtools/schemas/model_parameters/camera_filter.schema.yml +2 -2
  70. simtools/schemas/model_parameters/camera_pixels.schema.yml +2 -2
  71. simtools/schemas/model_parameters/camera_transmission.schema.yml +2 -2
  72. simtools/schemas/model_parameters/channels_per_chip.schema.yml +2 -2
  73. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +2 -2
  74. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +90 -1
  75. simtools/schemas/model_parameters/default_trigger.schema.yml +2 -2
  76. simtools/schemas/model_parameters/design_model.schema.yml +2 -2
  77. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +2 -2
  78. simtools/schemas/model_parameters/disc_bins.schema.yml +2 -2
  79. simtools/schemas/model_parameters/disc_start.schema.yml +2 -2
  80. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +2 -2
  81. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +2 -2
  82. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +2 -2
  83. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +2 -2
  84. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +2 -2
  85. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +2 -2
  86. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +2 -2
  87. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +2 -2
  88. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +2 -2
  89. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +2 -2
  90. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +2 -2
  91. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +2 -2
  92. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +2 -2
  93. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +2 -2
  94. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +2 -2
  95. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +2 -2
  96. simtools/schemas/model_parameters/dish_shape_length.schema.yml +2 -2
  97. simtools/schemas/model_parameters/dsum_clipping.schema.yml +2 -2
  98. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +2 -2
  99. simtools/schemas/model_parameters/dsum_offset.schema.yml +2 -2
  100. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +2 -2
  101. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +2 -2
  102. simtools/schemas/model_parameters/dsum_prescale.schema.yml +2 -2
  103. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +2 -2
  104. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +2 -2
  105. simtools/schemas/model_parameters/dsum_shaping.schema.yml +2 -2
  106. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +2 -2
  107. simtools/schemas/model_parameters/dsum_threshold.schema.yml +3 -3
  108. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +2 -2
  109. simtools/schemas/model_parameters/effective_focal_length.schema.yml +2 -2
  110. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +2 -2
  111. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +2 -2
  112. simtools/schemas/model_parameters/fadc_bins.schema.yml +2 -2
  113. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +2 -2
  114. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +2 -2
  115. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +2 -2
  116. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +2 -2
  117. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +2 -2
  118. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +2 -2
  119. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +2 -2
  120. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +2 -2
  121. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +2 -2
  122. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +2 -2
  123. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +2 -2
  124. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +2 -2
  125. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +2 -2
  126. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +2 -2
  127. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +2 -2
  128. simtools/schemas/model_parameters/fadc_mhz.schema.yml +2 -2
  129. simtools/schemas/model_parameters/fadc_noise.schema.yml +2 -2
  130. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +2 -2
  131. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +2 -2
  132. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +2 -2
  133. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +2 -2
  134. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +2 -2
  135. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +2 -2
  136. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +2 -2
  137. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +2 -2
  138. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  139. simtools/schemas/model_parameters/flatfielding.schema.yml +2 -2
  140. simtools/schemas/model_parameters/focal_length.schema.yml +2 -2
  141. simtools/schemas/model_parameters/focus_offset.schema.yml +2 -2
  142. simtools/schemas/model_parameters/gain_variation.schema.yml +2 -2
  143. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +2 -2
  144. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +2 -2
  145. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +2 -2
  146. simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
  147. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +2 -2
  148. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +2 -2
  149. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +2 -2
  150. simtools/schemas/model_parameters/min_photons.schema.yml +2 -2
  151. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +2 -2
  152. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +2 -2
  153. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +2 -2
  154. simtools/schemas/model_parameters/mirror_class.schema.yml +2 -2
  155. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +2 -2
  156. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +2 -2
  157. simtools/schemas/model_parameters/mirror_list.schema.yml +2 -2
  158. simtools/schemas/model_parameters/mirror_offset.schema.yml +2 -2
  159. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +2 -2
  160. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +2 -2
  161. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +2 -2
  162. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +2 -2
  163. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +2 -2
  164. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +2 -2
  165. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +2 -2
  166. simtools/schemas/model_parameters/num_gains.schema.yml +2 -2
  167. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +2 -2
  168. simtools/schemas/model_parameters/optics_properties.schema.yml +2 -2
  169. simtools/schemas/model_parameters/pedestal_events.schema.yml +7 -3
  170. simtools/schemas/model_parameters/photon_delay.schema.yml +2 -2
  171. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +2 -2
  172. simtools/schemas/model_parameters/pm_average_gain.schema.yml +2 -2
  173. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +2 -2
  174. simtools/schemas/model_parameters/pm_gain_index.schema.yml +2 -2
  175. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +2 -2
  176. simtools/schemas/model_parameters/pm_transit_time.schema.yml +2 -2
  177. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +2 -2
  178. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +2 -2
  179. simtools/schemas/model_parameters/qe_variation.schema.yml +2 -2
  180. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +2 -2
  181. simtools/schemas/model_parameters/random_focal_length.schema.yml +2 -2
  182. simtools/schemas/model_parameters/random_generator.schema.yml +2 -2
  183. simtools/schemas/model_parameters/random_mono_probability.schema.yml +2 -2
  184. simtools/schemas/model_parameters/sampled_output.schema.yml +2 -2
  185. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +2 -2
  186. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +2 -2
  187. simtools/schemas/model_parameters/tailcut_scale.schema.yml +2 -2
  188. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +2 -2
  189. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +2 -2
  190. simtools/schemas/model_parameters/telescope_random_error.schema.yml +2 -2
  191. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +2 -2
  192. simtools/schemas/model_parameters/telescope_transmission.schema.yml +2 -2
  193. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +2 -2
  194. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +2 -2
  195. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +2 -2
  196. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +2 -2
  197. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +2 -2
  198. simtools/schemas/model_parameters/transit_time_error.schema.yml +2 -2
  199. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +2 -2
  200. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +2 -2
  201. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +2 -2
  202. simtools/schemas/model_parameters/trigger_pixels.schema.yml +2 -2
  203. simtools/simtel/simtel_config_reader.py +21 -17
  204. simtools/simtel/simtel_config_writer.py +237 -65
  205. simtools/simtel/simtel_io_file_info.py +57 -0
  206. simtools/simtel/simtel_io_histogram.py +10 -14
  207. simtools/simtel/simtel_io_histograms.py +2 -2
  208. simtools/simtel/simtel_io_metadata.py +91 -0
  209. simtools/simtel/simulator_array.py +26 -12
  210. simtools/simtel/simulator_camera_efficiency.py +12 -6
  211. simtools/simtel/simulator_light_emission.py +6 -11
  212. simtools/simtel/simulator_ray_tracing.py +14 -4
  213. simtools/simulator.py +230 -66
  214. simtools/testing/configuration.py +5 -0
  215. simtools/testing/helpers.py +18 -0
  216. simtools/testing/sim_telarray_metadata.py +212 -0
  217. simtools/testing/validate_output.py +12 -5
  218. simtools/utils/general.py +18 -27
  219. simtools/utils/names.py +27 -5
  220. simtools/visualization/visualize.py +2 -2
  221. simtools/applications/production_scale_events.py +0 -185
  222. {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/licenses/LICENSE +0 -0
  223. {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,7 @@
2
2
  """Configuration file writer for sim_telarray."""
3
3
 
4
4
  import logging
5
+ from copy import deepcopy
5
6
  from pathlib import Path
6
7
 
7
8
  import astropy.units as u
@@ -14,6 +15,27 @@ from simtools.utils import names
14
15
  __all__ = ["SimtelConfigWriter"]
15
16
 
16
17
 
18
+ def sim_telarray_random_seeds(seed, number):
19
+ """
20
+ Generate random seeds to be used in sim_telarray.
21
+
22
+ Parameters
23
+ ----------
24
+ seed: int
25
+ Seed for the random number generator.
26
+ number: int
27
+ Number of random seeds to generate.
28
+
29
+ Returns
30
+ -------
31
+ list
32
+ List of random seeds.
33
+ """
34
+ rng = np.random.default_rng(seed)
35
+ max_int32 = np.iinfo(np.int32).max # sim_telarray requires 32 bit integers
36
+ return list(rng.integers(low=1, high=max_int32, size=number, dtype=np.int32))
37
+
38
+
17
39
  class SimtelConfigWriter:
18
40
  """
19
41
  SimtelConfigWriter writes sim_telarray configuration files.
@@ -49,7 +71,9 @@ class SimtelConfigWriter:
49
71
  self._layout_name = layout_name
50
72
  self._telescope_model_name = telescope_model_name
51
73
 
52
- def write_telescope_config_file(self, config_file_path, parameters, config_parameters=None):
74
+ def write_telescope_config_file(
75
+ self, config_file_path, parameters, telescope_name=None, write_dummy_config=False
76
+ ):
53
77
  """
54
78
  Write the sim_telarray config file for a single telescope.
55
79
 
@@ -59,41 +83,38 @@ class SimtelConfigWriter:
59
83
  Path of the file to write on.
60
84
  parameters: dict
61
85
  Model parameters
62
- config_parameters: dict
63
- Simulation software configuration parameters
86
+ telescope_name: str
87
+ Name of the telescope (use self._telescope_model_name if None)
88
+ write_dummy_config: bool
89
+ Flag to write a dummy telescope configuration file.
64
90
  """
65
91
  self._logger.debug(f"Writing telescope config file {config_file_path}")
66
92
 
67
- if config_parameters:
68
- parameters.update(config_parameters)
69
-
70
93
  with open(config_file_path, "w", encoding="utf-8") as file:
71
94
  self._write_header(file, "TELESCOPE CONFIGURATION FILE")
72
95
 
96
+ telescope_name = telescope_name or self._telescope_model_name
73
97
  file.write("#ifdef TELESCOPE\n")
74
- file.write(
75
- f" echo Configuration for {self._telescope_model_name} - TELESCOPE $(TELESCOPE)\n"
76
- )
98
+ file.write(f" echo Configuration for {telescope_name} - TELESCOPE $(TELESCOPE)\n")
77
99
  file.write("#endif\n\n")
100
+ if write_dummy_config:
101
+ file.write("#define DUMMY_CONFIG 1\n")
78
102
 
79
103
  for par, value in parameters.items():
80
- _simtel_name = names.get_simulation_software_name_from_parameter_name(
81
- par, simulation_software="sim_telarray"
82
- )
83
- # array trigger is a site parameter, not a telescope parameter
84
- # fake_mirror_list is not a sim_telarray parameter (used for testeff only)
85
- if (
86
- not _simtel_name
87
- or _simtel_name.startswith("array_trigger")
88
- or _simtel_name == "fake_mirror_list"
89
- ):
90
- continue
91
- file.write(
92
- f"{_simtel_name} = {self._get_value_string_for_simtel(value['value'])}\n"
104
+ simtel_name, value = self._convert_model_parameters_to_simtel_format(
105
+ names.get_simulation_software_name_from_parameter_name(
106
+ par, software_name="sim_telarray"
107
+ ),
108
+ value["value"],
109
+ config_file_path,
110
+ None,
93
111
  )
94
- _config_meta = self._get_simtel_metadata("telescope", parameters)
95
- for value in _config_meta:
96
- file.write(f"{value}\n")
112
+ if simtel_name:
113
+ file.write(f"{simtel_name} = {self._get_value_string_for_simtel(value)}\n")
114
+ if "stars" not in parameters: # sim_telarray requires 'stars' to be set
115
+ file.write("stars = none\n")
116
+ for meta in self._get_sim_telarray_metadata("telescope", parameters, telescope_name):
117
+ file.write(f"{meta}\n")
97
118
 
98
119
  def _get_value_string_for_simtel(self, value):
99
120
  """
@@ -116,9 +137,11 @@ class SimtelConfigWriter:
116
137
  value = gen.convert_list_to_string(value, shorten_list=True)
117
138
  return value
118
139
 
119
- def _get_simtel_metadata(self, config_type, model_parameters):
140
+ def _get_sim_telarray_metadata(
141
+ self, config_type, model_parameters, telescope_model_name, sim_telarray_seeds=None
142
+ ):
120
143
  """
121
- Return simtel metadata.
144
+ Return sim_telarray metadata.
122
145
 
123
146
  Parameters
124
147
  ----------
@@ -126,12 +149,15 @@ class SimtelConfigWriter:
126
149
  Type of the configuration file (telescope, site)
127
150
  model_parameters: dict
128
151
  Model parameters dictionary.
152
+ telescope_model_name: str
153
+ Name of the telescope model
154
+ sim_telarray_seeds: dict
155
+ Dictionary with configuration for sim_telarray random instrument setup.
129
156
 
130
157
  Returns
131
158
  -------
132
159
  list
133
- List with simtel metadata.
134
-
160
+ List with sim_telarray metadata.
135
161
  """
136
162
  meta_parameters = [
137
163
  f"config_release = {self._model_version} with simtools v{simtools.version.__version__}",
@@ -140,10 +166,10 @@ class SimtelConfigWriter:
140
166
  if config_type == "telescope":
141
167
  meta_parameters.extend(
142
168
  [
143
- f"camera_config_name = {self._telescope_model_name}",
169
+ f"camera_config_name = {telescope_model_name}",
144
170
  "camera_config_variant = ",
145
171
  f"camera_config_version = {self._model_version}",
146
- f"optics_config_name = {self._telescope_model_name}",
172
+ f"optics_config_name = {telescope_model_name}",
147
173
  "optics_config_variant = ",
148
174
  f"optics_config_version = {self._model_version}",
149
175
  ]
@@ -161,25 +187,41 @@ class SimtelConfigWriter:
161
187
  ]
162
188
  )
163
189
  prefix = "metaparam global"
190
+ meta_parameters.append("metaparam global add random_seed")
164
191
  else:
165
192
  raise ValueError(f"Unknown metadata type {config_type}")
166
193
 
167
- if model_parameters:
168
- for key, value in model_parameters.items():
169
- simtel_name = names.get_simulation_software_name_from_parameter_name(
170
- key, simulation_software="sim_telarray", set_meta_parameter=False
171
- )
172
- if simtel_name and value.get("meta_parameter"):
173
- meta_parameters.append(f"{prefix} add {simtel_name}")
174
- simtel_name = names.get_simulation_software_name_from_parameter_name(
175
- key, simulation_software="sim_telarray", set_meta_parameter=True
176
- )
177
- if simtel_name and value.get("meta_parameter"):
178
- meta_parameters.append(f"{prefix} set {simtel_name}={value['value']}")
194
+ self._add_model_parameters_to_metadata(model_parameters, meta_parameters, prefix)
195
+
196
+ if sim_telarray_seeds and sim_telarray_seeds.get("random_instrument_instances"):
197
+ meta_parameters.append(f"{prefix} set instrument_seed={sim_telarray_seeds['seed']}")
198
+ meta_parameters.append(
199
+ f"{prefix} set instrument_instances="
200
+ f"{sim_telarray_seeds['random_instrument_instances']}"
201
+ )
179
202
 
180
203
  return meta_parameters
181
204
 
182
- def write_array_config_file(self, config_file_path, telescope_model, site_model):
205
+ def _add_model_parameters_to_metadata(self, model_parameters, meta_parameters, prefix):
206
+ """Add model parameters to metadata."""
207
+ if not model_parameters:
208
+ return
209
+
210
+ for key, value in model_parameters.items():
211
+ simtel_name = names.get_simulation_software_name_from_parameter_name(
212
+ key, software_name="sim_telarray", set_meta_parameter=False
213
+ )
214
+ if simtel_name and value.get("meta_parameter"):
215
+ meta_parameters.append(f"{prefix} add {simtel_name}")
216
+ simtel_name = names.get_simulation_software_name_from_parameter_name(
217
+ key, software_name="sim_telarray", set_meta_parameter=True
218
+ )
219
+ if simtel_name and value.get("meta_parameter"):
220
+ meta_parameters.append(f"{prefix} set {simtel_name}={value['value']}")
221
+
222
+ def write_array_config_file(
223
+ self, config_file_path, telescope_model, site_model, sim_telarray_seeds=None
224
+ ):
183
225
  """
184
226
  Write the sim_telarray config file for an array of telescopes.
185
227
 
@@ -191,11 +233,13 @@ class SimtelConfigWriter:
191
233
  Dictionary of TelescopeModel's instances as used by the ArrayModel instance.
192
234
  site_model: Site model
193
235
  Site model.
236
+ sim_telarray_seeds: dict
237
+ Dictionary with configuration for sim_telarray random instrument setup.
194
238
  """
239
+ config_file_directory = Path(config_file_path).parent
195
240
  with open(config_file_path, "w", encoding="utf-8") as file:
196
241
  self._write_header(file, "ARRAY CONFIGURATION FILE")
197
242
 
198
- # Be careful with the formatting - simtel is sensitive
199
243
  file.write("#ifndef TELESCOPE\n")
200
244
  file.write("# define TELESCOPE 0\n")
201
245
  file.write("#endif\n\n")
@@ -208,27 +252,66 @@ class SimtelConfigWriter:
208
252
  file.write(self.TAB + f"echo ModelVersion: {self._model_version}\n")
209
253
  file.write(self.TAB + "echo *****************************\n\n")
210
254
 
211
- # Writing site parameters
212
255
  self._write_site_parameters(
213
- file, site_model.parameters, Path(config_file_path).parent, telescope_model
256
+ file,
257
+ site_model.parameters,
258
+ config_file_directory,
259
+ telescope_model,
260
+ sim_telarray_seeds,
214
261
  )
215
262
 
216
- # Maximum telescopes
217
263
  file.write(self.TAB + f"maximum_telescopes = {len(telescope_model)}\n\n")
218
264
 
219
265
  # Default telescope in sim_telarray - 0th tel in telescope list
220
266
  _, first_telescope = next(iter(telescope_model.items()))
221
- tel_config_file = first_telescope.get_config_file(no_export=True).name
222
- file.write(f"# include <{tel_config_file}>\n\n")
267
+ invalid_telescope_name = "InvalidTelescope"
268
+ file.write(f"# include <{invalid_telescope_name}.cfg>\n\n")
269
+ self.write_dummy_telescope_configuration_file(
270
+ deepcopy(first_telescope.parameters),
271
+ config_file_directory / f"{invalid_telescope_name}.cfg",
272
+ invalid_telescope_name,
273
+ )
223
274
 
224
- # Looping over telescopes
225
275
  for count, (tel_name, tel_model) in enumerate(telescope_model.items()):
226
- tel_config_file = tel_model.get_config_file(no_export=True).name
227
- file.write(f"%{tel_name}\n")
276
+ tel_config_file = tel_model.config_file_path.name
277
+ file.write(f"% {tel_name}\n")
228
278
  file.write(f"#elif TELESCOPE == {count + 1}\n\n")
229
279
  file.write(f"# include <{tel_config_file}>\n\n")
230
280
  file.write("#endif \n\n") # configuration files need to end with \n\n
231
281
 
282
+ if sim_telarray_seeds and sim_telarray_seeds.get("random_instrument_instances"):
283
+ self._write_random_seeds_file(sim_telarray_seeds, config_file_directory)
284
+
285
+ def _write_random_seeds_file(self, sim_telarray_seeds, config_file_directory):
286
+ """
287
+ Write list of random number used to generate random instances of instrument.
288
+
289
+ Parameters
290
+ ----------
291
+ random_instrument_instances: int
292
+ Number of random instances of the instrument.
293
+ """
294
+ self._logger.info(
295
+ "Writing random seed file "
296
+ f"{config_file_directory}/{sim_telarray_seeds['seed_file_name']}"
297
+ f" (global seed {sim_telarray_seeds['seed']})"
298
+ )
299
+ if sim_telarray_seeds["random_instrument_instances"] > 1024:
300
+ raise ValueError("Number of random instances of instrument must be less than 1024")
301
+ random_integers = sim_telarray_random_seeds(
302
+ sim_telarray_seeds["seed"], sim_telarray_seeds["random_instrument_instances"]
303
+ )
304
+ with open(
305
+ config_file_directory / sim_telarray_seeds["seed_file_name"], "w", encoding="utf-8"
306
+ ) as file:
307
+ file.write(
308
+ "# Random seeds for instrument configuration generated with seed "
309
+ f"{sim_telarray_seeds['seed']}"
310
+ f" (model version {self._model_version}, site {self._site})\n"
311
+ )
312
+ for number in random_integers:
313
+ file.write(f"{number}\n")
314
+
232
315
  def write_single_mirror_list_file(
233
316
  self, mirror_number, mirrors, single_mirror_list_file, set_focal_length_to_zero=False
234
317
  ):
@@ -288,7 +371,7 @@ class SimtelConfigWriter:
288
371
  title: str
289
372
  Title of the header.
290
373
  comment_char: str
291
- Character to be used for comments, which differs among ctypes of config files.
374
+ Character to be used for comments, which differs among types of config files.
292
375
  """
293
376
  header = f"{comment_char}{50 * '='}\n"
294
377
  header += f"{comment_char} {title}\n"
@@ -309,7 +392,9 @@ class SimtelConfigWriter:
309
392
  header += f"{comment_char}\n"
310
393
  file.write(header)
311
394
 
312
- def _write_site_parameters(self, file, site_parameters, model_path, telescope_model):
395
+ def _write_site_parameters(
396
+ self, file, site_parameters, model_path, telescope_model, sim_telarray_seeds=None
397
+ ):
313
398
  """
314
399
  Write site parameters.
315
400
 
@@ -323,20 +408,25 @@ class SimtelConfigWriter:
323
408
  Path to the model for writing of additional files.
324
409
  telescope_model: dict of TelescopeModel
325
410
  Telescope models.
411
+ sim_telarray_seeds: dict
412
+ Dictionary with configuration for sim_telarray random instrument setup.
326
413
  """
327
414
  file.write(self.TAB + "% Site parameters\n")
328
415
  for par, value in site_parameters.items():
329
- _simtel_name = names.get_simulation_software_name_from_parameter_name(
330
- par, simulation_software="sim_telarray"
416
+ simtel_name, value = self._convert_model_parameters_to_simtel_format(
417
+ names.get_simulation_software_name_from_parameter_name(
418
+ par, software_name="sim_telarray"
419
+ ),
420
+ value["value"],
421
+ model_path,
422
+ telescope_model,
331
423
  )
332
- _simtel_name, value = self._convert_model_parameters_to_simtel_format(
333
- _simtel_name, value["value"], model_path, telescope_model
334
- )
335
- if _simtel_name is not None:
336
- file.write(f"{self.TAB}{_simtel_name} = {value}\n")
337
- _simtel_meta = self._get_simtel_metadata("site", site_parameters)
338
- for value in _simtel_meta:
339
- file.write(f"{self.TAB}{value}\n")
424
+ if simtel_name is not None:
425
+ file.write(f"{self.TAB}{simtel_name} = {value}\n")
426
+ for meta in self._get_sim_telarray_metadata(
427
+ "site", site_parameters, self._telescope_model_name, sim_telarray_seeds
428
+ ):
429
+ file.write(f"{self.TAB}{meta}\n")
340
430
  file.write("\n")
341
431
 
342
432
  def _convert_model_parameters_to_simtel_format(
@@ -370,6 +460,8 @@ class SimtelConfigWriter:
370
460
  value = conversion_dict[simtel_name](value, model_path, telescope_model)
371
461
  except KeyError:
372
462
  pass
463
+ except AttributeError: # covers cases where telescope_model is None
464
+ return None, None
373
465
  return simtel_name, value
374
466
 
375
467
  def _write_array_triggers_file(self, array_triggers, model_path, telescope_model):
@@ -432,3 +524,83 @@ class SimtelConfigWriter:
432
524
  if trigger_dict["name"] == telescope_type + "_array":
433
525
  return trigger_dict
434
526
  return None
527
+
528
+ def write_dummy_telescope_configuration_file(
529
+ self, parameters, config_file_path, telescope_name
530
+ ):
531
+ """
532
+ Write 'dummy' telescope configuration file used as zeroth telescope in sim_telarray.
533
+
534
+ Replaces key telescope configuration values with dummy values.
535
+
536
+ Parameters
537
+ ----------
538
+ parameters: dict
539
+ Telescope parameters used as template.
540
+ config_file_path: str or Path
541
+ Path of the dummy configuration file to write on.
542
+ telescope_name: str
543
+ Name of the telescope.
544
+ """
545
+ self._logger.debug(f"Writing {telescope_name} telescope config file {config_file_path}")
546
+ dummy_defaults = {
547
+ "camera_config_file": f"{telescope_name}_single_pixel_camera.dat",
548
+ "discriminator_pulse_shape": f"{telescope_name}_pulse.dat",
549
+ "fadc_pulse_shape": f"{telescope_name}_pulse.dat",
550
+ "mirror_list": f"{telescope_name}_single_12m_mirror.dat",
551
+ "mirror_reflectivity": f"{telescope_name}_reflectivity.dat",
552
+ "camera_pixels": 1,
553
+ "trigger_pixels": 1,
554
+ "num_gains": 1,
555
+ "fadc_bins": 10,
556
+ "disc_bins": 10,
557
+ "fadc_sum_bins": 10,
558
+ "fadc_sum_offset": 0,
559
+ "asum_threshold": 0,
560
+ "dsum_threshold": 0,
561
+ "discriminator_threshold": 1,
562
+ "fadc_amplitude": 1.0,
563
+ "discriminator_amplitude": 1.0,
564
+ }
565
+
566
+ for key, val in dummy_defaults.items():
567
+ if key in parameters:
568
+ parameters[key]["value"] = val
569
+
570
+ self.write_telescope_config_file(
571
+ config_file_path, parameters, telescope_name, write_dummy_config=True
572
+ )
573
+
574
+ config_file_directory = Path(config_file_path).parent
575
+ self._write_dummy_mirror_list_files(config_file_directory, telescope_name)
576
+ self._write_dummy_camera_files(config_file_directory, telescope_name)
577
+
578
+ def _write_dummy_mirror_list_files(self, config_directory, telescope_name):
579
+ """Write dummy mirror list with single mirror and reflectivity file."""
580
+ with open(
581
+ config_directory / f"{telescope_name}_single_12m_mirror.dat", "w", encoding="utf-8"
582
+ ) as file:
583
+ file.write("0 0 1200 0.0 0\n")
584
+ with open(
585
+ config_directory / f"{telescope_name}_reflectivity.dat", "w", encoding="utf-8"
586
+ ) as file:
587
+ file.writelines(f"{w} 0.8\n" for w in range(200, 801, 50))
588
+
589
+ def _write_dummy_camera_files(self, config_directory, telescope_name):
590
+ """Write dummy camera, pulse shape, and funnels file with a single pixel."""
591
+ with open(
592
+ config_directory / f"{telescope_name}_single_pixel_camera.dat", "w", encoding="utf-8"
593
+ ) as file:
594
+ file.write(f'PixType 1 0 0 300 1 300 0.00 "{telescope_name}_funnels.dat"\n')
595
+ file.write("Pixel 0 1 0. 0. 0 0 0 0x00 1\n")
596
+ file.write("Trigger 1 of 0\n")
597
+
598
+ with open(config_directory / f"{telescope_name}_funnel.dat", "w", encoding="utf-8") as file:
599
+ file.writelines(f"{a} 0.78 1.5\n" for a in range(36))
600
+
601
+ with open(config_directory / f"{telescope_name}_pulse.dat", "w", encoding="utf-8") as file:
602
+ file.write("0 0 0\n")
603
+ file.write("1 1 1\n")
604
+ file.write("2 2 2\n")
605
+ file.write("3 3 3\n")
606
+ file.write("4 0 0\n")
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/python3
2
+ """Read file info and run headers from sim_telarray files."""
3
+
4
+ from eventio import EventIOFile
5
+ from eventio.simtel import MCRunHeader, RunHeader
6
+
7
+
8
+ def get_corsika_run_number(file):
9
+ """
10
+ Return the CORSIKA run number from a sim_telarray file.
11
+
12
+ Parameters
13
+ ----------
14
+ file: str
15
+ Path to the sim_telarray file.
16
+
17
+ Returns
18
+ -------
19
+ int, None
20
+ CORSIKA run number. Returns None if not found.
21
+ """
22
+ run_header = get_corsika_run_header(file)
23
+ return run_header.get("run") if run_header else None
24
+
25
+
26
+ def get_corsika_run_header(file):
27
+ """
28
+ Return the CORSIKA run header from a sim_telarray file.
29
+
30
+ Reads both RunHeader and MCRunHeader object from file and
31
+ returns a merged dictionary.
32
+
33
+ Parameters
34
+ ----------
35
+ file: str
36
+ Path to the sim_telarray file.
37
+
38
+ Returns
39
+ -------
40
+ dict, None
41
+ CORSIKA run header. Returns None if not found.
42
+ """
43
+ run_header = None
44
+ mc_run_header = None
45
+
46
+ with EventIOFile(file) as f:
47
+ for o in f:
48
+ if isinstance(o, RunHeader) and run_header is None:
49
+ run_header = o.parse()
50
+ elif isinstance(o, MCRunHeader) and mc_run_header is None:
51
+ mc_run_header = o.parse()
52
+ if run_header and mc_run_header:
53
+ break
54
+
55
+ run_header = run_header or {}
56
+ mc_run_header = mc_run_header or {}
57
+ return run_header | mc_run_header or None
@@ -1,4 +1,4 @@
1
- """Reads the content of either a single histogram or simtel_array output file."""
1
+ """Reads the content of either a single histogram or sim_telarray output file."""
2
2
 
3
3
  import copy
4
4
  import logging
@@ -11,7 +11,8 @@ from ctao_cr_spectra.definitions import IRFDOC_PROTON_SPECTRUM
11
11
  from ctao_cr_spectra.spectral import cone_solid_angle
12
12
  from eventio import EventIOFile, Histograms
13
13
  from eventio.search_utils import yield_toplevel_of_type
14
- from eventio.simtel import MCRunHeader
14
+
15
+ from simtools.simtel.simtel_io_file_info import get_corsika_run_header
15
16
 
16
17
  __all__ = [
17
18
  "HistogramIdNotFoundError",
@@ -32,13 +33,13 @@ class SimtelIOHistogram:
32
33
  """
33
34
  Reads and generates histograms from sim_telarray output.
34
35
 
35
- Read the content of either a single histogram (.hdata, or .hdata.zst) or a single simtel_array
36
+ Read the content of either a single histogram (.hdata, or .hdata.zst) or a single sim_telarray
36
37
  output file (.simtel or .simtel.zst).
37
38
 
38
39
  Parameters
39
40
  ----------
40
41
  histogram_file: str
41
- The histogram (.hdata.zst) or simtel_array (.simtel.zst) file.
42
+ The histogram (.hdata.zst) or sim_telarray (.simtel.zst) file.
42
43
  area_from_distribution: bool
43
44
  If true, the area thrown (the area in which the simulated events are distributed)
44
45
  in the trigger rate calculation is estimated based on the event distribution.
@@ -135,14 +136,9 @@ class SimtelIOHistogram:
135
136
  Returns
136
137
  -------
137
138
  dict:
138
- dictionary with information about the simulation (pyeventio MCRunHeader object).
139
+ dictionary with information about the simulation
139
140
  """
140
- if self._config is None:
141
- with EventIOFile(self.histogram_file) as f:
142
- self._config = next(
143
- (obj.parse() for obj in f if isinstance(obj, MCRunHeader)), None
144
- )
145
- return self._config
141
+ return self._config if self._config else get_corsika_run_header(self.histogram_file)
146
142
 
147
143
  @property
148
144
  def total_number_of_events(self):
@@ -348,7 +344,7 @@ class SimtelIOHistogram:
348
344
  for the triggered events.
349
345
  """
350
346
  if self.trigger_rate is None:
351
- # Get the simulated and triggered 2D histograms from the simtel_array output file
347
+ # Get the simulated and triggered 2D histograms from the sim_telarray output file
352
348
  if events_histogram is None and triggered_events_histogram is None:
353
349
  events_histogram, triggered_events_histogram = self.fill_event_histogram_dicts()
354
350
  # Calculate triggered/simulated event 1D histogram (energy dependent)
@@ -408,7 +404,7 @@ class SimtelIOHistogram:
408
404
  """
409
405
  Produce the meta data to include in the tabulated form of the trigger rate per energy bin.
410
406
 
411
- It shows some information from the input file (simtel_array file) and the final estimate
407
+ It shows some information from the input file (sim_telarray file) and the final estimate
412
408
  system trigger rate.
413
409
 
414
410
  Returns
@@ -417,7 +413,7 @@ class SimtelIOHistogram:
417
413
  dictionary with the metadata.
418
414
  """
419
415
  return {
420
- "simtel_array_file": self.histogram_file,
416
+ "sim_telarray_file": self.histogram_file,
421
417
  "simulation_input": self.print_info(mode="silent"),
422
418
  "system_trigger_rate (Hz)": self.trigger_rate.value,
423
419
  }
@@ -24,7 +24,7 @@ __all__ = [
24
24
 
25
25
  class SimtelIOHistograms:
26
26
  """
27
- Read the content of either multiple histogram (.hdata, or .hdata.zst) or simtel_array files.
27
+ Read the content of either multiple histogram (.hdata, or .hdata.zst) or sim_telarray files.
28
28
 
29
29
  Allow both the .hdata.zst histogram and the .simtel.zst output file type.
30
30
  It uses the SimtelIOHistogram class to deal with individual files.
@@ -159,7 +159,7 @@ class SimtelIOHistograms:
159
159
  if sim_hist is None or trig_hist is None:
160
160
  msg = (
161
161
  "Simulated and triggered histograms were not found in the stacked histograms."
162
- " Please check your simtel_array files!"
162
+ " Please check your sim_telarray files!"
163
163
  )
164
164
  self._logger.error(msg)
165
165
  raise HistogramIdNotFoundError