gammasimtools 0.13.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 (226) hide show
  1. {gammasimtools-0.13.0.dist-info → gammasimtools-0.14.0.dist-info}/METADATA +3 -3
  2. {gammasimtools-0.13.0.dist-info → gammasimtools-0.14.0.dist-info}/RECORD +224 -217
  3. {gammasimtools-0.13.0.dist-info → gammasimtools-0.14.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.13.0.dist-info → gammasimtools-0.14.0.dist-info}/entry_points.txt +3 -1
  5. simtools/_version.py +2 -2
  6. simtools/applications/db_add_file_to_db.py +15 -0
  7. simtools/applications/db_add_value_from_json_to_db.py +18 -1
  8. simtools/applications/derive_ctao_array_layouts.py +120 -0
  9. simtools/applications/derive_photon_electron_spectrum.py +29 -1
  10. simtools/applications/docs_produce_array_element_report.py +41 -16
  11. simtools/applications/docs_produce_model_parameter_reports.py +28 -8
  12. simtools/applications/{production_extract_mc_event_data.py → generate_simtel_event_data.py} +12 -20
  13. simtools/applications/print_version.py +81 -0
  14. simtools/applications/production_derive_corsika_limits.py +172 -39
  15. simtools/applications/production_scale_events.py +59 -36
  16. simtools/applications/run_application.py +41 -11
  17. simtools/applications/simulate_light_emission.py +115 -247
  18. simtools/applications/simulate_prod_htcondor_generator.py +2 -2
  19. simtools/camera/single_photon_electron_spectrum.py +163 -15
  20. simtools/data_model/model_data_writer.py +7 -6
  21. simtools/db/db_handler.py +14 -8
  22. simtools/dependencies.py +38 -3
  23. simtools/layout/array_layout.py +1 -0
  24. simtools/layout/ctao_array_layouts.py +172 -0
  25. simtools/model/array_model.py +3 -4
  26. simtools/model/model_parameter.py +30 -87
  27. simtools/production_configuration/derive_corsika_limits.py +222 -154
  28. simtools/production_configuration/event_scaler.py +2 -2
  29. simtools/reporting/docs_auto_report_generator.py +217 -0
  30. simtools/reporting/docs_read_parameters.py +192 -110
  31. simtools/schemas/application_workflow.metaschema.yml +3 -0
  32. simtools/schemas/model_parameter.metaschema.yml +13 -0
  33. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +6 -0
  34. simtools/schemas/model_parameters/adjust_gain.schema.yml +1 -1
  35. simtools/schemas/model_parameters/altitude.schema.yml +1 -1
  36. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +3 -3
  37. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +3 -3
  38. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +3 -3
  39. simtools/schemas/model_parameters/array_window.schema.yml +1 -1
  40. simtools/schemas/model_parameters/asum_clipping.schema.yml +1 -1
  41. simtools/schemas/model_parameters/asum_offset.schema.yml +1 -1
  42. simtools/schemas/model_parameters/asum_threshold.schema.yml +1 -1
  43. simtools/schemas/model_parameters/axes_offsets.schema.yml +2 -2
  44. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +1 -1
  45. simtools/schemas/model_parameters/camera_body_shape.schema.yml +1 -1
  46. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +1 -1
  47. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +1 -1
  48. simtools/schemas/model_parameters/camera_depth.schema.yml +1 -1
  49. simtools/schemas/model_parameters/camera_pixels.schema.yml +1 -1
  50. simtools/schemas/model_parameters/camera_transmission.schema.yml +1 -1
  51. simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
  52. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +1 -1
  53. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +1 -1
  54. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +1 -1
  55. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +1 -1
  56. simtools/schemas/model_parameters/dark_events.schema.yml +1 -1
  57. simtools/schemas/model_parameters/disc_bins.schema.yml +1 -1
  58. simtools/schemas/model_parameters/disc_start.schema.yml +1 -1
  59. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +1 -1
  60. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +1 -1
  61. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +1 -1
  62. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +1 -1
  63. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +1 -1
  64. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +1 -1
  65. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +1 -1
  66. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +1 -1
  67. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +1 -1
  68. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +1 -1
  69. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -1
  70. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +1 -1
  71. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +1 -1
  72. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +1 -1
  73. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +1 -1
  74. simtools/schemas/model_parameters/dish_shape_length.schema.yml +1 -1
  75. simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -1
  76. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +1 -1
  77. simtools/schemas/model_parameters/dsum_offset.schema.yml +1 -1
  78. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +1 -1
  79. simtools/schemas/model_parameters/dsum_prescale.schema.yml +2 -2
  80. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +1 -1
  81. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +1 -1
  82. simtools/schemas/model_parameters/dsum_threshold.schema.yml +1 -1
  83. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +1 -1
  84. simtools/schemas/model_parameters/effective_focal_length.schema.yml +5 -5
  85. simtools/schemas/model_parameters/epsg_code.schema.yml +1 -1
  86. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +1 -1
  87. simtools/schemas/model_parameters/fadc_bins.schema.yml +1 -1
  88. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
  89. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
  90. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +1 -1
  91. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +1 -1
  92. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +1 -1
  93. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
  94. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
  95. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +1 -1
  96. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +1 -1
  97. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +1 -1
  98. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +1 -1
  99. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +1 -1
  100. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +1 -1
  101. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +1 -1
  102. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +1 -1
  103. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +1 -1
  104. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +1 -1
  105. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +1 -1
  106. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +1 -1
  107. simtools/schemas/model_parameters/fadc_mhz.schema.yml +1 -1
  108. simtools/schemas/model_parameters/fadc_noise.schema.yml +1 -1
  109. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +1 -1
  110. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +1 -1
  111. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +1 -1
  112. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +1 -1
  113. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +1 -1
  114. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +1 -1
  115. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +1 -1
  116. simtools/schemas/model_parameters/focal_length.schema.yml +1 -1
  117. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +20 -20
  118. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +1 -1
  119. simtools/schemas/model_parameters/focus_offset.schema.yml +4 -4
  120. simtools/schemas/model_parameters/gain_variation.schema.yml +1 -1
  121. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +1 -1
  122. simtools/schemas/model_parameters/geomag_rotation.schema.yml +1 -1
  123. simtools/schemas/model_parameters/geomag_vertical.schema.yml +1 -1
  124. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +1 -1
  125. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
  126. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
  127. simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
  128. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +1 -1
  129. simtools/schemas/model_parameters/laser_photons.schema.yml +1 -1
  130. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +1 -1
  131. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +1 -1
  132. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +1 -1
  133. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +1 -1
  134. simtools/schemas/model_parameters/laser_var_photons.schema.yml +1 -1
  135. simtools/schemas/model_parameters/laser_wavelength.schema.yml +1 -1
  136. simtools/schemas/model_parameters/led_events.schema.yml +1 -1
  137. simtools/schemas/model_parameters/led_photons.schema.yml +1 -1
  138. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +1 -1
  139. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +1 -1
  140. simtools/schemas/model_parameters/led_var_photons.schema.yml +1 -1
  141. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
  142. simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
  143. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +1 -1
  144. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +4 -4
  145. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +4 -4
  146. simtools/schemas/model_parameters/mirror_class.schema.yml +1 -1
  147. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +1 -1
  148. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +1 -1
  149. simtools/schemas/model_parameters/mirror_offset.schema.yml +1 -1
  150. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +3 -3
  151. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +3 -3
  152. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +1 -1
  153. simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +45 -0
  154. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +2 -2
  155. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +1 -1
  156. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +5 -5
  157. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +1 -1
  158. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +1 -1
  159. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +1 -1
  160. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +2 -2
  161. simtools/schemas/model_parameters/num_gains.schema.yml +1 -1
  162. simtools/schemas/model_parameters/pedestal_events.schema.yml +1 -1
  163. simtools/schemas/model_parameters/photon_delay.schema.yml +1 -1
  164. simtools/schemas/model_parameters/photons_per_run.schema.yml +1 -1
  165. simtools/schemas/model_parameters/pixel_cells.schema.yml +1 -1
  166. simtools/schemas/model_parameters/pixels_parallel.schema.yml +1 -1
  167. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +1 -1
  168. simtools/schemas/model_parameters/pm_average_gain.schema.yml +1 -1
  169. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +1 -1
  170. simtools/schemas/model_parameters/pm_gain_index.schema.yml +1 -1
  171. simtools/schemas/model_parameters/pm_transit_time.schema.yml +4 -4
  172. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +1 -1
  173. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +7 -3
  174. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +1 -1
  175. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +1 -1
  176. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +20 -20
  177. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +1 -1
  178. simtools/schemas/model_parameters/qe_variation.schema.yml +1 -1
  179. simtools/schemas/model_parameters/random_focal_length.schema.yml +2 -2
  180. simtools/schemas/model_parameters/random_mono_probability.schema.yml +38 -0
  181. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +1 -1
  182. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +4 -1
  183. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +4 -1
  184. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +1 -1
  185. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +1 -1
  186. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +5 -5
  187. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
  188. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +1 -1
  189. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +1 -1
  190. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +20 -20
  191. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +1 -1
  192. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +1 -1
  193. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +1 -1
  194. simtools/schemas/model_parameters/stars.schema.yml +36 -0
  195. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
  196. simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
  197. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +1 -1
  198. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +1 -1
  199. simtools/schemas/model_parameters/telescope_random_error.schema.yml +1 -1
  200. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +1 -1
  201. simtools/schemas/model_parameters/telescope_transmission.schema.yml +6 -6
  202. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +1 -1
  203. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +1 -1
  204. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +1 -1
  205. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +1 -1
  206. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +1 -1
  207. simtools/schemas/model_parameters/transit_time_error.schema.yml +1 -1
  208. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +1 -1
  209. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +1 -1
  210. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +4 -4
  211. simtools/schemas/model_parameters/trigger_pixels.schema.yml +1 -1
  212. simtools/simtel/simtel_config_writer.py +70 -38
  213. simtools/simtel/simtel_io_event_reader.py +278 -0
  214. simtools/simtel/simtel_io_event_writer.py +317 -0
  215. simtools/simtel/simulator_light_emission.py +181 -67
  216. simtools/simulator.py +2 -2
  217. simtools/testing/configuration.py +17 -0
  218. simtools/utils/general.py +33 -7
  219. simtools/utils/geometry.py +19 -0
  220. simtools/utils/names.py +7 -1
  221. simtools/visualization/visualize.py +2 -2
  222. simtools/production_configuration/extract_mc_event_data.py +0 -253
  223. simtools/simtel/simtel_io_events.py +0 -265
  224. {gammasimtools-0.13.0.dist-info → gammasimtools-0.14.0.dist-info/licenses}/LICENSE +0 -0
  225. {gammasimtools-0.13.0.dist-info → gammasimtools-0.14.0.dist-info}/top_level.txt +0 -0
  226. /simtools/schemas/model_parameters/{nsb_skymap.schema.yml → nsb_sky_map.schema.yml} +0 -0
@@ -86,6 +86,18 @@ class ModelParameter:
86
86
  self._is_config_file_up_to_date = False
87
87
  self._is_exported_model_files_up_to_date = False
88
88
 
89
+ @property
90
+ def parameters(self):
91
+ """
92
+ Model parameters dictionary.
93
+
94
+ Returns
95
+ -------
96
+ dict
97
+ Dictionary containing all model parameters
98
+ """
99
+ return self._parameters
100
+
89
101
  def _get_parameter_dict(self, par_name):
90
102
  """
91
103
  Get model parameter dictionary as stored in the DB.
@@ -110,11 +122,11 @@ class ModelParameter:
110
122
  If par_name does not match any parameter in this model.
111
123
  """
112
124
  try:
113
- return self._parameters[par_name]
125
+ return self.parameters[par_name]
114
126
  except (KeyError, ValueError) as e:
115
- msg = f"Parameter {par_name} was not found in the model {self.name}, {self.site}."
116
- self._logger.error(msg)
117
- raise InvalidModelParameterError(msg) from e
127
+ raise InvalidModelParameterError(
128
+ f"Parameter {par_name} was not found in the model {self.name}, {self.site}."
129
+ ) from e
118
130
 
119
131
  def get_parameter_value(self, par_name, parameter_dict=None):
120
132
  """
@@ -258,7 +270,7 @@ class ModelParameter:
258
270
 
259
271
  def print_parameters(self):
260
272
  """Print parameters and their values for debugging purposes."""
261
- for par in self._parameters:
273
+ for par in self.parameters:
262
274
  print(f"{par} = {self.get_parameter_value(par)}")
263
275
 
264
276
  def _set_config_file_directory_and_name(self):
@@ -298,21 +310,6 @@ class ModelParameter:
298
310
  """
299
311
  return self._simulation_config_parameters.get(simulation_software)
300
312
 
301
- def has_parameter(self, par_name):
302
- """Check if a parameter exists in the model.
303
-
304
- Parameters
305
- ----------
306
- par_name : str
307
- Name of the parameter.
308
-
309
- Returns
310
- -------
311
- bool
312
- True if parameter exists in the model.
313
- """
314
- return par_name in self._parameters
315
-
316
313
  def _load_simulation_software_parameter(self):
317
314
  """Read simulation software parameters from DB."""
318
315
  for simulation_software in self._simulation_config_parameters:
@@ -337,12 +334,12 @@ class ModelParameter:
337
334
  if self.db is None:
338
335
  return
339
336
 
340
- if self.name is not None:
337
+ if self.name:
341
338
  self._parameters = self.db.get_model_parameters(
342
339
  self.site, self.name, self.collection, self.model_version
343
340
  )
344
341
 
345
- if self.site is not None:
342
+ if self.site:
346
343
  self._parameters.update(
347
344
  self.db.get_model_parameters(
348
345
  self.site,
@@ -353,56 +350,11 @@ class ModelParameter:
353
350
  )
354
351
  self._load_simulation_software_parameter()
355
352
 
356
- def set_extra_label(self, extra_label):
357
- """
358
- Set an extra label for the name of the config file.
359
-
360
- Notes
361
- -----
362
- The config file directory name is not affected by the extra label. Only the file name is \
363
- changed. This is important for the ArrayModel class to export multiple config files in the\
364
- same directory.
365
-
366
- Parameters
367
- ----------
368
- extra_label: str
369
- Extra label to be appended to the original label.
370
- """
371
- self._extra_label = extra_label
372
- self._set_config_file_directory_and_name()
373
-
374
353
  @property
375
354
  def extra_label(self):
376
355
  """Return the extra label if defined, if not return ''."""
377
356
  return self._extra_label if self._extra_label is not None else ""
378
357
 
379
- def get_simtel_parameters(self, parameters=None):
380
- """
381
- Get simtel parameters as name and value pairs.
382
-
383
- Parameters
384
- ----------
385
- parameters: dict
386
- Parameters (simtools) to be renamed (if necessary)
387
-
388
- Returns
389
- -------
390
- dict
391
- simtel parameters as dict (sorted by parameter names)
392
-
393
- """
394
- if parameters is None:
395
- parameters = self._parameters
396
-
397
- _simtel_parameter_value = {}
398
- for key in parameters:
399
- _par_name = names.get_simulation_software_name_from_parameter_name(
400
- key, simulation_software="sim_telarray"
401
- )
402
- if _par_name is not None:
403
- _simtel_parameter_value[_par_name] = parameters[key].get("value")
404
- return dict(sorted(_simtel_parameter_value.items()))
405
-
406
358
  def change_parameter(self, par_name, value):
407
359
  """
408
360
  Change the value of an existing parameter.
@@ -421,29 +373,24 @@ class ModelParameter:
421
373
  InvalidModelParameterError
422
374
  If the parameter to be changed does not exist in this model.
423
375
  """
424
- if par_name not in self._parameters:
425
- msg = f"Parameter {par_name} not in the model"
426
- self._logger.error(msg)
427
- raise InvalidModelParameterError(msg)
376
+ if par_name not in self.parameters:
377
+ raise InvalidModelParameterError(f"Parameter {par_name} not in the model")
428
378
 
429
- if isinstance(value, str):
430
- value = gen.convert_string_to_list(value)
379
+ value = gen.convert_string_to_list(value) if isinstance(value, str) else value
431
380
 
381
+ par_type = self.get_parameter_type(par_name)
432
382
  if not gen.validate_data_type(
433
- reference_dtype=self.get_parameter_type(par_name),
383
+ reference_dtype=par_type,
434
384
  value=value,
435
385
  dtype=None,
436
386
  allow_subtypes=True,
437
387
  ):
438
- raise ValueError(
439
- f"Could not cast {value} of type {type(value)} "
440
- f"to {self.get_parameter_type(par_name)}."
441
- )
388
+ raise ValueError(f"Could not cast {value} of type {type(value)} to {par_type}.")
442
389
 
443
390
  self._logger.debug(
444
391
  f"Changing parameter {par_name} from {self.get_parameter_value(par_name)} to {value}"
445
392
  )
446
- self._parameters[par_name]["value"] = value
393
+ self.parameters[par_name]["value"] = value
447
394
 
448
395
  # In case parameter is a file, the model files will be outdated
449
396
  if self.get_parameter_file_flag(par_name):
@@ -483,7 +430,7 @@ class ModelParameter:
483
430
 
484
431
  """
485
432
  for par, value in kwargs.items():
486
- if par in self._parameters:
433
+ if par in self.parameters:
487
434
  self.change_parameter(par, value)
488
435
 
489
436
  self._is_config_file_up_to_date = False
@@ -507,7 +454,7 @@ class ModelParameter:
507
454
  def export_model_files(self):
508
455
  """Export the model files into the config file directory."""
509
456
  # Removing parameter files added manually (which are not in DB)
510
- pars_from_db = copy(self._parameters)
457
+ pars_from_db = copy(self.parameters)
511
458
  if self._added_parameter_files is not None:
512
459
  for par in self._added_parameter_files:
513
460
  pars_from_db.pop(par)
@@ -517,18 +464,14 @@ class ModelParameter:
517
464
 
518
465
  def export_config_file(self):
519
466
  """Export the config file used by sim_telarray."""
520
- # Exporting model file
521
467
  if not self._is_exported_model_files_up_to_date:
522
468
  self.export_model_files()
523
469
 
524
- # Using SimtelConfigWriter to write the config file.
525
470
  self._load_simtel_config_writer()
526
471
  self.simtel_config_writer.write_telescope_config_file(
527
472
  config_file_path=self.config_file_path,
528
- parameters=self.get_simtel_parameters(parameters=self._parameters),
529
- config_parameters=self.get_simtel_parameters(
530
- parameters=self._simulation_config_parameters["simtel"]
531
- ),
473
+ parameters=self.parameters,
474
+ config_parameters=self._simulation_config_parameters["simtel"],
532
475
  )
533
476
 
534
477
  @property
@@ -1,16 +1,17 @@
1
- """Calculate the thresholds for energy, radial distance, and viewcone."""
1
+ """Calculate CORSIKA thresholds for energy, radial distance, and viewcone."""
2
+
3
+ import logging
2
4
 
3
5
  import astropy.units as u
4
6
  import matplotlib.pyplot as plt
5
7
  import numpy as np
6
- import tables
7
- from astropy.coordinates import AltAz
8
- from ctapipe.coordinates import GroundFrame, TiltedGroundFrame
8
+
9
+ from simtools.simtel.simtel_io_event_reader import SimtelIOEventDataReader
9
10
 
10
11
 
11
12
  class LimitCalculator:
12
13
  """
13
- Compute thresholds/limits for energy, radial distance, and viewcone.
14
+ Compute thresholds for CORSIKA configuration for energy, radial distance, and viewcone.
14
15
 
15
16
  Event data is read from the reduced MC event data file.
16
17
 
@@ -23,52 +24,14 @@ class LimitCalculator:
23
24
  """
24
25
 
25
26
  def __init__(self, event_data_file, telescope_list=None):
26
- """
27
- Initialize the LimitCalculator with the given event data file.
28
-
29
- Parameters
30
- ----------
31
- event_data_file : str
32
- Path to the reduced MC event data file.
33
- telescope_list : list, optional
34
- List of telescope IDs to filter the events (default is None).
35
- """
27
+ """Initialize the LimitCalculator with the given event data file."""
28
+ self._logger = logging.getLogger(__name__)
36
29
  self.event_data_file = event_data_file
37
30
  self.telescope_list = telescope_list
38
- self.event_x_core = None
39
- self.event_y_core = None
40
- self.simulated = None
41
- self.shower_id_triggered = None
42
- self.list_of_files = None
43
- self.shower_sim_azimuth = None
44
- self.shower_sim_altitude = None
45
- self.array_azimuth = None
46
- self.array_altitude = None
47
- self.trigger_telescope_list_list = None
48
- self.units = {}
49
- self._read_event_data()
50
-
51
- def _read_event_data(self):
52
- """Read the event data from the reduced MC event data file."""
53
- with tables.open_file(self.event_data_file, mode="r") as f:
54
- reduced_data = f.root.data.reduced_data
55
- triggered_data = f.root.data.triggered_data
56
- file_names = f.root.data.file_names
57
- trigger_telescope_list_list = f.root.data.trigger_telescope_list_list
58
-
59
- self.event_x_core = reduced_data.col("core_x")
60
- self.event_y_core = reduced_data.col("core_y")
61
- self.simulated = reduced_data.col("simulated")
62
- self.shower_id_triggered = triggered_data.col("shower_id_triggered")
63
- self.list_of_files = file_names.col("file_names")
64
- self.shower_sim_azimuth = reduced_data.col("shower_sim_azimuth")
65
- self.shower_sim_altitude = reduced_data.col("shower_sim_altitude")
66
- self.array_altitude = reduced_data.col("array_altitudes")
67
- self.array_azimuth = reduced_data.col("array_azimuths")
68
-
69
- self.trigger_telescope_list_list = [
70
- [np.int16(tel) for tel in event] for event in trigger_telescope_list_list
71
- ]
31
+
32
+ self.reader = SimtelIOEventDataReader(event_data_file, telescope_list=telescope_list)
33
+ self.event_data = self.reader.triggered_shower_data
34
+ self.triggered_data = self.reader.triggered_data
72
35
 
73
36
  def _compute_limits(self, hist, bin_edges, loss_fraction, limit_type="lower"):
74
37
  """
@@ -94,40 +57,18 @@ class LimitCalculator:
94
57
  total_events = np.sum(hist)
95
58
  threshold = (1 - loss_fraction) * total_events
96
59
  bin_index = np.searchsorted(cumulative_sum, threshold)
97
- return bin_edges[bin_index] if limit_type == "upper" else bin_edges[-bin_index]
98
60
 
99
- def _prepare_data_for_limits(self):
100
- """
101
- Prepare the data required for computing limits.
61
+ return bin_edges[bin_index] if limit_type == "upper" else bin_edges[-bin_index]
102
62
 
103
- Returns
104
- -------
105
- tuple
106
- Tuple containing core distances, triggered energies, core bins, and energy bins.
107
- """
108
- shower_id_triggered_masked = self.shower_id_triggered
109
- if self.telescope_list is not None:
110
- mask = np.array(
111
- [
112
- all(tel in event for tel in self.telescope_list)
113
- for event in self.trigger_telescope_list_list
114
- ]
115
- )
116
- shower_id_triggered_masked = self.shower_id_triggered[mask]
117
-
118
- triggered_energies = self.simulated[shower_id_triggered_masked]
119
- energy_bins = np.logspace(
120
- np.log10(triggered_energies.min()), np.log10(triggered_energies.max()), 1000
121
- )
122
- event_x_core_shower, event_y_core_shower = self._transform_to_shower_coordinates()
123
- core_distances_all = np.sqrt(event_x_core_shower**2 + event_y_core_shower**2)
124
- core_distances_triggered = core_distances_all[shower_id_triggered_masked]
125
- core_bins = np.linspace(
126
- core_distances_triggered.min(), core_distances_triggered.max(), 1000
63
+ @property
64
+ def energy_bins(self):
65
+ """Return bins for the energy histogram."""
66
+ return np.logspace(
67
+ np.log10(self.event_data.simulated_energy.min()),
68
+ np.log10(self.event_data.simulated_energy.max()),
69
+ 1000,
127
70
  )
128
71
 
129
- return core_distances_triggered, triggered_energies, core_bins, energy_bins
130
-
131
72
  def compute_lower_energy_limit(self, loss_fraction):
132
73
  """
133
74
  Compute the lower energy limit in TeV based on the event loss fraction.
@@ -142,13 +83,19 @@ class LimitCalculator:
142
83
  astropy.units.Quantity
143
84
  Lower energy limit.
144
85
  """
145
- _, triggered_energies, _, energy_bins = self._prepare_data_for_limits()
86
+ hist, _ = np.histogram(self.event_data.simulated_energy, bins=self.energy_bins)
87
+ return (
88
+ self._compute_limits(hist, self.energy_bins, loss_fraction, limit_type="lower") * u.TeV
89
+ )
146
90
 
147
- hist, _ = np.histogram(triggered_energies, bins=energy_bins)
148
- lower_bin_edge_value = self._compute_limits(
149
- hist, energy_bins, loss_fraction, limit_type="lower"
91
+ @property
92
+ def core_distance_bins(self):
93
+ """Return bins for the core distance histogram."""
94
+ return np.linspace(
95
+ self.event_data.core_distance_shower.min(),
96
+ self.event_data.core_distance_shower.max(),
97
+ 1000,
150
98
  )
151
- return lower_bin_edge_value * u.TeV
152
99
 
153
100
  def compute_upper_radial_distance(self, loss_fraction):
154
101
  """
@@ -164,18 +111,29 @@ class LimitCalculator:
164
111
  astropy.units.Quantity
165
112
  Upper radial distance in m.
166
113
  """
167
- core_distances_triggered, _, core_bins, _ = self._prepare_data_for_limits()
114
+ hist, _ = np.histogram(self.event_data.core_distance_shower, bins=self.core_distance_bins)
115
+ return (
116
+ self._compute_limits(hist, self.core_distance_bins, loss_fraction, limit_type="upper")
117
+ * u.m
118
+ )
168
119
 
169
- hist, _ = np.histogram(core_distances_triggered, bins=core_bins)
170
- upper_bin_edge_value = self._compute_limits(
171
- hist, core_bins, loss_fraction, limit_type="upper"
120
+ @property
121
+ def view_cone_bins(self):
122
+ """Return bins for the viewcone histogram."""
123
+ return np.linspace(
124
+ self.triggered_data.angular_distance.min(),
125
+ self.triggered_data.angular_distance.max(),
126
+ 1000,
172
127
  )
173
- return upper_bin_edge_value * u.m
174
128
 
175
129
  def compute_viewcone(self, loss_fraction):
176
130
  """
177
131
  Compute the viewcone based on the event loss fraction.
178
132
 
133
+ The shower IDs of triggered events are used to create a mask for the
134
+ azimuth and altitude of the triggered events. A mapping is created
135
+ between the triggered events and the simulated events using the shower IDs.
136
+
179
137
  Parameters
180
138
  ----------
181
139
  loss_fraction : float
@@ -186,75 +144,185 @@ class LimitCalculator:
186
144
  astropy.units.Quantity
187
145
  Viewcone radius in degrees.
188
146
  """
189
- # already in radians
190
- azimuth_diff = self.array_azimuth - self.shower_sim_azimuth # * (np.pi / 180.0)
191
- sim_altitude_rad = self.shower_sim_altitude # * (np.pi / 180.0)
192
- array_altitude_rad = self.array_altitude # * (np.pi / 180.0)
193
- x_1 = np.cos(azimuth_diff) * np.cos(sim_altitude_rad)
194
- y_1 = np.sin(azimuth_diff) * np.cos(sim_altitude_rad)
195
- z_1 = np.sin(sim_altitude_rad)
196
- x_2 = x_1 * np.sin(array_altitude_rad) - z_1 * np.cos(array_altitude_rad)
197
- y_2 = y_1
198
- z_2 = x_1 * np.cos(array_altitude_rad) + z_1 * np.sin(array_altitude_rad)
199
- off_angles = np.arctan2(np.sqrt(x_2**2 + y_2**2), z_2) * (180.0 / np.pi)
200
- angle_bins = np.linspace(off_angles.min(), off_angles.max(), 400)
201
- hist, _ = np.histogram(off_angles, bins=angle_bins)
202
-
203
- upper_bin_edge_value = self._compute_limits(
204
- hist, angle_bins, loss_fraction, limit_type="upper"
147
+ hist, _ = np.histogram(self.triggered_data.angular_distance, bins=self.view_cone_bins)
148
+ return (
149
+ self._compute_limits(hist, self.view_cone_bins, loss_fraction, limit_type="upper")
150
+ * u.deg
205
151
  )
206
- return upper_bin_edge_value * u.deg
207
152
 
208
- def _transform_to_shower_coordinates(self):
153
+ def plot_data(self, lower_energy_limit, upper_radial_distance, viewcone, output_path=None):
209
154
  """
210
- Transform core positions from ground coordinates to shower coordinates.
155
+ Plot the core distances and energies of triggered events.
156
+
157
+ Parameters
158
+ ----------
159
+ lower_energy_limit: astropy.units.Quantity
160
+ Lower energy limit to display on plots.
161
+ upper_radial_distance: astropy.units.Quantity
162
+ Upper radial distance limit to display on plots.
163
+ viewcone: astropy.units.Quantity
164
+ Viewcone radius to display on plots.
165
+ output_path: Path or str, optional
166
+ Directory to save plots. If None, plots will be displayed.
167
+ """
168
+ event_counts = "Event Count"
169
+ plots = {
170
+ "core_vs_energy": {
171
+ "x_data": self.event_data.core_distance_shower,
172
+ "y_data": self.event_data.simulated_energy,
173
+ "bins": [self.core_distance_bins, self.energy_bins],
174
+ "plot_type": "histogram2d",
175
+ "plot_params": {"norm": "log", "cmap": "viridis"},
176
+ "labels": {
177
+ "x": "Core Distance [m]",
178
+ "y": "Energy [TeV]",
179
+ "title": "Triggered events: core distance vs energy",
180
+ },
181
+ "scales": {"y": "log"},
182
+ "colorbar_label": event_counts,
183
+ "filename": "core_vs_energy_distribution.png",
184
+ },
185
+ "energy_distribution": {
186
+ "x_data": self.event_data.simulated_energy,
187
+ "bins": np.logspace(-3, 0.0, 100),
188
+ "plot_type": "histogram",
189
+ "plot_params": {"histtype": "step", "color": "k", "lw": 2},
190
+ "labels": {
191
+ "x": "Energy [TeV]",
192
+ "y": event_counts,
193
+ "title": "Triggered events: energy distribution",
194
+ },
195
+ "scales": {"x": "log", "y": "log"},
196
+ "lines": {"x": lower_energy_limit.value},
197
+ "filename": "energy_distribution.png",
198
+ },
199
+ "core_distance": {
200
+ "x_data": self.event_data.core_distance_shower,
201
+ "bins": self.core_distance_bins,
202
+ "plot_type": "histogram",
203
+ "plot_params": {"histtype": "step", "color": "k", "lw": 2},
204
+ "labels": {
205
+ "x": "Core Distance [m]",
206
+ "y": event_counts,
207
+ "title": "Triggered events: core distance distribution",
208
+ },
209
+ "lines": {"x": upper_radial_distance.value},
210
+ "filename": "core_distance_distribution.png",
211
+ },
212
+ "core_xy": {
213
+ "x_data": self.event_data.x_core_shower,
214
+ "y_data": self.event_data.y_core_shower,
215
+ "bins": 100,
216
+ "plot_type": "histogram2d",
217
+ "plot_params": {"norm": "log", "cmap": "viridis"},
218
+ "labels": {
219
+ "x": "Core X [m]",
220
+ "y": "Core Y [m]",
221
+ "title": "Triggered events: core x vs core y",
222
+ },
223
+ "colorbar_label": event_counts,
224
+ "lines": {"x": upper_radial_distance.value, "y": upper_radial_distance.value},
225
+ "filename": "core_xy_distribution.png",
226
+ },
227
+ "view-cone": {
228
+ "x_data": self.triggered_data.angular_distance,
229
+ "bins": self.view_cone_bins,
230
+ "plot_type": "histogram",
231
+ "plot_params": {"histtype": "step", "color": "k", "lw": 2},
232
+ "labels": {
233
+ "x": "Distance to pointing direction [deg]",
234
+ "y": event_counts,
235
+ "title": "Triggered events: viewcone distribution",
236
+ },
237
+ "lines": {"x": viewcone.value},
238
+ "filename": "viewcone_distribution.png",
239
+ },
240
+ }
241
+
242
+ for _, plot_args in plots.items():
243
+ filename = plot_args.pop("filename")
244
+ output_file = output_path / filename if output_path else None
245
+ self._create_plot(**plot_args, output_file=output_file)
246
+
247
+ def _create_plot(
248
+ self,
249
+ x_data,
250
+ y_data=None,
251
+ bins=None,
252
+ plot_type="histogram",
253
+ plot_params=None,
254
+ labels=None,
255
+ scales=None,
256
+ colorbar_label=None,
257
+ output_file=None,
258
+ lines=None,
259
+ ):
260
+ """
261
+ Create and save a plot with the given parameters.
262
+
263
+ Parameters
264
+ ----------
265
+ x_data : array-like
266
+ Data for the x-axis or primary data for histograms.
267
+ y_data : array-like, optional
268
+ Data for the y-axis in scatter or 2D histograms.
269
+ bins : int, array-like, or list, optional
270
+ Bins specification for histograms.
271
+ plot_type : str, optional
272
+ Type of plot: 'histogram', 'histogram2d', or 'scatter'.
273
+ plot_params : dict, optional
274
+ Additional parameters to pass to the plotting function.
275
+ labels : dict, optional
276
+ Dictionary containing 'x', 'y', and 'title' labels.
277
+ scales : dict, optional
278
+ Dictionary containing 'x' and 'y' scale types ('log' or 'linear').
279
+ colorbar_label : str, optional
280
+ Label for the colorbar in 2D histograms.
281
+ output_file : Path, optional
282
+ File path to save the plot. If not provided, the plot will be displayed.
283
+ lines : dict, optional
284
+ Dictionary containing 'x' and 'y' values for reference lines.
211
285
 
212
286
  Returns
213
287
  -------
214
- tuple
215
- Core positions in shower coordinates (x, y).
288
+ matplotlib.figure.Figure
289
+ The created figure object.
216
290
  """
217
- pointing_az = self.shower_sim_azimuth * u.rad
218
- pointing_alt = self.shower_sim_altitude * u.rad
219
-
220
- pointing = AltAz(az=pointing_az, alt=pointing_alt)
221
- ground = GroundFrame(x=self.event_x_core * u.m, y=self.event_y_core * u.m, z=0 * u.m)
222
- shower_frame = ground.transform_to(TiltedGroundFrame(pointing_direction=pointing))
223
-
224
- return shower_frame.x.value, shower_frame.y.value
225
-
226
- def plot_data(self):
227
- """Plot the core distances and energies of triggered events."""
228
- shower_id_triggered_masked = self.shower_id_triggered
229
- if self.telescope_list is not None:
230
- mask = np.array(
231
- [
232
- all(tel in event for tel in self.telescope_list)
233
- for event in self.trigger_telescope_list_list
234
- ]
235
- )
236
- shower_id_triggered_masked = self.shower_id_triggered[mask]
237
-
238
- core_distances_all = np.sqrt(self.event_x_core**2 + self.event_y_core**2)
239
- core_distances_triggered = core_distances_all[shower_id_triggered_masked]
240
- triggered_energies = self.simulated[shower_id_triggered_masked]
241
-
242
- core_bins = np.linspace(core_distances_triggered.min(), core_distances_triggered.max(), 400)
243
- energy_bins = np.logspace(
244
- np.log10(triggered_energies.min()), np.log10(triggered_energies.max()), 400
245
- )
246
- plt.figure(figsize=(8, 6))
247
- plt.hist2d(
248
- core_distances_triggered,
249
- triggered_energies,
250
- bins=[core_bins, energy_bins],
251
- norm="log",
252
- cmap="viridis",
253
- )
254
-
255
- plt.colorbar(label="Event Count")
256
- plt.xlabel("Core Distance [m]")
257
- plt.ylabel("Energy [TeV]")
258
- plt.yscale("log")
259
- plt.title("2D Histogram of Triggered Core Distance vs Energy")
260
- plt.show()
291
+ fig = plt.figure(figsize=(8, 6))
292
+ plot_params = plot_params or {}
293
+ labels = labels or {}
294
+ scales = scales or {}
295
+ lines = lines or {}
296
+
297
+ if plot_type == "histogram":
298
+ plt.hist(x_data, bins=bins, **plot_params)
299
+ elif plot_type == "histogram2d":
300
+ plt.hist2d(x_data, y_data, bins=bins, **plot_params)
301
+ if colorbar_label:
302
+ plt.colorbar(label=colorbar_label)
303
+ elif plot_type == "scatter":
304
+ plt.scatter(x_data, y_data, **plot_params)
305
+
306
+ if "x" in lines:
307
+ plt.axvline(lines["x"], color="r", linestyle="--")
308
+ if "y" in lines:
309
+ plt.axhline(lines["y"], color="r", linestyle="--")
310
+
311
+ plt.xlabel(labels.get("x", ""))
312
+ plt.ylabel(labels.get("y", ""))
313
+ plt.title(labels.get("title", ""))
314
+
315
+ if "x" in scales:
316
+ plt.xscale(scales["x"])
317
+ if "y" in scales:
318
+ plt.yscale(scales["y"])
319
+
320
+ if output_file:
321
+ self._logger.info(f"Saving plot to {output_file}")
322
+ plt.savefig(output_file, dpi=300, bbox_inches="tight")
323
+ plt.close()
324
+ else:
325
+ plt.tight_layout()
326
+ plt.show()
327
+
328
+ return fig
@@ -68,9 +68,9 @@ class EventScaler:
68
68
  The scaling factor.
69
69
  """
70
70
  metric_results = self.evaluator.calculate_metrics()
71
- uncertainty_effective_area = metric_results.get("uncertainty_effective_area", {})
71
+ uncertainty_effective_area = metric_results.get("uncertainty_effective_area")
72
72
  current_max_error = uncertainty_effective_area.get("max_error")
73
- target_max_error = self.metrics.get("uncertainty_effective_area", {}).get("target_error")[
73
+ target_max_error = self.metrics.get("uncertainty_effective_area").get("target_error")[
74
74
  "value"
75
75
  ]
76
76