gammasimtools 0.26.0__py3-none-any.whl → 0.27.1__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.1.dist-info}/METADATA +5 -1
  2. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.dist-info}/RECORD +70 -66
  3. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.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 +52 -4
  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.1.dist-info}/licenses/LICENSE +0 -0
  70. {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.dist-info}/top_level.txt +0 -0
@@ -7,9 +7,7 @@ Main functionalities are: computing centroids, psf containers etc.
7
7
 
8
8
  import gzip
9
9
  import logging
10
- import shlex
11
- import shutil
12
- import subprocess
10
+ import tempfile
13
11
  from math import fabs, pi, sqrt
14
12
  from pathlib import Path
15
13
 
@@ -18,6 +16,7 @@ import matplotlib.pyplot as plt
18
16
  import numpy as np
19
17
 
20
18
  from simtools import settings
19
+ from simtools.job_execution import job_manager
21
20
  from simtools.utils.general import collect_kwargs, set_default_kwargs
22
21
 
23
22
 
@@ -93,36 +92,49 @@ class PSFImage:
93
92
  photons_file: str
94
93
  Name of sim_telarray file with photon list.
95
94
  """
95
+ rx_command = [
96
+ f"{settings.config.sim_telarray_path}/bin/rx",
97
+ "-f",
98
+ f"{self._containment_fraction:.2f}",
99
+ "-v",
100
+ ]
101
+
96
102
  try:
97
- with subprocess.Popen(
98
- shlex.split(
99
- f"{settings.config.sim_telarray_path}/bin/rx "
100
- f"-f {self._containment_fraction:.2f} -v"
101
- ),
102
- stdin=subprocess.PIPE,
103
- stdout=subprocess.PIPE,
104
- ) as rx_process:
105
- with gzip.open(photon_file, "rb") as _stdin:
106
- with rx_process.stdin:
107
- shutil.copyfileobj(_stdin, rx_process.stdin)
108
- try:
109
- rx_output = rx_process.communicate()[0].splitlines()[-1:][0].split()
110
- except IndexError as e:
111
- raise IndexError(
112
- f"Unexpected output format from rx: {rx_process}"
113
- ) from e
103
+ with tempfile.NamedTemporaryFile(mode="wb", delete=False) as tmp_file:
104
+ with gzip.open(photon_file, "rb") as gz:
105
+ tmp_file.write(gz.read())
106
+ tmp_file_path = tmp_file.name
107
+
108
+ try:
109
+ with open(tmp_file_path, "rb") as tmp_f:
110
+ result = job_manager.submit(rx_command, stdin=tmp_f)
111
+
112
+ data_lines = [
113
+ line.strip()
114
+ for line in result.stdout.strip().split("\n")
115
+ if line.strip() and not line.startswith("#")
116
+ ]
117
+
118
+ if not data_lines:
119
+ raise IndexError("No data line found in RX output")
120
+
121
+ rx_output = data_lines[-1].split()
122
+ self.set_psf(
123
+ 2 * float(rx_output[0]), fraction=self._containment_fraction, unit="cm"
124
+ )
125
+ self.centroid_x = float(rx_output[1])
126
+ self.centroid_y = float(rx_output[2])
127
+ self._effective_area = float(rx_output[5])
128
+
129
+ finally:
130
+ Path(tmp_file_path).unlink(missing_ok=True)
131
+
114
132
  except FileNotFoundError as e:
115
133
  raise FileNotFoundError(f"Photon list file not found: {photon_file}") from e
116
-
117
- try:
118
- self.set_psf(2 * float(rx_output[0]), fraction=self._containment_fraction, unit="cm")
119
- self.centroid_x = float(rx_output[1])
120
- self.centroid_y = float(rx_output[2])
121
- self._effective_area = float(rx_output[5])
122
- except IndexError as e:
123
- raise IndexError(f"Unexpected output format from rx: {rx_output}") from e
124
- except ValueError as e:
125
- raise ValueError(f"Invalid output format from rx: {rx_output}") from e
134
+ except (IndexError, ValueError) as e:
135
+ raise type(e)(
136
+ f"Invalid RX output format: {locals().get('rx_output', 'unknown')}"
137
+ ) from e
126
138
 
127
139
  def read_photon_list_from_simtel_file(self, photons_file):
128
140
  """
@@ -150,9 +162,9 @@ class PSFImage:
150
162
  self._process_simtel_line(line)
151
163
 
152
164
  if not self._is_photon_positions_ok():
153
- msg = "Problems reading sim_telarray file - invalid data"
154
- self._logger.error(msg)
155
- raise RuntimeError(msg)
165
+ raise RuntimeError(
166
+ f"Problems reading sim_telarray photons file {photons_file} - invalid data"
167
+ )
156
168
 
157
169
  self.centroid_x = np.mean(self.photon_pos_x)
158
170
  self.centroid_y = np.mean(self.photon_pos_y)
@@ -467,9 +479,10 @@ class PSFImage:
467
479
  ax.hist2d(data["X"], data["Y"], **kwargs_for_image)
468
480
  ax.set_aspect("equal", "datalim")
469
481
 
470
- # PSF circle (80%)
482
+ # PSF circle (containment fraction)
483
+ fraction = self._containment_fraction if self._containment_fraction is not None else 0.8
471
484
  center = (0, 0) if centralized else (self.centroid_x, self.centroid_y)
472
- circle = plt.Circle(center, self.get_psf(0.8) / 2, **kwargs_for_psf)
485
+ circle = plt.Circle(center, self.get_psf(fraction) / 2, **kwargs_for_psf)
473
486
  ax.add_artist(circle)
474
487
 
475
488
  ax.axhline(0, color="k", linestyle="--", zorder=3, linewidth=0.5)
@@ -495,7 +508,8 @@ class PSFImage:
495
508
  if radius is not None:
496
509
  radius_all = radius.to(u.cm).value if isinstance(radius, u.Quantity) else radius
497
510
  else:
498
- radius_all = list(np.linspace(0, 1.6 * self.get_psf(0.8), 30))
511
+ fraction = self._containment_fraction if self._containment_fraction is not None else 0.8
512
+ radius_all = list(np.linspace(0, 1.6 * self.get_psf(fraction), 30))
499
513
  intensity = [
500
514
  self._sum_photons_in_radius(rad) / self._number_of_detected_photons
501
515
  for rad in radius_all
@@ -510,15 +524,15 @@ class PSFImage:
510
524
 
511
525
  return result
512
526
 
513
- def plot_cumulative(self, file_name=None, d80=None, **kwargs):
527
+ def plot_cumulative(self, file_name=None, psf_diameter_cm=None, **kwargs):
514
528
  """Plot cumulative data (intensity vs radius).
515
529
 
516
530
  Parameters
517
531
  ----------
518
532
  file_name: str
519
533
  Name of the file to save the plot to.
520
- d80: float
521
- d80 value to be marked in the plot (in cm).
534
+ psf_diameter_cm: float
535
+ PSF diameter value to be marked in the plot (in cm).
522
536
  **kwargs:
523
537
  Customization of line plot (e.g., color, linestyle, linewidth).
524
538
  """
@@ -527,9 +541,10 @@ class PSFImage:
527
541
  ax.set_xlabel("Radius (cm)")
528
542
  ax.set_ylabel("Contained light %")
529
543
  ax.plot(data[self.__PSF_RADIUS], data[self.__PSF_CUMULATIVE], **kwargs)
530
- ax.axvline(x=self.get_psf(0.8) / 2, color="b", linestyle="--", linewidth=1)
531
- if d80 is not None:
532
- ax.axvline(x=d80 / 2.0, color="r", linestyle="--", linewidth=1)
544
+ fraction = self._containment_fraction if self._containment_fraction is not None else 0.8
545
+ ax.axvline(x=self.get_psf(fraction) / 2, color="b", linestyle="--", linewidth=1)
546
+ if psf_diameter_cm is not None:
547
+ ax.axvline(x=psf_diameter_cm / 2.0, color="r", linestyle="--", linewidth=1)
533
548
  if file_name is not None:
534
549
  fig.savefig(file_name)
535
550
  plt.close(fig)
@@ -857,10 +857,11 @@ def _run_ray_tracing_simulation(tel_model, site_model, args_dict, pars):
857
857
  if pars is None:
858
858
  raise ValueError("No best parameters found")
859
859
 
860
- tel_model.overwrite_parameters(pars)
860
+ tel_model.overwrite_parameters(pars, flat_dict=True)
861
861
  ray = RayTracing(
862
862
  telescope_model=tel_model,
863
863
  site_model=site_model,
864
+ label=args_dict.get("label") or getattr(tel_model, "label", None),
864
865
  zenith_angle=args_dict["zenith"] * u.deg,
865
866
  source_distance=args_dict["src_distance"] * u.km,
866
867
  off_axis_angle=[0.0] * u.deg,
@@ -1381,7 +1382,7 @@ def cleanup_intermediate_files(output_dir):
1381
1382
  output_dir : Path
1382
1383
  Directory containing output files to clean up.
1383
1384
  """
1384
- patterns = ["*.log", "*.lis*"]
1385
+ patterns = ["*.log", "*.lis*", "*.dat"]
1385
1386
  files_removed = 0
1386
1387
 
1387
1388
  for pattern in patterns:
@@ -51,8 +51,8 @@ class RayTracing:
51
51
  """
52
52
 
53
53
  YLABEL = {
54
- "d80_cm": r"$D_{80}$",
55
- "d80_deg": r"$D_{80}$",
54
+ "psf_cm": "PSF",
55
+ "psf_deg": "PSF",
56
56
  "eff_area": "Eff. mirror area",
57
57
  "eff_flen": "Eff. focal length",
58
58
  }
@@ -209,6 +209,7 @@ class RayTracing:
209
209
  simtel = SimulatorRayTracing(
210
210
  telescope_model=self.telescope_model,
211
211
  site_model=self.site_model,
212
+ label=self.label,
212
213
  test=test,
213
214
  config_data={
214
215
  "zenith_angle": self.zenith_angle,
@@ -468,22 +469,46 @@ class RayTracing:
468
469
  else:
469
470
  self._logger.error("No results to export")
470
471
 
472
+ def get_psf_mm(self, row_index: int = 0) -> float:
473
+ """Return PSF diameter from the analysis results in mm.
474
+
475
+ Parameters
476
+ ----------
477
+ row_index : int
478
+ Row index into the results table (default: 0).
479
+
480
+ Returns
481
+ -------
482
+ float
483
+ PSF diameter in millimeters.
484
+ """
485
+ if self._results is None:
486
+ raise RuntimeError("No results available; run analyze() first")
487
+ psf = self._results["psf_cm"][row_index]
488
+
489
+ if isinstance(psf, u.Quantity):
490
+ psf_cm = psf.to_value(u.cm)
491
+ else:
492
+ psf_cm = float(psf)
493
+
494
+ return psf_cm * 10.0
495
+
471
496
  def _read_results(self):
472
497
  """Read existing results file and store it in _results."""
473
498
  self._results = astropy.io.ascii.read(self._file_results, format="ecsv")
474
499
 
475
- def plot(self, key, save=False, d80=None, **kwargs):
500
+ def plot(self, key, save=False, psf_diameter_cm=None, **kwargs):
476
501
  """
477
502
  Plot key vs off-axis angle and save the figure in pdf.
478
503
 
479
504
  Parameters
480
505
  ----------
481
506
  key: str
482
- d80_cm, d80_deg, eff_area or eff_flen
507
+ psf_cm, psf_deg, eff_area or eff_flen
483
508
  save: bool
484
509
  If True, figure will be saved.
485
- d80: float
486
- d80 for cumulative PSF plot.
510
+ psf_diameter_cm: float
511
+ PSF diameter value to be marked in the cumulative PSF plot (in cm).
487
512
  **kwargs:
488
513
  kwargs for plt.plot
489
514
 
@@ -533,7 +558,9 @@ class RayTracing:
533
558
  image_cumulative_file_name
534
559
  )
535
560
  self._logger.info(f"Saving cumulative PSF to {image_cumulative_file}")
536
- image.plot_cumulative(file_name=image_cumulative_file, d80=d80)
561
+ image.plot_cumulative(
562
+ file_name=image_cumulative_file, psf_diameter_cm=psf_diameter_cm
563
+ )
537
564
 
538
565
  def plot_histogram(self, key, **kwargs):
539
566
  """
@@ -542,7 +569,7 @@ class RayTracing:
542
569
  Parameters
543
570
  ----------
544
571
  key: str
545
- d80_cm, d80_deg, eff_area or eff_flen
572
+ psf_cm, psf_deg, eff_area or eff_flen
546
573
  **kwargs:
547
574
  kwargs for plt.hist
548
575
 
@@ -564,7 +591,7 @@ class RayTracing:
564
591
  Parameters
565
592
  ----------
566
593
  key: str
567
- d80_cm, d80_deg, eff_area or eff_flen
594
+ psf_cm, psf_deg, eff_area or eff_flen
568
595
 
569
596
  Returns
570
597
  -------
@@ -588,7 +615,7 @@ class RayTracing:
588
615
  Parameters
589
616
  ----------
590
617
  key: str
591
- d80_cm, d80_deg, eff_area or eff_flen
618
+ psf_cm, psf_deg, eff_area or eff_flen
592
619
 
593
620
  Returns
594
621
  -------
@@ -1,26 +1,17 @@
1
1
  """Generate run scripts and directories for CORSIKA simulations."""
2
2
 
3
3
  import logging
4
- import stat
4
+ from pathlib import Path
5
5
 
6
6
  from simtools import settings
7
- from simtools.io import io_handler
8
7
  from simtools.runners.runner_services import RunnerServices
9
8
 
10
9
 
11
- class MissingRequiredEntryInCorsikaConfigError(Exception):
12
- """Exception for missing required entry in corsika config."""
13
-
14
-
15
10
  class CorsikaRunner:
16
11
  """
17
- Generate run scripts and directories for CORSIKA simulations. Run simulations if requested.
18
-
19
- CorsikaRunner is responsible for configuring and running CORSIKA, using corsika_autoinputs
20
- provided by the sim_telarray package. CorsikaRunner generates shell scripts to be run
21
- externally or by the simulator module simulator.
12
+ Prepare and run CORSIKA simulations.
22
13
 
23
- CorsikaRunner is configured through a CorsikaConfig instance.
14
+ Generate run scripts and directories for CORSIKA simulations. Run simulations if requested.
24
15
 
25
16
  Parameters
26
17
  ----------
@@ -28,8 +19,6 @@ class CorsikaRunner:
28
19
  CORSIKA configuration.
29
20
  label: str
30
21
  Instance label.
31
- keep_seeds: bool
32
- Use seeds based on run number and primary particle. If False, use sim_telarray seeds.
33
22
  use_multipipe: bool
34
23
  Use multipipe to run CORSIKA and sim_telarray.
35
24
  curved_atmosphere_min_zenith_angle: Quantity
@@ -40,7 +29,6 @@ class CorsikaRunner:
40
29
  self,
41
30
  corsika_config,
42
31
  label=None,
43
- keep_seeds=False,
44
32
  use_multipipe=False,
45
33
  curved_atmosphere_min_zenith_angle=None,
46
34
  ):
@@ -50,73 +38,63 @@ class CorsikaRunner:
50
38
  self.label = label
51
39
 
52
40
  self.corsika_config = corsika_config
53
- self._keep_seeds = keep_seeds
54
41
  self._use_multipipe = use_multipipe
55
42
  self.curved_atmosphere_min_zenith_angle = curved_atmosphere_min_zenith_angle
56
43
 
57
- self.io_handler = io_handler.IOHandler()
58
-
59
- self.runner_service = RunnerServices(corsika_config, label)
60
- self._directory = self.runner_service.load_data_directories("corsika")
44
+ self.runner_service = RunnerServices(corsika_config, run_type="corsika", label=label)
45
+ self.file_list = None
61
46
 
62
- def prepare_run_script(
63
- self, run_number=None, extra_commands=None, input_file=None, use_pfp=True
64
- ):
47
+ def prepare_run(self, run_number, sub_script, extra_commands=None, corsika_file=None):
65
48
  """
66
- Prepare and write CORSIKA run script.
49
+ Prepare CORSIKA run script and run directory.
50
+
51
+ The CORSIKA run directory includes all input files needed for the simulation.
67
52
 
68
53
  Parameters
69
54
  ----------
70
- use_pfp: bool
71
- Whether to use the preprocessor in preparing the CORSIKA input file
72
55
  run_number: int
73
56
  Run number.
57
+ sub_script: str or Path
58
+ Path to the CORSIKA run script to be created.
59
+ corsika_file: str or Path
60
+ Path to the multipipe script (used only if use_multipipe is True).
74
61
  extra_commands: str
75
62
  Additional commands for running simulations.
76
-
77
- Returns
78
- -------
79
- Path:
80
- Full path of the run script file.
81
63
  """
82
- if input_file is not None:
83
- self._logger.warning(
84
- "input_file parameter is not used in CorsikaRunner.prepare_run_script"
85
- )
86
- self.corsika_config.run_number = run_number
87
-
88
- script_file_path = self.get_file_name(
89
- file_type="sub_script", run_number=self.corsika_config.run_number
90
- )
91
- corsika_input_file = self.corsika_config.generate_corsika_input_file(
92
- use_multipipe=self._use_multipipe, use_test_seeds=self._keep_seeds
64
+ self.file_list = self.runner_service.load_files(run_number=run_number)
65
+
66
+ self.corsika_config.generate_corsika_input_file(
67
+ self._use_multipipe,
68
+ self.runner_service.get_file_name("corsika_input", run_number=run_number),
69
+ self.runner_service.get_file_name("corsika_output", run_number=run_number)
70
+ if not self._use_multipipe
71
+ else corsika_file,
93
72
  )
94
73
 
95
- # CORSIKA input file for a specific run, created by the preprocessor pfp
96
- corsika_input_tmp_name = self.corsika_config.get_corsika_config_file_name(
97
- file_type="config_tmp", run_number=self.corsika_config.run_number
98
- )
99
- corsika_input_tmp_file = self._directory["inputs"].joinpath(corsika_input_tmp_name)
100
- # CORSIKA log file naming (temporary and final)
101
- corsika_log_tmp_file = (
102
- self._directory["data"]
103
- .joinpath(f"run{self.corsika_config.run_number:06}")
104
- .joinpath(f"run{self.corsika_config.run_number}.log")
105
- )
106
- corsika_log_file = self.get_file_name(
107
- file_type="corsika_log", run_number=self.corsika_config.run_number
108
- )
74
+ self._logger.debug(f"Extra commands to be added to the run script: {extra_commands}")
109
75
 
110
- if use_pfp:
111
- pfp_command = self._get_pfp_command(corsika_input_tmp_file, corsika_input_file)
112
- autoinputs_command = self._get_autoinputs_command(
113
- self.corsika_config.run_number, corsika_input_tmp_file
114
- )
76
+ corsika_run_dir = self.runner_service.get_file_name(
77
+ "corsika_output", run_number=run_number
78
+ ).parent
115
79
 
116
- self._logger.debug(f"Extra commands to be added to the run script: {extra_commands}")
117
- self._logger.debug(f"CORSIKA data will be set to {self._directory['data']}")
80
+ self._export_run_script(run_number, sub_script, corsika_run_dir, extra_commands)
118
81
 
119
- with open(script_file_path, "w", encoding="utf-8") as file:
82
+ def _corsika_executable(self):
83
+ """Get the CORSIKA executable path."""
84
+ if self.corsika_config.use_curved_atmosphere:
85
+ self._logger.debug("Using curved-atmosphere CORSIKA binary.")
86
+ return Path(settings.config.corsika_exe_curved)
87
+ self._logger.debug("Using flat-atmosphere CORSIKA binary.")
88
+ return Path(settings.config.corsika_exe)
89
+
90
+ def _export_run_script(self, run_number, sub_script, corsika_run_dir, extra_commands):
91
+ """Export CORSIKA run script."""
92
+ corsika_log_file = self.runner_service.get_file_name(
93
+ "corsika_log", run_number=run_number
94
+ ).with_suffix("") # remove .gz from log file
95
+ corsika_input = self.runner_service.get_file_name("corsika_input", run_number=run_number)
96
+ sub_script = Path(sub_script)
97
+ with open(sub_script, "w", encoding="utf-8") as file:
120
98
  file.write("#!/usr/bin/env bash\n")
121
99
  file.write("set -e\n")
122
100
  file.write("set -o pipefail\n")
@@ -129,136 +107,19 @@ class CorsikaRunner:
129
107
  file.write(f"{extra_commands}\n")
130
108
  file.write("# End of extras\n\n")
131
109
 
132
- file.write(f"export CORSIKA_DATA={self._directory['data']}\n")
110
+ file.write(f"export CORSIKA_DATA={corsika_run_dir}\n")
133
111
  file.write('mkdir -p "$CORSIKA_DATA"\n')
134
112
  file.write('cd "$CORSIKA_DATA" || exit 2\n')
135
- if use_pfp:
136
- file.write("\n# Running pfp\n")
137
- file.write(pfp_command)
138
- file.write("\n# Replacing the XXXXXX placeholder with the run number\n")
139
- file.write(
140
- f"sed -i 's/XXXXXX/{self.corsika_config.run_number:06}/g' "
141
- f"{corsika_input_tmp_file}\n"
142
- )
143
- else:
144
- file.write("\n# Copying CORSIKA input file to run location\n")
145
- file.write(f"cp {corsika_input_file} {corsika_input_tmp_file}")
146
- file.write("\n# Running corsika_autoinputs\n")
147
- file.write(autoinputs_command)
148
- file.write("\n# Moving log files to the corsika log directory\n")
149
- file.write(f"gzip {corsika_log_tmp_file}\n")
150
- file.write(f"mv -v {corsika_log_tmp_file}.gz {corsika_log_file}\n")
151
-
152
- file.write('\necho "RUNTIME: $SECONDS"\n')
153
-
154
- script_file_path.chmod(script_file_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP)
155
- return script_file_path
156
113
 
157
- def get_resources(self, run_number=None):
158
- """Return computing resources used."""
159
- return self.runner_service.get_resources(run_number)
160
-
161
- def _get_pfp_command(self, input_tmp_file, corsika_input_file):
162
- """
163
- Get pfp pre-processor command.
164
-
165
- pfp is a pre-processor tool and part of sim_telarray.
166
-
167
- Parameters
168
- ----------
169
- input_tmp_file: Path
170
- Temporary input file.
171
-
172
- Returns
173
- -------
174
- str
175
- pfp command.
176
- """
177
- cmd = settings.config.sim_telarray_path / "bin/pfp"
178
- cmd = str(cmd) + f" -V -DWITHOUT_MULTIPIPE - < {corsika_input_file}"
179
- cmd += f" > {input_tmp_file} || exit\n"
180
- return cmd
181
-
182
- def _get_autoinputs_command(self, run_number, input_tmp_file):
183
- """
184
- Get autoinputs command.
185
-
186
- corsika_autoinputs is a tool to generate random seeds and user/host dependent
187
- parameters for CORSIKA configuration.
188
-
189
- Parameters
190
- ----------
191
- run_number: int
192
- Run number.
193
- input_tmp_file: Path
194
- Temporary input file.
195
-
196
- Returns
197
- -------
198
- str
199
- autoinputs command.
200
- """
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.")
207
-
208
- log_file = self.get_file_name(file_type="log", run_number=run_number)
209
- if self._use_multipipe:
210
- log_file = log_file.with_name(f"multipipe_{log_file.name}")
211
-
212
- cmd = settings.config.sim_telarray_path.joinpath("bin/corsika_autoinputs")
213
- cmd = str(cmd) + f" --run {corsika_bin_path}"
214
- cmd += f" -R {run_number}"
215
- cmd += ' -p "$CORSIKA_DATA"'
216
- if self._keep_seeds:
217
- logging.warning(
218
- "Using --keep-seeds option in corsika_autoinputs is not recommended. "
219
- "It should only be used for testing purposes."
114
+ file.write("\n# Running corsika\n")
115
+ file.write(
116
+ f"{self._corsika_executable()} < {corsika_input} > {corsika_log_file} 2>&1\n"
220
117
  )
221
- cmd += " --keep-seeds"
222
- cmd += f" {input_tmp_file} | gzip > {log_file} 2>&1"
223
- cmd += " || exit 1\n"
224
- return cmd
118
+ file.write("\n# Cleanup\n")
119
+ file.write(f"gzip {corsika_log_file}\n")
225
120
 
226
- def get_file_name(
227
- self,
228
- simulation_software="corsika",
229
- file_type=None,
230
- run_number=None,
231
- mode="",
232
- model_version_index=0,
233
- ):
234
- """
235
- Get the full path of a file for a given run number.
236
-
237
- Parameters
238
- ----------
239
- simulation_software: str
240
- Simulation software.
241
- file_type: str
242
- File type.
243
- run_number: int
244
- Run number.
245
- model_version_index: int
246
- Index of the model version.
247
- This is used to select the correct simulator_array instance in case
248
- multiple array models are simulated.
121
+ file.write('\necho "RUNTIME: $SECONDS"\n')
249
122
 
250
- Returns
251
- -------
252
- str
253
- File name with full path.
254
- """
255
- if simulation_software.lower() != "corsika":
256
- raise ValueError(
257
- f"simulation_software ({simulation_software}) is not supported in CorsikaRunner"
258
- )
259
- return self.runner_service.get_file_name(
260
- file_type=file_type,
261
- run_number=run_number,
262
- mode=mode,
263
- _model_version_index=model_version_index,
264
- )
123
+ def get_resources(self, sub_out_file):
124
+ """Return computing resources used."""
125
+ return self.runner_service.get_resources(sub_out_file)