gammasimtools 0.24.0__py3-none-any.whl → 0.26.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.24.0.dist-info → gammasimtools-0.26.0.dist-info}/METADATA +2 -1
  2. {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/RECORD +134 -130
  3. {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/entry_points.txt +3 -1
  4. {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/licenses/LICENSE +1 -1
  5. simtools/_version.py +2 -2
  6. simtools/application_control.py +78 -0
  7. simtools/applications/calculate_incident_angles.py +0 -2
  8. simtools/applications/convert_geo_coordinates_of_array_elements.py +1 -2
  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 +2 -6
  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/derive_mirror_rnda.py +1 -3
  20. simtools/applications/derive_psf_parameters.py +5 -1
  21. simtools/applications/derive_pulse_shape_parameters.py +194 -0
  22. simtools/applications/derive_trigger_rates.py +1 -1
  23. simtools/applications/docs_produce_array_element_report.py +2 -8
  24. simtools/applications/docs_produce_calibration_reports.py +1 -3
  25. simtools/applications/docs_produce_model_parameter_reports.py +0 -2
  26. simtools/applications/docs_produce_simulation_configuration_report.py +1 -3
  27. simtools/applications/generate_array_config.py +0 -1
  28. simtools/applications/generate_corsika_histograms.py +48 -235
  29. simtools/applications/generate_regular_arrays.py +5 -35
  30. simtools/applications/generate_simtel_event_data.py +2 -2
  31. simtools/applications/maintain_simulation_model_add_production.py +2 -2
  32. simtools/applications/maintain_simulation_model_write_array_element_positions.py +87 -0
  33. simtools/applications/plot_array_layout.py +64 -108
  34. simtools/applications/plot_simulated_event_distributions.py +57 -0
  35. simtools/applications/plot_tabular_data.py +0 -1
  36. simtools/applications/plot_tabular_data_for_model_parameter.py +1 -6
  37. simtools/applications/production_derive_corsika_limits.py +1 -1
  38. simtools/applications/production_generate_grid.py +0 -1
  39. simtools/applications/run_application.py +1 -1
  40. simtools/applications/simulate_flasher.py +3 -4
  41. simtools/applications/simulate_illuminator.py +0 -1
  42. simtools/applications/simulate_pedestals.py +2 -6
  43. simtools/applications/simulate_prod.py +9 -28
  44. simtools/applications/simulate_prod_htcondor_generator.py +8 -1
  45. simtools/applications/submit_array_layouts.py +7 -7
  46. simtools/applications/submit_model_parameter_from_external.py +1 -3
  47. simtools/applications/validate_camera_efficiency.py +0 -1
  48. simtools/applications/validate_camera_fov.py +0 -1
  49. simtools/applications/validate_cumulative_psf.py +0 -2
  50. simtools/applications/validate_file_using_schema.py +49 -123
  51. simtools/applications/validate_optics.py +0 -13
  52. simtools/camera/camera_efficiency.py +1 -6
  53. simtools/camera/single_photon_electron_spectrum.py +2 -1
  54. simtools/configuration/commandline_parser.py +43 -8
  55. simtools/configuration/configurator.py +6 -11
  56. simtools/corsika/corsika_config.py +204 -99
  57. simtools/corsika/corsika_histograms.py +411 -1735
  58. simtools/corsika/primary_particle.py +1 -1
  59. simtools/data_model/metadata_collector.py +5 -2
  60. simtools/data_model/metadata_model.py +0 -4
  61. simtools/data_model/model_data_writer.py +27 -17
  62. simtools/data_model/schema.py +112 -5
  63. simtools/data_model/validate_data.py +80 -48
  64. simtools/db/db_handler.py +19 -8
  65. simtools/db/db_model_upload.py +2 -1
  66. simtools/db/mongo_db.py +133 -42
  67. simtools/dependencies.py +83 -44
  68. simtools/io/ascii_handler.py +4 -2
  69. simtools/io/table_handler.py +1 -1
  70. simtools/job_execution/htcondor_script_generator.py +0 -2
  71. simtools/layout/array_layout.py +4 -12
  72. simtools/layout/array_layout_utils.py +227 -58
  73. simtools/model/array_model.py +37 -18
  74. simtools/model/calibration_model.py +0 -4
  75. simtools/model/legacy_model_parameter.py +134 -0
  76. simtools/model/model_parameter.py +24 -14
  77. simtools/model/model_repository.py +18 -5
  78. simtools/model/model_utils.py +1 -6
  79. simtools/model/site_model.py +0 -4
  80. simtools/model/telescope_model.py +6 -11
  81. simtools/production_configuration/derive_corsika_limits.py +6 -11
  82. simtools/production_configuration/interpolation_handler.py +16 -16
  83. simtools/ray_tracing/incident_angles.py +5 -11
  84. simtools/ray_tracing/mirror_panel_psf.py +3 -7
  85. simtools/ray_tracing/psf_analysis.py +29 -27
  86. simtools/ray_tracing/psf_parameter_optimisation.py +822 -680
  87. simtools/ray_tracing/ray_tracing.py +6 -15
  88. simtools/reporting/docs_auto_report_generator.py +8 -13
  89. simtools/reporting/docs_read_parameters.py +70 -16
  90. simtools/runners/corsika_runner.py +15 -10
  91. simtools/runners/corsika_simtel_runner.py +9 -8
  92. simtools/runners/runner_services.py +17 -7
  93. simtools/runners/simtel_runner.py +11 -58
  94. simtools/runners/simtools_runner.py +2 -4
  95. simtools/schemas/model_parameters/flasher_pulse_exp_decay.schema.yml +2 -0
  96. simtools/schemas/model_parameters/flasher_pulse_shape.schema.yml +50 -0
  97. simtools/schemas/model_parameters/flasher_pulse_width.schema.yml +2 -0
  98. simtools/schemas/simulation_models_info.schema.yml +2 -0
  99. simtools/settings.py +154 -0
  100. simtools/sim_events/file_info.py +128 -0
  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 +273 -0
  105. simtools/simtel/simtel_config_writer.py +146 -22
  106. simtools/simtel/simtel_table_reader.py +6 -4
  107. simtools/simtel/simulator_array.py +62 -23
  108. simtools/simtel/simulator_camera_efficiency.py +4 -6
  109. simtools/simtel/simulator_light_emission.py +101 -19
  110. simtools/simtel/simulator_ray_tracing.py +4 -10
  111. simtools/simulator.py +360 -353
  112. simtools/telescope_trigger_rates.py +3 -4
  113. simtools/testing/assertions.py +115 -8
  114. simtools/testing/configuration.py +2 -3
  115. simtools/testing/helpers.py +2 -3
  116. simtools/testing/log_inspector.py +5 -1
  117. simtools/testing/sim_telarray_metadata.py +1 -1
  118. simtools/testing/validate_output.py +69 -23
  119. simtools/utils/general.py +37 -0
  120. simtools/utils/geometry.py +0 -77
  121. simtools/utils/names.py +7 -9
  122. simtools/version.py +37 -0
  123. simtools/visualization/legend_handlers.py +21 -10
  124. simtools/visualization/plot_array_layout.py +312 -41
  125. simtools/visualization/plot_corsika_histograms.py +143 -605
  126. simtools/visualization/plot_mirrors.py +834 -0
  127. simtools/visualization/plot_pixels.py +2 -4
  128. simtools/visualization/plot_psf.py +0 -1
  129. simtools/visualization/plot_simtel_event_histograms.py +4 -4
  130. simtools/visualization/plot_simtel_events.py +6 -11
  131. simtools/visualization/plot_tables.py +8 -19
  132. simtools/visualization/visualize.py +22 -2
  133. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +0 -160
  134. simtools/applications/print_version.py +0 -53
  135. simtools/io/hdf5_handler.py +0 -139
  136. simtools/simtel/simtel_io_file_info.py +0 -62
  137. {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/WHEEL +0 -0
  138. {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@ import logging
5
5
  import shutil
6
6
  from copy import copy
7
7
  from math import pi, tan
8
- from pathlib import Path
9
8
 
10
9
  import astropy.io.ascii
11
10
  import astropy.units as u
@@ -33,8 +32,6 @@ class RayTracing:
33
32
  telescope model
34
33
  site_model: SiteModel
35
34
  site model
36
- simtel_path: str (or Path)
37
- Location of sim_telarray installation.
38
35
  label: str
39
36
  label used for output file naming.
40
37
  zenith_angle: astropy.units.Quantity
@@ -64,7 +61,6 @@ class RayTracing:
64
61
  self,
65
62
  telescope_model,
66
63
  site_model,
67
- simtel_path,
68
64
  label=None,
69
65
  zenith_angle=20.0 * u.deg,
70
66
  off_axis_angle=[0.0] * u.deg,
@@ -78,7 +74,6 @@ class RayTracing:
78
74
  self._logger = logging.getLogger(__name__)
79
75
  self._logger.debug(f"Initializing RayTracing class {single_mirror_mode}")
80
76
 
81
- self.simtel_path = Path(simtel_path)
82
77
  self._io_handler = io_handler.IOHandler()
83
78
 
84
79
  self.telescope_model, self.site_model = telescope_model, site_model
@@ -212,7 +207,6 @@ class RayTracing:
212
207
  f"Simulating RayTracing for off_axis={this_off_axis}, mirror={mirror_number}"
213
208
  )
214
209
  simtel = SimulatorRayTracing(
215
- simtel_path=self.simtel_path,
216
210
  telescope_model=self.telescope_model,
217
211
  site_model=self.site_model,
218
212
  test=test,
@@ -408,11 +402,7 @@ class RayTracing:
408
402
  PSFImage
409
403
  PSF image object.
410
404
  """
411
- image = PSFImage(
412
- focal_length=focal_length,
413
- containment_fraction=containment_fraction,
414
- simtel_path=self.simtel_path,
415
- )
405
+ image = PSFImage(focal_length=focal_length, containment_fraction=containment_fraction)
416
406
  image.process_photon_list(photons_file, use_rx)
417
407
  self._psf_images[this_off_axis] = copy(image)
418
408
  return image
@@ -623,10 +613,11 @@ class RayTracing:
623
613
  -------
624
614
  List of PSFImages
625
615
  """
626
- images = []
627
- for this_off_axis in self.off_axis_angle:
628
- if self._psf_images and this_off_axis in self._psf_images:
629
- images.append(self._psf_images[this_off_axis])
616
+ images = [
617
+ self._psf_images[this_off_axis]
618
+ for this_off_axis in self.off_axis_angle
619
+ if self._psf_images and this_off_axis in self._psf_images
620
+ ]
630
621
  if len(images) == 0:
631
622
  self._logger.warning("No image found")
632
623
  return None
@@ -16,11 +16,10 @@ logger = logging.getLogger()
16
16
  class ReportGenerator:
17
17
  """Automate report generation."""
18
18
 
19
- def __init__(self, db_config, args, output_path):
19
+ def __init__(self, args, output_path):
20
20
  """Initialise class."""
21
21
  self._logger = logging.getLogger(__name__)
22
- self.db = db_handler.DatabaseHandler(db_config=db_config)
23
- self.db_config = db_config
22
+ self.db = db_handler.DatabaseHandler()
24
23
  self.args = args
25
24
  self.output_path = output_path
26
25
 
@@ -99,7 +98,7 @@ class ReportGenerator:
99
98
  )
100
99
 
101
100
  output_path = Path(self.output_path) / str(model_version)
102
- ReadParameters(self.db_config, self.args, output_path).produce_array_element_report()
101
+ ReadParameters(self.args, output_path).produce_array_element_report()
103
102
 
104
103
  logger.info(
105
104
  f"Markdown report generated for {site} "
@@ -167,9 +166,7 @@ class ReportGenerator:
167
166
  }
168
167
  )
169
168
 
170
- ReadParameters(
171
- self.db_config, self.args, self.output_path
172
- ).produce_model_parameter_reports()
169
+ ReadParameters(self.args, self.output_path).produce_model_parameter_reports()
173
170
 
174
171
  logger.info(
175
172
  f"Markdown report generated for {site} Telescope {telescope}: {self.output_path}"
@@ -211,7 +208,7 @@ class ReportGenerator:
211
208
  )
212
209
 
213
210
  output_path = Path(self.output_path) / str(model_version)
214
- ReadParameters(self.db_config, self.args, output_path).produce_observatory_report()
211
+ ReadParameters(self.args, output_path).produce_observatory_report()
215
212
 
216
213
  logger.info(f"Observatory report generated for {site} (v{model_version}): {output_path}")
217
214
 
@@ -237,9 +234,7 @@ class ReportGenerator:
237
234
  self.args.update({"model_version": version})
238
235
  output_path = Path(self.output_path) / str(version)
239
236
 
240
- ReadParameters(
241
- self.db_config, self.args, output_path
242
- ).produce_simulation_configuration_report()
237
+ ReadParameters(self.args, output_path).produce_simulation_configuration_report()
243
238
 
244
239
  logger.info(f"Configuration reports for (v{version}) produced: {output_path}")
245
240
 
@@ -262,7 +257,7 @@ class ReportGenerator:
262
257
  output_path = Path(self.output_path) / str(version)
263
258
 
264
259
  try:
265
- ReadParameters(self.db_config, self.args, output_path).produce_calibration_reports()
260
+ ReadParameters(self.args, output_path).produce_calibration_reports()
266
261
  logger.info(f"Calibration reports for (v{version}) produced: {output_path}")
267
262
  except ValueError as err:
268
263
  # Some model versions do not have calibration_devices in the DB;
@@ -305,7 +300,7 @@ class ReportGenerator:
305
300
 
306
301
  # Generate parameter comparison reports for calibration devices
307
302
  ReadParameters(
308
- self.db_config, version_args, self.output_path
303
+ version_args, self.output_path
309
304
  ).generate_model_parameter_reports_for_devices(array_elements)
310
305
 
311
306
  logger.info(
@@ -17,7 +17,7 @@ from simtools.io import ascii_handler, io_handler
17
17
  from simtools.model.telescope_model import TelescopeModel
18
18
  from simtools.utils import names
19
19
  from simtools.version import sort_versions
20
- from simtools.visualization import plot_pixels, plot_tables
20
+ from simtools.visualization import plot_mirrors, plot_pixels, plot_tables
21
21
 
22
22
  logger = logging.getLogger()
23
23
  MARKDOWN_LINK_RE = re.compile(r"\[([^\]]+)\]\(([^)]+)\)")
@@ -26,11 +26,10 @@ MARKDOWN_LINK_RE = re.compile(r"\[([^\]]+)\]\(([^)]+)\)")
26
26
  class ReadParameters:
27
27
  """Read and manage model parameter data for report generation."""
28
28
 
29
- def __init__(self, db_config, args, output_path):
29
+ def __init__(self, args, output_path):
30
30
  """Initialise class."""
31
31
  self._logger = logging.getLogger(__name__)
32
- self.db = db_handler.DatabaseHandler(db_config=db_config)
33
- self.db_config = db_config
32
+ self.db = db_handler.DatabaseHandler()
34
33
  self.array_element = args.get("telescope", None)
35
34
  self.site = args.get("site", None)
36
35
  self.model_version = args.get("model_version", None)
@@ -72,6 +71,12 @@ class ReadParameters:
72
71
 
73
72
  if parameter == "camera_config_file":
74
73
  plot_names = self._plot_camera_config(parameter, parameter_version, input_file, outpath)
74
+ elif parameter in (
75
+ "mirror_list",
76
+ "primary_mirror_segmentation",
77
+ "secondary_mirror_segmentation",
78
+ ):
79
+ plot_names = self._plot_mirror_config(parameter, parameter_version, input_file, outpath)
75
80
  elif parameter_version:
76
81
  plot_names = self._plot_parameter_tables(
77
82
  parameter,
@@ -103,7 +108,6 @@ class ReadParameters:
103
108
  plot_pixels.plot(
104
109
  config=plot_config,
105
110
  output_file=Path(f"{outpath}/{plot_name}"),
106
- db_config=self.db_config,
107
111
  )
108
112
  plot_names.append(plot_name)
109
113
  else:
@@ -115,6 +119,38 @@ class ReadParameters:
115
119
 
116
120
  return plot_names
117
121
 
122
+ def _plot_mirror_config(self, parameter, parameter_version, input_file, outpath):
123
+ """Generate plots for mirror configuration files."""
124
+ if not parameter_version:
125
+ return []
126
+
127
+ plot_names = []
128
+ plot_name = input_file.stem.replace(".", "-")
129
+ plot_path = Path(f"{outpath}/{plot_name}").with_suffix(".png")
130
+
131
+ if not plot_path.exists():
132
+ plot_config = {
133
+ "parameter": parameter,
134
+ "telescope": self.array_element,
135
+ "parameter_version": parameter_version,
136
+ "site": self.site,
137
+ "model_version": self.model_version,
138
+ }
139
+
140
+ plot_mirrors.plot(
141
+ config=plot_config,
142
+ output_file=Path(f"{outpath}/{plot_name}"),
143
+ )
144
+ plot_names.append(plot_name)
145
+ else:
146
+ logger.info(
147
+ "Mirror configuration file plot already exists: %s",
148
+ plot_path,
149
+ )
150
+ plot_names.append(plot_name)
151
+
152
+ return plot_names
153
+
118
154
  def _plot_parameter_tables(self, parameter, parameter_version, outpath):
119
155
  """Generate plots for parameter tables."""
120
156
  tel = self._get_telescope_identifier()
@@ -126,7 +162,6 @@ class ReadParameters:
126
162
  telescope=tel,
127
163
  output_path=outpath,
128
164
  plot_type="all",
129
- db_config=self.db_config,
130
165
  )
131
166
 
132
167
  if not config_data:
@@ -141,7 +176,6 @@ class ReadParameters:
141
176
  plot_tables.plot(
142
177
  config=plot_config,
143
178
  output_file=image_output_file,
144
- db_config=self.db_config,
145
179
  )
146
180
  plt.close("all")
147
181
 
@@ -175,7 +209,7 @@ class ReadParameters:
175
209
  markdown_output_file = output_data_path / output_file_name
176
210
 
177
211
  if not markdown_output_file.exists():
178
- outpath = Path(io_handler.IOHandler().get_output_directory().parent / "_images")
212
+ outpath = io_handler.IOHandler().get_output_directory("_images")
179
213
  outpath.mkdir(parents=True, exist_ok=True)
180
214
 
181
215
  plot_names = self._generate_plots(parameter, parameter_version, input_file, outpath)
@@ -543,7 +577,6 @@ class ReadParameters:
543
577
  telescope_name=self.array_element,
544
578
  model_version=self.model_version,
545
579
  label="reports",
546
- db_config=self.db_config,
547
580
  ignore_software_version=True,
548
581
  )
549
582
 
@@ -648,7 +681,7 @@ class ReadParameters:
648
681
 
649
682
  def _write_file_flag_section(self, file, parameter, comparison_data):
650
683
  """Write image/plot references when parameter entries include files."""
651
- outpath = Path(io_handler.IOHandler().get_output_directory().parent / "_images")
684
+ outpath = io_handler.IOHandler().get_output_directory("_images")
652
685
  latest_parameter_version = max(
653
686
  comparison_data.get(parameter),
654
687
  key=lambda x: tuple(map(int, x["parameter_version"].split("."))),
@@ -664,13 +697,25 @@ class ReadParameters:
664
697
 
665
698
  file.write("The latest parameter version is plotted below.\n\n")
666
699
 
667
- if parameter != "camera_config_file":
668
- plot_name = f"{parameter}_{latest_parameter_version}_{self.site}_{tel}"
669
- image_path = outpath / f"{plot_name}.png"
670
- file.write(f"![Parameter plot.]({image_path.as_posix()})")
700
+ if parameter in (
701
+ "camera_config_file",
702
+ "mirror_list",
703
+ "primary_mirror_segmentation",
704
+ "secondary_mirror_segmentation",
705
+ ):
706
+ self._write_file_based_plot(
707
+ file, parameter, comparison_data, latest_model_version, outpath
708
+ )
671
709
  return
672
710
 
673
- # camera_config_file: find latest value and convert markdown link to png filename
711
+ plot_name = f"{parameter}_{latest_parameter_version}_{self.site}_{tel}"
712
+ image_path = outpath / f"{plot_name}.png"
713
+ file.write(f"![Parameter plot.]({image_path.as_posix()})")
714
+
715
+ def _write_file_based_plot(
716
+ self, file, parameter, comparison_data, latest_model_version, outpath
717
+ ):
718
+ """Write plot reference for file-based parameters."""
674
719
  latest_value = None
675
720
  for item in comparison_data.get(parameter):
676
721
  if latest_model_version in item["model_version"].split(", "):
@@ -686,7 +731,16 @@ class ReadParameters:
686
731
 
687
732
  filename_png = Path(match.group(1)).with_suffix(".png").name
688
733
  image_path = outpath / filename_png
689
- file.write(f"![Camera configuration plot.]({image_path.as_posix()})")
734
+
735
+ plot_descriptions = {
736
+ "camera_config_file": "Camera configuration plot",
737
+ "mirror_list": "Mirror panel layout",
738
+ "primary_mirror_segmentation": "Primary mirror segmentation",
739
+ "secondary_mirror_segmentation": "Secondary mirror segmentation",
740
+ }
741
+
742
+ description = plot_descriptions.get(parameter, "Parameter plot")
743
+ file.write(f"![{description}.]({image_path.as_posix()})")
690
744
 
691
745
  def _write_array_layouts_section(self, file, layouts):
692
746
  """Write the array layouts section of the report."""
@@ -2,8 +2,8 @@
2
2
 
3
3
  import logging
4
4
  import stat
5
- from pathlib import Path
6
5
 
6
+ from simtools import settings
7
7
  from simtools.io import io_handler
8
8
  from simtools.runners.runner_services import RunnerServices
9
9
 
@@ -26,23 +26,23 @@ class CorsikaRunner:
26
26
  ----------
27
27
  corsika_config_data: CorsikaConfig
28
28
  CORSIKA configuration.
29
- simtel_path: str or Path
30
- Location of source of the sim_telarray/CORSIKA package.
31
29
  label: str
32
30
  Instance label.
33
31
  keep_seeds: bool
34
32
  Use seeds based on run number and primary particle. If False, use sim_telarray seeds.
35
33
  use_multipipe: bool
36
34
  Use multipipe to run CORSIKA and sim_telarray.
35
+ curved_atmosphere_min_zenith_angle: Quantity
36
+ Minimum zenith angle for which to use the curved-atmosphere CORSIKA binary.
37
37
  """
38
38
 
39
39
  def __init__(
40
40
  self,
41
41
  corsika_config,
42
- simtel_path,
43
42
  label=None,
44
43
  keep_seeds=False,
45
44
  use_multipipe=False,
45
+ curved_atmosphere_min_zenith_angle=None,
46
46
  ):
47
47
  """Initialize CorsikaRunner."""
48
48
  self._logger = logging.getLogger(__name__)
@@ -52,8 +52,8 @@ class CorsikaRunner:
52
52
  self.corsika_config = corsika_config
53
53
  self._keep_seeds = keep_seeds
54
54
  self._use_multipipe = use_multipipe
55
+ self.curved_atmosphere_min_zenith_angle = curved_atmosphere_min_zenith_angle
55
56
 
56
- self._simtel_path = Path(simtel_path)
57
57
  self.io_handler = io_handler.IOHandler()
58
58
 
59
59
  self.runner_service = RunnerServices(corsika_config, label)
@@ -63,7 +63,7 @@ class CorsikaRunner:
63
63
  self, run_number=None, extra_commands=None, input_file=None, use_pfp=True
64
64
  ):
65
65
  """
66
- Get the full path of the run script file for a given run number.
66
+ Prepare and write CORSIKA run script.
67
67
 
68
68
  Parameters
69
69
  ----------
@@ -174,7 +174,7 @@ class CorsikaRunner:
174
174
  str
175
175
  pfp command.
176
176
  """
177
- cmd = self._simtel_path.joinpath("sim_telarray/bin/pfp")
177
+ cmd = settings.config.sim_telarray_path / "bin/pfp"
178
178
  cmd = str(cmd) + f" -V -DWITHOUT_MULTIPIPE - < {corsika_input_file}"
179
179
  cmd += f" > {input_tmp_file} || exit\n"
180
180
  return cmd
@@ -183,7 +183,7 @@ class CorsikaRunner:
183
183
  """
184
184
  Get autoinputs command.
185
185
 
186
- corsika_autoinputs is a tool to generate random and user/host dependent
186
+ corsika_autoinputs is a tool to generate random seeds and user/host dependent
187
187
  parameters for CORSIKA configuration.
188
188
 
189
189
  Parameters
@@ -198,13 +198,18 @@ class CorsikaRunner:
198
198
  str
199
199
  autoinputs command.
200
200
  """
201
- corsika_bin_path = self._simtel_path.joinpath("corsika-run/corsika")
201
+ if self.corsika_config.use_curved_atmosphere:
202
+ corsika_bin_path = settings.config.corsika_exe_curved
203
+ self._logger.debug("Using curved-atmosphere CORSIKA binary.")
204
+ else:
205
+ corsika_bin_path = settings.config.corsika_exe
206
+ self._logger.debug("Using flat-atmosphere CORSIKA binary.")
202
207
 
203
208
  log_file = self.get_file_name(file_type="log", run_number=run_number)
204
209
  if self._use_multipipe:
205
210
  log_file = log_file.with_name(f"multipipe_{log_file.name}")
206
211
 
207
- cmd = self._simtel_path.joinpath("sim_telarray/bin/corsika_autoinputs")
212
+ cmd = settings.config.sim_telarray_path.joinpath("bin/corsika_autoinputs")
208
213
  cmd = str(cmd) + f" --run {corsika_bin_path}"
209
214
  cmd += f" -R {run_number}"
210
215
  cmd += ' -p "$CORSIKA_DATA"'
@@ -5,6 +5,7 @@ import stat
5
5
  from pathlib import Path
6
6
 
7
7
  import simtools.utils.general as gen
8
+ from simtools import settings
8
9
  from simtools.runners.corsika_runner import CorsikaRunner
9
10
  from simtools.simtel.simulator_array import SimulatorArray
10
11
 
@@ -21,8 +22,6 @@ class CorsikaSimtelRunner:
21
22
  corsika_config : CorsikaConfig or list of CorsikaConfig
22
23
  A list of "CorsikaConfig" instances which
23
24
  contain the CORSIKA configuration parameters.
24
- simtel_path : str or Path
25
- Location of the sim_telarray package.
26
25
  label : str
27
26
  Label.
28
27
  keep_seeds : bool
@@ -38,20 +37,19 @@ class CorsikaSimtelRunner:
38
37
  def __init__(
39
38
  self,
40
39
  corsika_config,
41
- simtel_path,
42
40
  label=None,
43
41
  keep_seeds=False,
44
42
  use_multipipe=False,
45
43
  sim_telarray_seeds=None,
46
44
  sequential=False,
47
45
  calibration_config=None,
46
+ curved_atmosphere_min_zenith_angle=None,
48
47
  ):
49
48
  self._logger = logging.getLogger(__name__)
50
49
  self.corsika_config = gen.ensure_iterable(corsika_config)
51
50
  # the base corsika config is the one used to define the CORSIKA specific parameters.
52
51
  # The others are used for the array configurations.
53
52
  self.base_corsika_config = self.corsika_config[0]
54
- self._simtel_path = simtel_path
55
53
  self.sim_telarray_seeds = sim_telarray_seeds
56
54
  self.label = label
57
55
  self.sequential = "--sequential" if sequential else ""
@@ -59,10 +57,10 @@ class CorsikaSimtelRunner:
59
57
  self.base_corsika_config.set_output_file_and_directory(use_multipipe)
60
58
  self.corsika_runner = CorsikaRunner(
61
59
  corsika_config=self.base_corsika_config,
62
- simtel_path=simtel_path,
63
60
  label=label,
64
61
  keep_seeds=keep_seeds,
65
62
  use_multipipe=use_multipipe,
63
+ curved_atmosphere_min_zenith_angle=curved_atmosphere_min_zenith_angle,
66
64
  )
67
65
  # The simulator array should be defined for every CORSIKA configuration
68
66
  # because it allows to define multiple sim_telarray instances
@@ -71,7 +69,6 @@ class CorsikaSimtelRunner:
71
69
  self.simulator_array.append(
72
70
  SimulatorArray(
73
71
  corsika_config=_corsika_config,
74
- simtel_path=simtel_path,
75
72
  label=label,
76
73
  use_multipipe=use_multipipe,
77
74
  sim_telarray_seeds=sim_telarray_seeds,
@@ -169,8 +166,8 @@ class CorsikaSimtelRunner:
169
166
  "run_cta_multipipe"
170
167
  )
171
168
  with open(multipipe_script, "w", encoding="utf-8") as file:
172
- multipipe_command = Path(self._simtel_path).joinpath(
173
- f"sim_telarray/bin/multipipe_corsika -c {multipipe_file} {self.sequential} "
169
+ multipipe_command = settings.config.sim_telarray_path.joinpath(
170
+ f"bin/multipipe_corsika -c {multipipe_file} {self.sequential} "
174
171
  "|| echo 'Fan-out failed'"
175
172
  )
176
173
  file.write(f"{multipipe_command}")
@@ -218,3 +215,7 @@ class CorsikaSimtelRunner:
218
215
  else self.simulator_array[model_version_index]
219
216
  )
220
217
  return runner.get_file_name(file_type=file_type, run_number=run_number, mode=mode)
218
+
219
+ def get_resources(self, run_number=None):
220
+ """Return computing resources used."""
221
+ return self.corsika_runner.get_resources(run_number)
@@ -28,7 +28,7 @@ class RunnerServices:
28
28
  self.corsika_config = corsika_config
29
29
  self.directory = {}
30
30
 
31
- def _get_info_for_file_name(self, run_number):
31
+ def _get_info_for_file_name(self, run_number, calibration_run_mode=None):
32
32
  """
33
33
  Return dictionary for building names for simulation output files.
34
34
 
@@ -36,6 +36,8 @@ class RunnerServices:
36
36
  ----------
37
37
  run_number : int
38
38
  Run number.
39
+ calibration_run_mode: str
40
+ Calibration run mode.
39
41
 
40
42
  Returns
41
43
  -------
@@ -43,9 +45,12 @@ class RunnerServices:
43
45
  Dictionary with the keys or building the file names for simulation output files.
44
46
  """
45
47
  _vc_high = self.corsika_config.get_config_parameter("VIEWCONE")[1]
46
- primary_name = self.corsika_config.primary
47
- if primary_name == "gamma" and _vc_high > 0:
48
- primary_name = "gamma_diffuse"
48
+ if calibration_run_mode is not None and calibration_run_mode != "":
49
+ primary_name = calibration_run_mode
50
+ else:
51
+ primary_name = self.corsika_config.primary
52
+ if primary_name == "gamma" and _vc_high > 0:
53
+ primary_name = "gamma_diffuse"
49
54
  return {
50
55
  "run_number": self.corsika_config.validate_run_number(run_number),
51
56
  "primary": primary_name,
@@ -119,7 +124,7 @@ class RunnerServices:
119
124
  _logger.debug(f"Checking if {run_sub_file} exists")
120
125
  return Path(run_sub_file).is_file()
121
126
 
122
- def _get_file_basename(self, run_number):
127
+ def _get_file_basename(self, run_number, calibration_run_mode):
123
128
  """
124
129
  Get the base name for the simulation files.
125
130
 
@@ -127,13 +132,15 @@ class RunnerServices:
127
132
  ----------
128
133
  run_number: int
129
134
  Run number.
135
+ calibration_run_mode: str
136
+ Calibration run mode.
130
137
 
131
138
  Returns
132
139
  -------
133
140
  str
134
141
  Base name for the simulation files.
135
142
  """
136
- info_for_file_name = self._get_info_for_file_name(run_number)
143
+ info_for_file_name = self._get_info_for_file_name(run_number, calibration_run_mode)
137
144
  file_label = f"_{info_for_file_name['label']}" if info_for_file_name.get("label") else ""
138
145
  zenith = self.corsika_config.get_config_parameter("THETAP")[0]
139
146
  azimuth = self.corsika_config.azimuth_angle
@@ -232,6 +239,7 @@ class RunnerServices:
232
239
  file_type,
233
240
  run_number=None,
234
241
  mode=None,
242
+ calibration_run_mode=None,
235
243
  _model_version_index=0,
236
244
  ): # pylint: disable=unused-argument
237
245
  """
@@ -245,6 +253,8 @@ class RunnerServices:
245
253
  Run number.
246
254
  mode: str
247
255
  out or err (optional, relevant only for sub_log).
256
+ calibration_run_mode: str
257
+ Calibration run mode.
248
258
  model_version_index: int
249
259
  Index of the model version.
250
260
  This is not used here, but in other implementations of this function is
@@ -261,7 +271,7 @@ class RunnerServices:
261
271
  ValueError
262
272
  If file_type is unknown.
263
273
  """
264
- file_name = self._get_file_basename(run_number)
274
+ file_name = self._get_file_basename(run_number, calibration_run_mode)
265
275
 
266
276
  if file_type in ["log", "histogram", "corsika_log"]:
267
277
  return self._get_log_file_path(file_type, file_name)
@@ -1,9 +1,7 @@
1
1
  """Base class for running sim_telarray simulations."""
2
2
 
3
3
  import logging
4
- import stat
5
4
  import subprocess
6
- from pathlib import Path
7
5
 
8
6
  import simtools.utils.general as gen
9
7
  from simtools.runners.runner_services import RunnerServices
@@ -26,23 +24,29 @@ class SimtelRunner:
26
24
 
27
25
  Parameters
28
26
  ----------
29
- simtel_path: str or Path
30
- Location of sim_telarray installation.
31
27
  label: str
32
28
  Instance label. Important for output file naming.
33
29
  corsika_config: CorsikaConfig
34
30
  CORSIKA configuration.
35
31
  use_multipipe: bool
36
32
  Use multipipe to run CORSIKA and sim_telarray.
33
+ calibration_run_mode: str
34
+ Calibration run mode.
37
35
  """
38
36
 
39
- def __init__(self, simtel_path, label=None, corsika_config=None, use_multipipe=False):
37
+ def __init__(
38
+ self,
39
+ label=None,
40
+ corsika_config=None,
41
+ use_multipipe=False,
42
+ calibration_run_mode=None,
43
+ ):
40
44
  """Initialize SimtelRunner."""
41
45
  self._logger = logging.getLogger(__name__)
42
46
 
43
- self._simtel_path = Path(simtel_path)
44
47
  self.label = label
45
48
  self._base_directory = None
49
+ self.calibration_run_mode = calibration_run_mode
46
50
 
47
51
  self.runs_per_set = 1
48
52
 
@@ -51,56 +55,6 @@ class SimtelRunner:
51
55
  "corsika_sim_telarray" if use_multipipe else "sim_telarray"
52
56
  )
53
57
 
54
- def __repr__(self):
55
- """Return a string representation of the SimtelRunner object."""
56
- return f"SimtelRunner(label={self.label})\n"
57
-
58
- def prepare_run_script(self, test=False, input_file=None, run_number=None, extra_commands=None):
59
- """
60
- Build and return the full path of the bash run script containing the sim_telarray command.
61
-
62
- Parameters
63
- ----------
64
- test: bool
65
- Test flag for faster execution.
66
- input_file: str or Path
67
- Full path of the input CORSIKA file.
68
- run_number: int
69
- Run number.
70
- extra_commands: str
71
- Additional commands for running simulations given in config.yml.
72
-
73
- Returns
74
- -------
75
- Path
76
- Full path of the run script.
77
- """
78
- script_file_path = self.get_file_name(file_type="sub_script", run_number=run_number)
79
- self._logger.debug(f"Run bash script - {script_file_path}")
80
- self._logger.debug(f"Extra commands to be added to the run script {extra_commands}")
81
-
82
- command = self._make_run_command(run_number=run_number, input_file=input_file)
83
- with script_file_path.open("w", encoding="utf-8") as file:
84
- file.write("#!/usr/bin/env bash\n\n")
85
- file.write("set -e\n")
86
- file.write("set -o pipefail\n")
87
- file.write("\nSECONDS=0\n")
88
-
89
- if extra_commands is not None:
90
- file.write("# Writing extras\n")
91
- for line in extra_commands:
92
- file.write(f"{line}\n")
93
- file.write("# End of extras\n\n")
94
-
95
- n = 1 if test else self.runs_per_set
96
- for _ in range(n):
97
- file.write(f"{command}\n\n")
98
-
99
- file.write('\necho "RUNTIME: $SECONDS"\n')
100
-
101
- script_file_path.chmod(script_file_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP)
102
- return script_file_path
103
-
104
58
  def run(self, test=False, input_file=None, run_number=None):
105
59
  """
106
60
  Make run command and run sim_telarray.
@@ -148,8 +102,6 @@ class SimtelRunner:
148
102
  msg = gen.get_log_excerpt(self._log_file)
149
103
  else:
150
104
  msg = "Simtel log file does not exist."
151
-
152
- self._logger.error(msg)
153
105
  raise SimtelExecutionError(msg)
154
106
 
155
107
  def _run_simtel_and_check_output(self, command, stdout_file, stderr_file):
@@ -255,4 +207,5 @@ class SimtelRunner:
255
207
  run_number=run_number,
256
208
  mode=mode,
257
209
  _model_version_index=model_version_index,
210
+ calibration_run_mode=self.calibration_run_mode,
258
211
  )