gammasimtools 0.25.0__py3-none-any.whl → 0.27.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 (138) hide show
  1. {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/METADATA +6 -1
  2. {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/RECORD +135 -130
  3. {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/entry_points.txt +3 -2
  5. {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/licenses/LICENSE +1 -1
  6. simtools/_version.py +2 -2
  7. simtools/application_control.py +35 -7
  8. simtools/applications/convert_geo_coordinates_of_array_elements.py +3 -3
  9. simtools/applications/db_add_file_to_db.py +1 -1
  10. simtools/applications/db_add_simulation_model_from_repository_to_db.py +1 -1
  11. simtools/applications/db_add_value_from_json_to_db.py +1 -1
  12. simtools/applications/db_generate_compound_indexes.py +1 -1
  13. simtools/applications/db_get_array_layouts_from_db.py +3 -7
  14. simtools/applications/db_get_file_from_db.py +1 -1
  15. simtools/applications/db_get_parameter_from_db.py +1 -1
  16. simtools/applications/db_inspect_databases.py +1 -1
  17. simtools/applications/db_upload_model_repository.py +1 -1
  18. simtools/applications/derive_ctao_array_layouts.py +1 -2
  19. simtools/applications/{calculate_incident_angles.py → derive_incident_angle.py} +16 -18
  20. simtools/applications/derive_mirror_rnda.py +112 -180
  21. simtools/applications/derive_psf_parameters.py +0 -1
  22. simtools/applications/derive_pulse_shape_parameters.py +0 -1
  23. simtools/applications/derive_trigger_rates.py +1 -1
  24. simtools/applications/docs_produce_array_element_report.py +2 -8
  25. simtools/applications/docs_produce_calibration_reports.py +1 -3
  26. simtools/applications/docs_produce_model_parameter_reports.py +0 -2
  27. simtools/applications/docs_produce_simulation_configuration_report.py +1 -3
  28. simtools/applications/generate_array_config.py +0 -1
  29. simtools/applications/generate_corsika_histograms.py +79 -229
  30. simtools/applications/generate_regular_arrays.py +76 -69
  31. simtools/applications/generate_simtel_event_data.py +2 -2
  32. simtools/applications/maintain_simulation_model_add_production.py +2 -2
  33. simtools/applications/maintain_simulation_model_write_array_element_positions.py +87 -0
  34. simtools/applications/plot_array_layout.py +5 -111
  35. simtools/applications/plot_simulated_event_distributions.py +57 -0
  36. simtools/applications/plot_tabular_data.py +0 -1
  37. simtools/applications/plot_tabular_data_for_model_parameter.py +1 -6
  38. simtools/applications/production_derive_corsika_limits.py +1 -1
  39. simtools/applications/production_generate_grid.py +0 -1
  40. simtools/applications/run_application.py +1 -1
  41. simtools/applications/simulate_flasher.py +3 -15
  42. simtools/applications/simulate_illuminator.py +2 -11
  43. simtools/applications/simulate_pedestals.py +1 -5
  44. simtools/applications/simulate_prod.py +8 -11
  45. simtools/applications/simulate_prod_htcondor_generator.py +1 -1
  46. simtools/applications/submit_array_layouts.py +2 -4
  47. simtools/applications/submit_data_from_external.py +2 -1
  48. simtools/applications/submit_model_parameter_from_external.py +1 -3
  49. simtools/applications/validate_camera_efficiency.py +28 -28
  50. simtools/applications/validate_camera_fov.py +0 -1
  51. simtools/applications/validate_cumulative_psf.py +1 -5
  52. simtools/applications/validate_optics.py +2 -14
  53. simtools/atmosphere.py +83 -0
  54. simtools/camera/camera_efficiency.py +171 -53
  55. simtools/camera/single_photon_electron_spectrum.py +8 -7
  56. simtools/configuration/commandline_parser.py +82 -11
  57. simtools/configuration/configurator.py +6 -11
  58. simtools/constants.py +5 -0
  59. simtools/corsika/corsika_config.py +100 -202
  60. simtools/corsika/corsika_histograms.py +561 -1708
  61. simtools/corsika/primary_particle.py +1 -1
  62. simtools/data_model/metadata_collector.py +5 -2
  63. simtools/data_model/metadata_model.py +0 -4
  64. simtools/data_model/model_data_writer.py +59 -64
  65. simtools/data_model/schema.py +2 -0
  66. simtools/data_model/validate_data.py +1 -3
  67. simtools/db/db_handler.py +23 -10
  68. simtools/db/mongo_db.py +2 -2
  69. simtools/dependencies.py +81 -38
  70. simtools/io/ascii_handler.py +55 -5
  71. simtools/io/io_handler.py +23 -12
  72. simtools/io/table_handler.py +1 -1
  73. simtools/job_execution/job_manager.py +154 -79
  74. simtools/job_execution/process_pool.py +137 -0
  75. simtools/layout/array_layout.py +4 -13
  76. simtools/layout/array_layout_utils.py +348 -57
  77. simtools/model/array_model.py +23 -63
  78. simtools/model/calibration_model.py +4 -8
  79. simtools/model/legacy_model_parameter.py +134 -0
  80. simtools/model/model_parameter.py +147 -86
  81. simtools/model/model_utils.py +40 -6
  82. simtools/model/site_model.py +4 -8
  83. simtools/model/telescope_model.py +10 -16
  84. simtools/production_configuration/derive_corsika_limits.py +6 -11
  85. simtools/production_configuration/interpolation_handler.py +16 -16
  86. simtools/ray_tracing/incident_angles.py +92 -17
  87. simtools/ray_tracing/mirror_panel_psf.py +338 -222
  88. simtools/ray_tracing/psf_analysis.py +62 -48
  89. simtools/ray_tracing/psf_parameter_optimisation.py +3 -3
  90. simtools/ray_tracing/ray_tracing.py +43 -25
  91. simtools/reporting/docs_auto_report_generator.py +8 -13
  92. simtools/reporting/docs_read_parameters.py +2 -8
  93. simtools/runners/corsika_runner.py +52 -195
  94. simtools/runners/corsika_simtel_runner.py +77 -108
  95. simtools/runners/runner_services.py +214 -213
  96. simtools/runners/simtel_runner.py +27 -160
  97. simtools/runners/simtools_runner.py +11 -73
  98. simtools/schemas/application_workflow.metaschema.yml +8 -0
  99. simtools/settings.py +173 -0
  100. simtools/{io/eventio_handler.py → sim_events/file_info.py} +3 -3
  101. simtools/{simtel/simtel_io_event_histograms.py → sim_events/histograms.py} +25 -15
  102. simtools/{simtel/simtel_io_event_reader.py → sim_events/reader.py} +20 -17
  103. simtools/{simtel/simtel_io_event_writer.py → sim_events/writer.py} +84 -25
  104. simtools/simtel/pulse_shapes.py +7 -2
  105. simtools/simtel/simtel_config_writer.py +79 -91
  106. simtools/simtel/simtel_seeds.py +184 -0
  107. simtools/simtel/simtel_table_reader.py +6 -4
  108. simtools/simtel/simulator_array.py +114 -109
  109. simtools/simtel/simulator_camera_efficiency.py +68 -46
  110. simtools/simtel/simulator_light_emission.py +164 -132
  111. simtools/simtel/simulator_ray_tracing.py +80 -71
  112. simtools/simulator.py +137 -355
  113. simtools/telescope_trigger_rates.py +3 -4
  114. simtools/testing/assertions.py +84 -33
  115. simtools/testing/configuration.py +1 -2
  116. simtools/testing/helpers.py +2 -3
  117. simtools/testing/log_inspector.py +1 -0
  118. simtools/testing/sim_telarray_metadata.py +14 -12
  119. simtools/testing/validate_output.py +121 -42
  120. simtools/utils/general.py +43 -17
  121. simtools/utils/geometry.py +0 -77
  122. simtools/utils/names.py +5 -5
  123. simtools/utils/random.py +36 -0
  124. simtools/visualization/legend_handlers.py +7 -6
  125. simtools/visualization/plot_array_layout.py +91 -16
  126. simtools/visualization/plot_corsika_histograms.py +145 -605
  127. simtools/visualization/plot_incident_angles.py +48 -1
  128. simtools/visualization/plot_mirrors.py +1 -4
  129. simtools/visualization/plot_pixels.py +2 -4
  130. simtools/visualization/plot_psf.py +160 -19
  131. simtools/visualization/plot_simtel_event_histograms.py +4 -4
  132. simtools/visualization/plot_simtel_events.py +6 -11
  133. simtools/visualization/plot_tables.py +8 -19
  134. simtools/visualization/visualize.py +22 -2
  135. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +0 -160
  136. simtools/applications/print_version.py +0 -53
  137. simtools/io/hdf5_handler.py +0 -139
  138. {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/top_level.txt +0 -0
@@ -214,17 +214,15 @@ class InterpolationHandler:
214
214
  np.ndarray
215
215
  Reduced production grid points.
216
216
  """
217
- production_grid_points = []
218
-
219
- for point in self.grid_points_production:
220
- production_grid_points.append(
221
- [
222
- point["azimuth"]["value"],
223
- point["zenith_angle"]["value"],
224
- point["nsb"]["value"],
225
- point["offset"]["value"],
226
- ]
227
- )
217
+ production_grid_points = [
218
+ [
219
+ point["azimuth"]["value"],
220
+ point["zenith_angle"]["value"],
221
+ point["nsb"]["value"],
222
+ point["offset"]["value"],
223
+ ]
224
+ for point in self.grid_points_production
225
+ ]
228
226
 
229
227
  production_grid_points = np.array(production_grid_points)
230
228
 
@@ -280,11 +278,13 @@ class InterpolationHandler:
280
278
  reduced_production_grid_points = self._prepare_production_grid_points()
281
279
  energy_grid = self.energy_grids[0] if self.energy_grids else []
282
280
 
283
- energy_query_grid = []
284
- for energy in energy_grid:
285
- for grid_point in reduced_production_grid_points:
286
- energy_query_grid.append(np.hstack([energy.to(u.TeV).value, grid_point]))
287
-
281
+ energy_query_grid = [
282
+ [
283
+ np.hstack([energy.to(u.TeV).value, grid_point])
284
+ for energy in energy_grid
285
+ for grid_point in reduced_production_grid_points
286
+ ]
287
+ ]
288
288
  energy_query_grid = np.array(energy_query_grid)
289
289
 
290
290
  self._logger.debug(f"Grid points with energy shape: {grid_points_energy.shape}")
@@ -9,13 +9,16 @@ Angle of incidence on to secondary mirror [deg] (if available).
9
9
  import logging
10
10
  import math
11
11
  import re
12
- import subprocess
13
12
  from pathlib import Path
14
13
 
15
14
  import astropy.units as u
16
- from astropy.table import QTable
15
+ import numpy as np
16
+ from astropy.table import QTable, vstack
17
17
 
18
+ from simtools import settings
18
19
  from simtools.data_model.metadata_collector import MetadataCollector
20
+ from simtools.data_model.model_data_writer import ModelDataWriter
21
+ from simtools.job_execution import job_manager
19
22
  from simtools.model.model_utils import initialize_simulation_models
20
23
 
21
24
 
@@ -24,10 +27,6 @@ class IncidentAnglesCalculator:
24
27
 
25
28
  Parameters
26
29
  ----------
27
- simtel_path : str or pathlib.Path
28
- Path to the sim_telarray installation directory (containing ``sim_telarray/bin``).
29
- db_config : dict
30
- Database configuration passed to ``initialize_simulation_models``.
31
30
  config_data : dict
32
31
  Simulation configuration (e.g. ``site``, ``telescope``, ``model_version``,
33
32
  ``off_axis_angle``, ``source_distance``, ``number_of_photons``).
@@ -48,15 +47,12 @@ class IncidentAnglesCalculator:
48
47
 
49
48
  def __init__(
50
49
  self,
51
- simtel_path,
52
- db_config,
53
50
  config_data,
54
51
  output_dir,
55
52
  label=None,
56
53
  ):
57
54
  self.logger = logging.getLogger(__name__)
58
55
 
59
- self._simtel_path = Path(simtel_path)
60
56
  self.config_data = config_data
61
57
  self.output_dir = Path(output_dir)
62
58
  self.label = label or f"incident_angles_{config_data['telescope']}"
@@ -82,7 +78,6 @@ class IncidentAnglesCalculator:
82
78
  )
83
79
  self.telescope_model, self.site_model, _ = initialize_simulation_models(
84
80
  label=self.label,
85
- db_config=db_config,
86
81
  site=config_data["site"],
87
82
  telescope_name=config_data["telescope"],
88
83
  model_version=config_data["model_version"],
@@ -216,8 +211,6 @@ class IncidentAnglesCalculator:
216
211
  Path to the generated shell script.
217
212
  """
218
213
  script_path = self.scripts_dir / f"run_incident_angles_{self._label_suffix()}.sh"
219
- simtel_bin = self._simtel_path / "sim_telarray/bin/sim_telarray_debug_trace"
220
- corsika_dummy = self._simtel_path / "sim_telarray/run9991.corsika.gz"
221
214
 
222
215
  theta = self.ZENITH_ANGLE_DEG
223
216
  off = float(self.config_data["off_axis_angle"].to_value(u.deg))
@@ -258,7 +251,10 @@ class IncidentAnglesCalculator:
258
251
  cfg("camera_filter", "none"),
259
252
  ]
260
253
 
261
- command = f"{simtel_bin} {' '.join(opts)} {corsika_dummy}"
254
+ command = (
255
+ f"{settings.config.sim_telarray_exe_debug_trace} {' '.join(opts)} "
256
+ f"{settings.config.corsika_dummy_file}"
257
+ )
262
258
  with script_path.open("w", encoding="utf-8") as sh:
263
259
  sh.write("#!/usr/bin/env bash\n\n")
264
260
  sh.write("set -e\nset -o pipefail\n\n")
@@ -279,8 +275,8 @@ class IncidentAnglesCalculator:
279
275
  """
280
276
  self.logger.info("Executing %s (logging to %s)", script_path, log_file)
281
277
  try:
282
- subprocess.check_call([str(script_path)])
283
- except subprocess.CalledProcessError as exc:
278
+ job_manager.submit(script_path)
279
+ except job_manager.JobExecutionError as exc:
284
280
  raise RuntimeError(f"Incident angles run failed, see log: {log_file}") from exc
285
281
 
286
282
  def _compute_incidence_angles_from_imaging_list(self, photons_file):
@@ -289,7 +285,7 @@ class IncidentAnglesCalculator:
289
285
  Column positions may differ between telescope types and sim_telarray versions.
290
286
  Header lines (``# Column N: ...``) are parsed to find indices; otherwise
291
287
  legacy positions (1-based) are used: focal=26, primary=32, secondary=36,
292
- primary X/Y = 29/30, secondary X/Y = 33/34.
288
+ primary X/Y = 29/30, secondary X/Y=33/34.
293
289
 
294
290
  Parameters
295
291
  ----------
@@ -698,9 +694,88 @@ class IncidentAnglesCalculator:
698
694
  self.logger.warning("No results to save")
699
695
  return
700
696
  output_file = self.results_dir / f"incident_angles_{self._label_suffix()}.ecsv"
701
- self.results.write(output_file, format="ascii.ecsv", overwrite=True)
697
+
698
+ data = self.results["angle_incidence_focal"].to(u.deg).value
699
+ bin_centers, hist = self._calculate_histogram(data, bins=1000)
700
+
701
+ output_table = QTable()
702
+ output_table["Incidence angle"] = bin_centers * u.deg
703
+ output_table["Fraction"] = hist
704
+
705
+ output_table.write(output_file, format="ascii.ecsv", overwrite=True)
702
706
 
703
707
  MetadataCollector.dump(
704
708
  args_dict=self.config_data,
705
709
  output_file=output_file.with_suffix(".yml"),
706
710
  )
711
+
712
+ def save_model_parameters(self, results_by_offset):
713
+ """
714
+ Write model parameters dictionary (json) + astropy table with incident angles.
715
+
716
+ Parameters
717
+ ----------
718
+ results_by_offset : dict
719
+ Dictionary with results for each offset.
720
+ """
721
+ # Combine results from all offsets
722
+ tables = [res for res in results_by_offset.values() if res is not None and len(res) > 0]
723
+ if not tables:
724
+ self.logger.warning("No results to write model parameters.")
725
+ return
726
+
727
+ combined_table = vstack(tables)
728
+
729
+ parameter_mapping = {
730
+ "camera_filter_incidence_angle": "angle_incidence_focal",
731
+ "primary_mirror_incidence_angle": "angle_incidence_primary",
732
+ "secondary_mirror_incidence_angle": "angle_incidence_secondary",
733
+ }
734
+
735
+ for param_name, col_name in parameter_mapping.items():
736
+ if col_name not in combined_table.colnames:
737
+ continue
738
+
739
+ data = combined_table[col_name].to(u.deg).value
740
+ # Create histogram
741
+ bin_centers, hist = self._calculate_histogram(data, bins=100)
742
+
743
+ table = QTable()
744
+ table["Incidence angle"] = bin_centers * u.deg
745
+ table["Fraction"] = hist
746
+
747
+ writer = ModelDataWriter(output_file=self.output_dir / f"{param_name}.ecsv")
748
+ writer.write(
749
+ product_data=table,
750
+ metadata=MetadataCollector(args_dict=self.config_data),
751
+ )
752
+
753
+ ModelDataWriter.dump_model_parameter(
754
+ parameter_name=param_name,
755
+ value=f"{param_name}.ecsv",
756
+ instrument=self.config_data["telescope"],
757
+ parameter_version=self.config_data["model_version"],
758
+ output_file=f"{param_name}.json",
759
+ output_path=self.output_dir,
760
+ metadata_input_dict=self.config_data,
761
+ )
762
+
763
+ def _calculate_histogram(self, data, bins=100):
764
+ """
765
+ Calculate normalized histogram (density).
766
+
767
+ Parameters
768
+ ----------
769
+ data : numpy.ndarray
770
+ Data to calculate histogram for.
771
+ bins : int
772
+ Number of bins.
773
+
774
+ Returns
775
+ -------
776
+ tuple
777
+ Bin centers and histogram values (density).
778
+ """
779
+ hist, bin_edges = np.histogram(data, bins=bins, density=True)
780
+ bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2
781
+ return bin_centers, hist