gammasimtools 0.26.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 (70) hide show
  1. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.0.dist-info}/METADATA +5 -1
  2. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.0.dist-info}/RECORD +70 -66
  3. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.0.dist-info}/entry_points.txt +1 -1
  5. simtools/_version.py +2 -2
  6. simtools/applications/convert_geo_coordinates_of_array_elements.py +2 -1
  7. simtools/applications/db_get_array_layouts_from_db.py +1 -1
  8. simtools/applications/{calculate_incident_angles.py → derive_incident_angle.py} +16 -16
  9. simtools/applications/derive_mirror_rnda.py +111 -177
  10. simtools/applications/generate_corsika_histograms.py +38 -1
  11. simtools/applications/generate_regular_arrays.py +73 -36
  12. simtools/applications/simulate_flasher.py +3 -13
  13. simtools/applications/simulate_illuminator.py +2 -10
  14. simtools/applications/simulate_pedestals.py +1 -1
  15. simtools/applications/simulate_prod.py +8 -7
  16. simtools/applications/submit_data_from_external.py +2 -1
  17. simtools/applications/validate_camera_efficiency.py +28 -27
  18. simtools/applications/validate_cumulative_psf.py +1 -3
  19. simtools/applications/validate_optics.py +2 -1
  20. simtools/atmosphere.py +83 -0
  21. simtools/camera/camera_efficiency.py +171 -48
  22. simtools/camera/single_photon_electron_spectrum.py +6 -6
  23. simtools/configuration/commandline_parser.py +47 -9
  24. simtools/constants.py +5 -0
  25. simtools/corsika/corsika_config.py +88 -185
  26. simtools/corsika/corsika_histograms.py +246 -69
  27. simtools/data_model/model_data_writer.py +46 -49
  28. simtools/data_model/schema.py +2 -0
  29. simtools/db/db_handler.py +4 -2
  30. simtools/db/mongo_db.py +2 -2
  31. simtools/io/ascii_handler.py +51 -3
  32. simtools/io/io_handler.py +23 -12
  33. simtools/job_execution/job_manager.py +154 -79
  34. simtools/job_execution/process_pool.py +137 -0
  35. simtools/layout/array_layout.py +0 -1
  36. simtools/layout/array_layout_utils.py +143 -21
  37. simtools/model/array_model.py +22 -50
  38. simtools/model/calibration_model.py +4 -4
  39. simtools/model/model_parameter.py +123 -73
  40. simtools/model/model_utils.py +40 -1
  41. simtools/model/site_model.py +4 -4
  42. simtools/model/telescope_model.py +4 -5
  43. simtools/ray_tracing/incident_angles.py +87 -6
  44. simtools/ray_tracing/mirror_panel_psf.py +337 -217
  45. simtools/ray_tracing/psf_analysis.py +57 -42
  46. simtools/ray_tracing/psf_parameter_optimisation.py +3 -2
  47. simtools/ray_tracing/ray_tracing.py +37 -10
  48. simtools/runners/corsika_runner.py +52 -191
  49. simtools/runners/corsika_simtel_runner.py +74 -100
  50. simtools/runners/runner_services.py +214 -213
  51. simtools/runners/simtel_runner.py +27 -155
  52. simtools/runners/simtools_runner.py +9 -69
  53. simtools/schemas/application_workflow.metaschema.yml +8 -0
  54. simtools/settings.py +19 -0
  55. simtools/simtel/simtel_config_writer.py +0 -55
  56. simtools/simtel/simtel_seeds.py +184 -0
  57. simtools/simtel/simulator_array.py +115 -103
  58. simtools/simtel/simulator_camera_efficiency.py +66 -42
  59. simtools/simtel/simulator_light_emission.py +110 -123
  60. simtools/simtel/simulator_ray_tracing.py +78 -63
  61. simtools/simulator.py +135 -346
  62. simtools/testing/sim_telarray_metadata.py +13 -11
  63. simtools/testing/validate_output.py +87 -19
  64. simtools/utils/general.py +6 -17
  65. simtools/utils/random.py +36 -0
  66. simtools/visualization/plot_corsika_histograms.py +2 -0
  67. simtools/visualization/plot_incident_angles.py +48 -1
  68. simtools/visualization/plot_psf.py +160 -18
  69. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.0.dist-info}/licenses/LICENSE +0 -0
  70. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.0.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,9 @@
3
3
 
4
4
  import math
5
5
 
6
+ from simtools import settings
7
+ from simtools.data_model import schema
8
+ from simtools.io import ascii_handler
6
9
  from simtools.model.calibration_model import CalibrationModel
7
10
  from simtools.model.site_model import SiteModel
8
11
  from simtools.model.telescope_model import TelescopeModel
@@ -10,7 +13,11 @@ from simtools.utils import names
10
13
 
11
14
 
12
15
  def initialize_simulation_models(
13
- label, model_version, site, telescope_name, calibration_device_name=None
16
+ label,
17
+ model_version,
18
+ site,
19
+ telescope_name,
20
+ calibration_device_name=None,
14
21
  ):
15
22
  """
16
23
  Initialize simulation models for a single telescope, site, and calibration device model.
@@ -33,16 +40,20 @@ def initialize_simulation_models(
33
40
  Tuple
34
41
  Tuple containing the telescope site, (optional) calibration device model.
35
42
  """
43
+ overwrite_model_parameter_dict = read_overwrite_model_parameter_dict()
44
+
36
45
  tel_model = TelescopeModel(
37
46
  site=site,
38
47
  telescope_name=telescope_name,
39
48
  model_version=model_version,
40
49
  label=label,
50
+ overwrite_model_parameter_dict=overwrite_model_parameter_dict,
41
51
  )
42
52
  site_model = SiteModel(
43
53
  site=site,
44
54
  model_version=model_version,
45
55
  label=label,
56
+ overwrite_model_parameter_dict=overwrite_model_parameter_dict,
46
57
  )
47
58
  if calibration_device_name is not None:
48
59
  calibration_model = CalibrationModel(
@@ -50,6 +61,7 @@ def initialize_simulation_models(
50
61
  calibration_device_model_name=calibration_device_name,
51
62
  model_version=model_version,
52
63
  label=label,
64
+ overwrite_model_parameter_dict=overwrite_model_parameter_dict,
53
65
  )
54
66
  else:
55
67
  calibration_model = None
@@ -58,6 +70,33 @@ def initialize_simulation_models(
58
70
  return tel_model, site_model, calibration_model
59
71
 
60
72
 
73
+ def read_overwrite_model_parameter_dict(overwrite_model_parameters=None):
74
+ """
75
+ Read overwrite model parameters dictionary from file.
76
+
77
+ Parameters
78
+ ----------
79
+ overwrite_model_parameters: str, optional
80
+ File name with overwrite model parameters.
81
+
82
+ Returns
83
+ -------
84
+ dict
85
+ Dictionary with model parameters to overwrite.
86
+ """
87
+ overwrite_model_parameter_dict = {}
88
+ overwrite_model_parameters = overwrite_model_parameters or settings.config.args.get(
89
+ "overwrite_model_parameters"
90
+ )
91
+ if overwrite_model_parameters is not None:
92
+ overwrite_model_parameter_dict = schema.validate_dict_using_schema(
93
+ data=ascii_handler.collect_data_from_file(file_name=overwrite_model_parameters),
94
+ schema_file="simulation_models_info.schema.yml",
95
+ ).get("changes", {})
96
+
97
+ return overwrite_model_parameter_dict
98
+
99
+
61
100
  def compute_telescope_transmission(pars: list[float], off_axis: float) -> float:
62
101
  """
63
102
  Compute telescope transmission (0 < T < 1) for a given off-axis angle.
@@ -30,8 +30,8 @@ class SiteModel(ModelParameter):
30
30
  Model version or list of model versions (in which case only the first one is used).
31
31
  label: str, optional
32
32
  Instance label.
33
- overwrite_model_parameters: str, optional
34
- File name to overwrite model parameters from DB with provided values.
33
+ overwrite_model_parameter_dict: dict, optional
34
+ Dictionary to overwrite model parameters from DB with provided values.
35
35
  ignore_software_version: bool, optional
36
36
  If True, ignore software version checks for deprecated parameters.
37
37
  """
@@ -41,7 +41,7 @@ class SiteModel(ModelParameter):
41
41
  site,
42
42
  model_version,
43
43
  label=None,
44
- overwrite_model_parameters=None,
44
+ overwrite_model_parameter_dict=None,
45
45
  ignore_software_version=False,
46
46
  ):
47
47
  """Initialize SiteModel."""
@@ -52,7 +52,7 @@ class SiteModel(ModelParameter):
52
52
  model_version=model_version,
53
53
  label=label,
54
54
  collection="sites",
55
- overwrite_model_parameters=overwrite_model_parameters,
55
+ overwrite_model_parameter_dict=overwrite_model_parameter_dict,
56
56
  ignore_software_version=ignore_software_version,
57
57
  )
58
58
 
@@ -30,8 +30,8 @@ class TelescopeModel(ModelParameter):
30
30
  Model version.
31
31
  label: str, optional
32
32
  Instance label.
33
- overwrite_model_parameters: str, optional
34
- File name to overwrite model parameters from DB with provided values.
33
+ overwrite_model_parameter_dict: dict, optional
34
+ Dictionary to overwrite model parameters from DB with provided values.
35
35
  ignore_software_version: bool, optional
36
36
  If True, ignore software version checks for deprecated parameters.
37
37
  """
@@ -42,7 +42,7 @@ class TelescopeModel(ModelParameter):
42
42
  telescope_name,
43
43
  model_version,
44
44
  label=None,
45
- overwrite_model_parameters=None,
45
+ overwrite_model_parameter_dict=None,
46
46
  ignore_software_version=False,
47
47
  ):
48
48
  """Initialize TelescopeModel."""
@@ -51,12 +51,11 @@ class TelescopeModel(ModelParameter):
51
51
  array_element_name=telescope_name,
52
52
  model_version=model_version,
53
53
  label=label,
54
- overwrite_model_parameters=overwrite_model_parameters,
54
+ overwrite_model_parameter_dict=overwrite_model_parameter_dict,
55
55
  ignore_software_version=ignore_software_version,
56
56
  )
57
57
 
58
58
  self._logger = logging.getLogger(__name__)
59
- self._logger.debug("Init TelescopeModel %s %s", site, telescope_name)
60
59
 
61
60
  self._single_mirror_list_file_paths = None
62
61
  self._mirrors = None
@@ -9,14 +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
18
  from simtools import settings
19
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
20
22
  from simtools.model.model_utils import initialize_simulation_models
21
23
 
22
24
 
@@ -273,8 +275,8 @@ class IncidentAnglesCalculator:
273
275
  """
274
276
  self.logger.info("Executing %s (logging to %s)", script_path, log_file)
275
277
  try:
276
- subprocess.check_call([str(script_path)])
277
- except subprocess.CalledProcessError as exc:
278
+ job_manager.submit(script_path)
279
+ except job_manager.JobExecutionError as exc:
278
280
  raise RuntimeError(f"Incident angles run failed, see log: {log_file}") from exc
279
281
 
280
282
  def _compute_incidence_angles_from_imaging_list(self, photons_file):
@@ -283,7 +285,7 @@ class IncidentAnglesCalculator:
283
285
  Column positions may differ between telescope types and sim_telarray versions.
284
286
  Header lines (``# Column N: ...``) are parsed to find indices; otherwise
285
287
  legacy positions (1-based) are used: focal=26, primary=32, secondary=36,
286
- primary X/Y = 29/30, secondary X/Y = 33/34.
288
+ primary X/Y = 29/30, secondary X/Y=33/34.
287
289
 
288
290
  Parameters
289
291
  ----------
@@ -692,9 +694,88 @@ class IncidentAnglesCalculator:
692
694
  self.logger.warning("No results to save")
693
695
  return
694
696
  output_file = self.results_dir / f"incident_angles_{self._label_suffix()}.ecsv"
695
- 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)
696
706
 
697
707
  MetadataCollector.dump(
698
708
  args_dict=self.config_data,
699
709
  output_file=output_file.with_suffix(".yml"),
700
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