gammasimtools 0.25.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.
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.26.0.dist-info}/METADATA +2 -1
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.26.0.dist-info}/RECORD +122 -121
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.26.0.dist-info}/entry_points.txt +2 -1
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.26.0.dist-info}/licenses/LICENSE +1 -1
- simtools/_version.py +2 -2
- simtools/application_control.py +35 -7
- simtools/applications/calculate_incident_angles.py +0 -2
- simtools/applications/convert_geo_coordinates_of_array_elements.py +1 -2
- simtools/applications/db_add_file_to_db.py +1 -1
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +1 -1
- simtools/applications/db_add_value_from_json_to_db.py +1 -1
- simtools/applications/db_generate_compound_indexes.py +1 -1
- simtools/applications/db_get_array_layouts_from_db.py +2 -6
- simtools/applications/db_get_file_from_db.py +1 -1
- simtools/applications/db_get_parameter_from_db.py +1 -1
- simtools/applications/db_inspect_databases.py +1 -1
- simtools/applications/db_upload_model_repository.py +1 -1
- simtools/applications/derive_ctao_array_layouts.py +1 -2
- simtools/applications/derive_mirror_rnda.py +1 -3
- simtools/applications/derive_psf_parameters.py +0 -1
- simtools/applications/derive_pulse_shape_parameters.py +0 -1
- simtools/applications/derive_trigger_rates.py +1 -1
- simtools/applications/docs_produce_array_element_report.py +2 -8
- simtools/applications/docs_produce_calibration_reports.py +1 -3
- simtools/applications/docs_produce_model_parameter_reports.py +0 -2
- simtools/applications/docs_produce_simulation_configuration_report.py +1 -3
- simtools/applications/generate_array_config.py +0 -1
- simtools/applications/generate_corsika_histograms.py +48 -235
- simtools/applications/generate_regular_arrays.py +5 -35
- simtools/applications/generate_simtel_event_data.py +2 -2
- simtools/applications/maintain_simulation_model_add_production.py +2 -2
- simtools/applications/maintain_simulation_model_write_array_element_positions.py +87 -0
- simtools/applications/plot_array_layout.py +5 -111
- simtools/applications/plot_simulated_event_distributions.py +57 -0
- simtools/applications/plot_tabular_data.py +0 -1
- simtools/applications/plot_tabular_data_for_model_parameter.py +1 -6
- simtools/applications/production_derive_corsika_limits.py +1 -1
- simtools/applications/production_generate_grid.py +0 -1
- simtools/applications/run_application.py +1 -1
- simtools/applications/simulate_flasher.py +0 -2
- simtools/applications/simulate_illuminator.py +0 -1
- simtools/applications/simulate_pedestals.py +1 -5
- simtools/applications/simulate_prod.py +1 -5
- simtools/applications/simulate_prod_htcondor_generator.py +1 -1
- simtools/applications/submit_array_layouts.py +2 -4
- simtools/applications/submit_model_parameter_from_external.py +1 -3
- simtools/applications/validate_camera_efficiency.py +0 -1
- simtools/applications/validate_camera_fov.py +0 -1
- simtools/applications/validate_cumulative_psf.py +0 -2
- simtools/applications/validate_optics.py +0 -13
- simtools/camera/camera_efficiency.py +1 -6
- simtools/camera/single_photon_electron_spectrum.py +2 -1
- simtools/configuration/commandline_parser.py +35 -2
- simtools/configuration/configurator.py +6 -11
- simtools/corsika/corsika_config.py +16 -21
- simtools/corsika/corsika_histograms.py +411 -1735
- simtools/corsika/primary_particle.py +1 -1
- simtools/data_model/metadata_collector.py +5 -2
- simtools/data_model/metadata_model.py +0 -4
- simtools/data_model/model_data_writer.py +13 -15
- simtools/data_model/validate_data.py +1 -3
- simtools/db/db_handler.py +19 -8
- simtools/dependencies.py +81 -38
- simtools/io/ascii_handler.py +4 -2
- simtools/io/table_handler.py +1 -1
- simtools/layout/array_layout.py +4 -12
- simtools/layout/array_layout_utils.py +226 -57
- simtools/model/array_model.py +1 -13
- simtools/model/calibration_model.py +0 -4
- simtools/model/legacy_model_parameter.py +134 -0
- simtools/model/model_parameter.py +24 -13
- simtools/model/model_utils.py +1 -6
- simtools/model/site_model.py +0 -4
- simtools/model/telescope_model.py +6 -11
- simtools/production_configuration/derive_corsika_limits.py +6 -11
- simtools/production_configuration/interpolation_handler.py +16 -16
- simtools/ray_tracing/incident_angles.py +5 -11
- simtools/ray_tracing/mirror_panel_psf.py +3 -7
- simtools/ray_tracing/psf_analysis.py +18 -19
- simtools/ray_tracing/psf_parameter_optimisation.py +0 -1
- simtools/ray_tracing/ray_tracing.py +6 -15
- simtools/reporting/docs_auto_report_generator.py +8 -13
- simtools/reporting/docs_read_parameters.py +2 -8
- simtools/runners/corsika_runner.py +5 -9
- simtools/runners/corsika_simtel_runner.py +3 -8
- simtools/runners/simtel_runner.py +0 -5
- simtools/runners/simtools_runner.py +2 -4
- simtools/settings.py +154 -0
- simtools/{io/eventio_handler.py → sim_events/file_info.py} +3 -3
- simtools/{simtel/simtel_io_event_histograms.py → sim_events/histograms.py} +25 -15
- simtools/{simtel/simtel_io_event_reader.py → sim_events/reader.py} +20 -17
- simtools/{simtel/simtel_io_event_writer.py → sim_events/writer.py} +84 -25
- simtools/simtel/pulse_shapes.py +7 -2
- simtools/simtel/simtel_config_writer.py +79 -36
- simtools/simtel/simtel_table_reader.py +6 -4
- simtools/simtel/simulator_array.py +4 -11
- simtools/simtel/simulator_camera_efficiency.py +4 -6
- simtools/simtel/simulator_light_emission.py +69 -24
- simtools/simtel/simulator_ray_tracing.py +4 -10
- simtools/simulator.py +7 -14
- simtools/telescope_trigger_rates.py +3 -4
- simtools/testing/assertions.py +84 -33
- simtools/testing/configuration.py +1 -2
- simtools/testing/helpers.py +2 -3
- simtools/testing/log_inspector.py +1 -0
- simtools/testing/sim_telarray_metadata.py +1 -1
- simtools/testing/validate_output.py +34 -23
- simtools/utils/general.py +37 -0
- simtools/utils/geometry.py +0 -77
- simtools/utils/names.py +5 -5
- simtools/visualization/legend_handlers.py +7 -6
- simtools/visualization/plot_array_layout.py +91 -16
- simtools/visualization/plot_corsika_histograms.py +143 -605
- simtools/visualization/plot_mirrors.py +1 -4
- simtools/visualization/plot_pixels.py +2 -4
- simtools/visualization/plot_psf.py +0 -1
- simtools/visualization/plot_simtel_event_histograms.py +4 -4
- simtools/visualization/plot_simtel_events.py +6 -11
- simtools/visualization/plot_tables.py +8 -19
- simtools/visualization/visualize.py +22 -2
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +0 -160
- simtools/applications/print_version.py +0 -53
- simtools/io/hdf5_handler.py +0 -139
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.26.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.26.0.dist-info}/top_level.txt +0 -0
|
@@ -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,
|
|
29
|
+
def __init__(self, args, output_path):
|
|
30
30
|
"""Initialise class."""
|
|
31
31
|
self._logger = logging.getLogger(__name__)
|
|
32
|
-
self.db = db_handler.DatabaseHandler(
|
|
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)
|
|
@@ -109,7 +108,6 @@ class ReadParameters:
|
|
|
109
108
|
plot_pixels.plot(
|
|
110
109
|
config=plot_config,
|
|
111
110
|
output_file=Path(f"{outpath}/{plot_name}"),
|
|
112
|
-
db_config=self.db_config,
|
|
113
111
|
)
|
|
114
112
|
plot_names.append(plot_name)
|
|
115
113
|
else:
|
|
@@ -142,7 +140,6 @@ class ReadParameters:
|
|
|
142
140
|
plot_mirrors.plot(
|
|
143
141
|
config=plot_config,
|
|
144
142
|
output_file=Path(f"{outpath}/{plot_name}"),
|
|
145
|
-
db_config=self.db_config,
|
|
146
143
|
)
|
|
147
144
|
plot_names.append(plot_name)
|
|
148
145
|
else:
|
|
@@ -165,7 +162,6 @@ class ReadParameters:
|
|
|
165
162
|
telescope=tel,
|
|
166
163
|
output_path=outpath,
|
|
167
164
|
plot_type="all",
|
|
168
|
-
db_config=self.db_config,
|
|
169
165
|
)
|
|
170
166
|
|
|
171
167
|
if not config_data:
|
|
@@ -180,7 +176,6 @@ class ReadParameters:
|
|
|
180
176
|
plot_tables.plot(
|
|
181
177
|
config=plot_config,
|
|
182
178
|
output_file=image_output_file,
|
|
183
|
-
db_config=self.db_config,
|
|
184
179
|
)
|
|
185
180
|
plt.close("all")
|
|
186
181
|
|
|
@@ -582,7 +577,6 @@ class ReadParameters:
|
|
|
582
577
|
telescope_name=self.array_element,
|
|
583
578
|
model_version=self.model_version,
|
|
584
579
|
label="reports",
|
|
585
|
-
db_config=self.db_config,
|
|
586
580
|
ignore_software_version=True,
|
|
587
581
|
)
|
|
588
582
|
|
|
@@ -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,8 +26,6 @@ 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
|
|
@@ -41,7 +39,6 @@ class CorsikaRunner:
|
|
|
41
39
|
def __init__(
|
|
42
40
|
self,
|
|
43
41
|
corsika_config,
|
|
44
|
-
simtel_path,
|
|
45
42
|
label=None,
|
|
46
43
|
keep_seeds=False,
|
|
47
44
|
use_multipipe=False,
|
|
@@ -57,7 +54,6 @@ class CorsikaRunner:
|
|
|
57
54
|
self._use_multipipe = use_multipipe
|
|
58
55
|
self.curved_atmosphere_min_zenith_angle = curved_atmosphere_min_zenith_angle
|
|
59
56
|
|
|
60
|
-
self._simtel_path = Path(simtel_path)
|
|
61
57
|
self.io_handler = io_handler.IOHandler()
|
|
62
58
|
|
|
63
59
|
self.runner_service = RunnerServices(corsika_config, label)
|
|
@@ -178,7 +174,7 @@ class CorsikaRunner:
|
|
|
178
174
|
str
|
|
179
175
|
pfp command.
|
|
180
176
|
"""
|
|
181
|
-
cmd =
|
|
177
|
+
cmd = settings.config.sim_telarray_path / "bin/pfp"
|
|
182
178
|
cmd = str(cmd) + f" -V -DWITHOUT_MULTIPIPE - < {corsika_input_file}"
|
|
183
179
|
cmd += f" > {input_tmp_file} || exit\n"
|
|
184
180
|
return cmd
|
|
@@ -203,17 +199,17 @@ class CorsikaRunner:
|
|
|
203
199
|
autoinputs command.
|
|
204
200
|
"""
|
|
205
201
|
if self.corsika_config.use_curved_atmosphere:
|
|
206
|
-
corsika_bin_path =
|
|
202
|
+
corsika_bin_path = settings.config.corsika_exe_curved
|
|
207
203
|
self._logger.debug("Using curved-atmosphere CORSIKA binary.")
|
|
208
204
|
else:
|
|
209
|
-
corsika_bin_path =
|
|
205
|
+
corsika_bin_path = settings.config.corsika_exe
|
|
210
206
|
self._logger.debug("Using flat-atmosphere CORSIKA binary.")
|
|
211
207
|
|
|
212
208
|
log_file = self.get_file_name(file_type="log", run_number=run_number)
|
|
213
209
|
if self._use_multipipe:
|
|
214
210
|
log_file = log_file.with_name(f"multipipe_{log_file.name}")
|
|
215
211
|
|
|
216
|
-
cmd =
|
|
212
|
+
cmd = settings.config.sim_telarray_path.joinpath("bin/corsika_autoinputs")
|
|
217
213
|
cmd = str(cmd) + f" --run {corsika_bin_path}"
|
|
218
214
|
cmd += f" -R {run_number}"
|
|
219
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,7 +37,6 @@ 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,
|
|
@@ -52,7 +50,6 @@ class CorsikaSimtelRunner:
|
|
|
52
50
|
# the base corsika config is the one used to define the CORSIKA specific parameters.
|
|
53
51
|
# The others are used for the array configurations.
|
|
54
52
|
self.base_corsika_config = self.corsika_config[0]
|
|
55
|
-
self._simtel_path = simtel_path
|
|
56
53
|
self.sim_telarray_seeds = sim_telarray_seeds
|
|
57
54
|
self.label = label
|
|
58
55
|
self.sequential = "--sequential" if sequential else ""
|
|
@@ -60,7 +57,6 @@ class CorsikaSimtelRunner:
|
|
|
60
57
|
self.base_corsika_config.set_output_file_and_directory(use_multipipe)
|
|
61
58
|
self.corsika_runner = CorsikaRunner(
|
|
62
59
|
corsika_config=self.base_corsika_config,
|
|
63
|
-
simtel_path=simtel_path,
|
|
64
60
|
label=label,
|
|
65
61
|
keep_seeds=keep_seeds,
|
|
66
62
|
use_multipipe=use_multipipe,
|
|
@@ -73,7 +69,6 @@ class CorsikaSimtelRunner:
|
|
|
73
69
|
self.simulator_array.append(
|
|
74
70
|
SimulatorArray(
|
|
75
71
|
corsika_config=_corsika_config,
|
|
76
|
-
simtel_path=simtel_path,
|
|
77
72
|
label=label,
|
|
78
73
|
use_multipipe=use_multipipe,
|
|
79
74
|
sim_telarray_seeds=sim_telarray_seeds,
|
|
@@ -171,8 +166,8 @@ class CorsikaSimtelRunner:
|
|
|
171
166
|
"run_cta_multipipe"
|
|
172
167
|
)
|
|
173
168
|
with open(multipipe_script, "w", encoding="utf-8") as file:
|
|
174
|
-
multipipe_command =
|
|
175
|
-
f"
|
|
169
|
+
multipipe_command = settings.config.sim_telarray_path.joinpath(
|
|
170
|
+
f"bin/multipipe_corsika -c {multipipe_file} {self.sequential} "
|
|
176
171
|
"|| echo 'Fan-out failed'"
|
|
177
172
|
)
|
|
178
173
|
file.write(f"{multipipe_command}")
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import subprocess
|
|
5
|
-
from pathlib import Path
|
|
6
5
|
|
|
7
6
|
import simtools.utils.general as gen
|
|
8
7
|
from simtools.runners.runner_services import RunnerServices
|
|
@@ -25,8 +24,6 @@ class SimtelRunner:
|
|
|
25
24
|
|
|
26
25
|
Parameters
|
|
27
26
|
----------
|
|
28
|
-
simtel_path: str or Path
|
|
29
|
-
Location of sim_telarray installation.
|
|
30
27
|
label: str
|
|
31
28
|
Instance label. Important for output file naming.
|
|
32
29
|
corsika_config: CorsikaConfig
|
|
@@ -39,7 +36,6 @@ class SimtelRunner:
|
|
|
39
36
|
|
|
40
37
|
def __init__(
|
|
41
38
|
self,
|
|
42
|
-
simtel_path,
|
|
43
39
|
label=None,
|
|
44
40
|
corsika_config=None,
|
|
45
41
|
use_multipipe=False,
|
|
@@ -48,7 +44,6 @@ class SimtelRunner:
|
|
|
48
44
|
"""Initialize SimtelRunner."""
|
|
49
45
|
self._logger = logging.getLogger(__name__)
|
|
50
46
|
|
|
51
|
-
self._simtel_path = Path(simtel_path)
|
|
52
47
|
self.label = label
|
|
53
48
|
self._base_directory = None
|
|
54
49
|
self.calibration_run_mode = calibration_run_mode
|
|
@@ -9,7 +9,7 @@ from simtools import dependencies
|
|
|
9
9
|
from simtools.io import ascii_handler
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def run_applications(args_dict,
|
|
12
|
+
def run_applications(args_dict, logger):
|
|
13
13
|
"""
|
|
14
14
|
Run simtools applications step-by-step as defined in a configuration file.
|
|
15
15
|
|
|
@@ -17,8 +17,6 @@ def run_applications(args_dict, db_config, logger):
|
|
|
17
17
|
----------
|
|
18
18
|
args_dict : dict
|
|
19
19
|
Dictionary containing command line arguments.
|
|
20
|
-
db_config : dict
|
|
21
|
-
Database configuration
|
|
22
20
|
logger : logging.Logger
|
|
23
21
|
Logger for logging application output.
|
|
24
22
|
"""
|
|
@@ -33,7 +31,7 @@ def run_applications(args_dict, db_config, logger):
|
|
|
33
31
|
|
|
34
32
|
with log_file.open("w", encoding="utf-8") as file:
|
|
35
33
|
file.write("Running simtools applications\n")
|
|
36
|
-
file.write(dependencies.get_version_string(
|
|
34
|
+
file.write(dependencies.get_version_string(run_time))
|
|
37
35
|
|
|
38
36
|
for config in configurations:
|
|
39
37
|
app = config.get("application")
|
simtools/settings.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Centralized settings object with command line and environment variables."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from types import MappingProxyType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _Config:
|
|
9
|
+
"""Centralized settings object with command line and environment variables."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize empty config."""
|
|
13
|
+
self._args = {}
|
|
14
|
+
self._db_config = {}
|
|
15
|
+
self._sim_telarray_path = None
|
|
16
|
+
self._sim_telarray_exe = None
|
|
17
|
+
self._corsika_path = None
|
|
18
|
+
self._corsika_exe = None
|
|
19
|
+
|
|
20
|
+
def load(self, args=None, db_config=None):
|
|
21
|
+
"""
|
|
22
|
+
Load configuration from command line arguments and environment variables.
|
|
23
|
+
|
|
24
|
+
For paths, first check for environment variables, then command line arguments.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
args : dict, optional
|
|
29
|
+
Command line arguments.
|
|
30
|
+
db_config : dict, optional
|
|
31
|
+
Database configuration.
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
self._args = MappingProxyType(args) if args is not None else {}
|
|
35
|
+
self._db_config = MappingProxyType(db_config) if db_config is not None else {}
|
|
36
|
+
self._sim_telarray_path = (
|
|
37
|
+
args.get("sim_telarray_path")
|
|
38
|
+
if args is not None and "sim_telarray_path" in args
|
|
39
|
+
else os.getenv("SIMTOOLS_SIM_TELARRAY_PATH")
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
self._sim_telarray_exe = (
|
|
43
|
+
args.get("sim_telarray_executable")
|
|
44
|
+
if args is not None and "sim_telarray_executable" in args
|
|
45
|
+
else os.getenv("SIMTOOLS_SIM_TELARRAY_EXECUTABLE", "sim_telarray")
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
self._corsika_path = (
|
|
49
|
+
args.get("corsika_path")
|
|
50
|
+
if args is not None and "corsika_path" in args
|
|
51
|
+
else os.getenv("SIMTOOLS_CORSIKA_PATH")
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
self._corsika_exe = self._get_corsika_exec() if self._corsika_path is not None else None
|
|
55
|
+
|
|
56
|
+
def _get_corsika_exec(self):
|
|
57
|
+
"""
|
|
58
|
+
Get the CORSIKA executable from environment variable or command line argument.
|
|
59
|
+
|
|
60
|
+
Build the executable name based on configured interaction models. Fall back to
|
|
61
|
+
legacy naming (simply "corsika") if models are not specified.
|
|
62
|
+
"""
|
|
63
|
+
he_model = (
|
|
64
|
+
self._args.get("corsika_he_interaction")
|
|
65
|
+
if self._args is not None and "corsika_he_interaction" in self._args
|
|
66
|
+
else os.getenv("SIMTOOLS_CORSIKA_HE_INTERACTION")
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
le_model = (
|
|
70
|
+
self._args.get("corsika_le_interaction")
|
|
71
|
+
if self._args is not None and "corsika_le_interaction" in self._args
|
|
72
|
+
else os.getenv("SIMTOOLS_CORSIKA_LE_INTERACTION")
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if he_model and le_model:
|
|
76
|
+
corsika_exe = self.corsika_path / f"corsika_{he_model}_{le_model}_flat"
|
|
77
|
+
if corsika_exe.exists():
|
|
78
|
+
return corsika_exe
|
|
79
|
+
|
|
80
|
+
# legacy naming
|
|
81
|
+
return self.corsika_path / "corsika"
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def args(self):
|
|
85
|
+
"""Command line arguments."""
|
|
86
|
+
return self._args
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def db_config(self):
|
|
90
|
+
"""Database configuration."""
|
|
91
|
+
return self._db_config
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def sim_telarray_path(self):
|
|
95
|
+
"""Path to the sim_telarray installation directory."""
|
|
96
|
+
return Path(self._sim_telarray_path) if self._sim_telarray_path is not None else None
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def sim_telarray_exe(self):
|
|
100
|
+
"""Path to the sim_telarray executable."""
|
|
101
|
+
return (
|
|
102
|
+
Path(self._sim_telarray_path) / "bin" / self._sim_telarray_exe
|
|
103
|
+
if self._sim_telarray_path is not None
|
|
104
|
+
else None
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def sim_telarray_exe_debug_trace(self):
|
|
109
|
+
"""Path to the debug trace version of the sim_telarray executable."""
|
|
110
|
+
return (
|
|
111
|
+
Path(self._sim_telarray_path) / "bin" / (self._sim_telarray_exe + "_debug_trace")
|
|
112
|
+
if self._sim_telarray_path is not None
|
|
113
|
+
else None
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def corsika_path(self):
|
|
118
|
+
"""Path to the CORSIKA installation directory."""
|
|
119
|
+
return Path(self._corsika_path) if self._corsika_path is not None else None
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def corsika_exe(self):
|
|
123
|
+
"""Path to the CORSIKA executable."""
|
|
124
|
+
return (
|
|
125
|
+
Path(self._corsika_path) / self._corsika_exe if self._corsika_path is not None else None
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def corsika_exe_curved(self):
|
|
130
|
+
"""Path to the curved version of the CORSIKA executable."""
|
|
131
|
+
if self._corsika_exe is None:
|
|
132
|
+
return None
|
|
133
|
+
corsika_curved = (
|
|
134
|
+
self._corsika_exe.name.replace("_flat", "_curved")
|
|
135
|
+
if "_flat" in self._corsika_exe.name
|
|
136
|
+
else self._corsika_exe.name + "-curved" # legacy naming convention
|
|
137
|
+
)
|
|
138
|
+
return Path(self._corsika_path) / corsika_curved if self._corsika_path is not None else None
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def corsika_dummy_file(self):
|
|
142
|
+
"""
|
|
143
|
+
Path to a dummy CORSIKA file required by sim_telarray for ray-tracing simulations.
|
|
144
|
+
|
|
145
|
+
This file does not need to exist; sim_telarray only requires a file path.
|
|
146
|
+
"""
|
|
147
|
+
return (
|
|
148
|
+
self.sim_telarray_path / "run9991.corsika.gz"
|
|
149
|
+
if self._sim_telarray_path is not None
|
|
150
|
+
else None
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
config = _Config()
|
|
@@ -24,7 +24,7 @@ def get_corsika_run_number(file):
|
|
|
24
24
|
int, None
|
|
25
25
|
CORSIKA run number. Returns None if not found.
|
|
26
26
|
"""
|
|
27
|
-
run_header =
|
|
27
|
+
run_header = get_combined_eventio_run_header(file)
|
|
28
28
|
if run_header and "run" in run_header:
|
|
29
29
|
return run_header["run"]
|
|
30
30
|
run_header, _ = get_corsika_run_and_event_headers(file)
|
|
@@ -34,9 +34,9 @@ def get_corsika_run_number(file):
|
|
|
34
34
|
return None
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def
|
|
37
|
+
def get_combined_eventio_run_header(sim_telarray_file):
|
|
38
38
|
"""
|
|
39
|
-
Return the CORSIKA run header information from an sim_telarray file.
|
|
39
|
+
Return the CORSIKA run header information from an eventio (sim_telarray) file.
|
|
40
40
|
|
|
41
41
|
Reads both RunHeader and MCRunHeader object from file and returns a merged dictionary.
|
|
42
42
|
Adds primary id from the first event.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Histograms for shower and triggered events."""
|
|
1
|
+
"""Histograms for shower and (if available) triggered events."""
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
4
|
import logging
|
|
@@ -6,12 +6,12 @@ import logging
|
|
|
6
6
|
import astropy.units as u
|
|
7
7
|
import numpy as np
|
|
8
8
|
|
|
9
|
-
from simtools.
|
|
9
|
+
from simtools.sim_events.reader import EventDataReader
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class
|
|
12
|
+
class EventDataHistograms:
|
|
13
13
|
"""
|
|
14
|
-
Generate and fill histograms for shower and triggered events.
|
|
14
|
+
Generate and fill histograms for shower and (if available) triggered events.
|
|
15
15
|
|
|
16
16
|
Event data is read from the reduced MC event data file.
|
|
17
17
|
Calculate cumulative and relative (efficiency) distributions.
|
|
@@ -35,7 +35,7 @@ class SimtelIOEventHistograms:
|
|
|
35
35
|
self.histograms = {}
|
|
36
36
|
self.file_info = {}
|
|
37
37
|
|
|
38
|
-
self.reader =
|
|
38
|
+
self.reader = EventDataReader(event_data_file, telescope_list=telescope_list)
|
|
39
39
|
|
|
40
40
|
def fill(self):
|
|
41
41
|
"""
|
|
@@ -63,12 +63,10 @@ class SimtelIOEventHistograms:
|
|
|
63
63
|
|
|
64
64
|
self.histograms = self._define_histograms(event_data, triggered_data, shower_data)
|
|
65
65
|
|
|
66
|
-
for
|
|
67
|
-
self._logger.debug(f"Filling histogram {name}")
|
|
66
|
+
for data in self.histograms.values():
|
|
68
67
|
self._fill_histogram_and_bin_edges(data)
|
|
69
68
|
|
|
70
69
|
self.print_summary()
|
|
71
|
-
|
|
72
70
|
self.calculate_efficiency_data()
|
|
73
71
|
self.calculate_cumulative_data()
|
|
74
72
|
|
|
@@ -202,11 +200,14 @@ class SimtelIOEventHistograms:
|
|
|
202
200
|
Adds to existing histogram if present, otherwise initializes it.
|
|
203
201
|
"""
|
|
204
202
|
if data["1d"]:
|
|
203
|
+
if data["event_data"] is None:
|
|
204
|
+
return
|
|
205
205
|
hist, _ = np.histogram(
|
|
206
|
-
getattr(data["event_data"], data["event_data_column"]),
|
|
207
|
-
bins=data["bin_edges"],
|
|
206
|
+
getattr(data["event_data"], data["event_data_column"]), bins=data["bin_edges"]
|
|
208
207
|
)
|
|
209
208
|
else:
|
|
209
|
+
if data["event_data"][0] is None or data["event_data"][1] is None:
|
|
210
|
+
return
|
|
210
211
|
hist, _, _ = np.histogram2d(
|
|
211
212
|
getattr(data["event_data"][0], data["event_data_column"][0]),
|
|
212
213
|
getattr(data["event_data"][1], data["event_data_column"][1]),
|
|
@@ -227,6 +228,8 @@ class SimtelIOEventHistograms:
|
|
|
227
228
|
dict
|
|
228
229
|
Dictionary containing the efficiency histograms.
|
|
229
230
|
"""
|
|
231
|
+
if not any(isinstance(ds, dict) and "TRIGGERS" in ds for ds in self.reader.data_sets):
|
|
232
|
+
return None
|
|
230
233
|
|
|
231
234
|
def calculate_efficiency(trig_hist, mc_hist):
|
|
232
235
|
with np.errstate(divide="ignore", invalid="ignore"):
|
|
@@ -295,11 +298,15 @@ class SimtelIOEventHistograms:
|
|
|
295
298
|
"""Return bins for the viewcone histogram."""
|
|
296
299
|
if "viewcone_bin_edges" in self.histograms:
|
|
297
300
|
return self.histograms["viewcone_bin_edges"]
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
|
|
302
|
+
viewcone_min = self.file_info.get("viewcone_min", 0.0 * u.deg).to("deg").value
|
|
303
|
+
viewcone_max = self.file_info.get("viewcone_max", 20.0 * u.deg).to("deg").value
|
|
304
|
+
|
|
305
|
+
# avoid zero-width bins
|
|
306
|
+
if viewcone_min == viewcone_max:
|
|
307
|
+
viewcone_max = viewcone_min + 0.5
|
|
308
|
+
|
|
309
|
+
return np.linspace(viewcone_min, viewcone_max, 100)
|
|
303
310
|
|
|
304
311
|
def calculate_cumulative_data(self):
|
|
305
312
|
"""
|
|
@@ -310,6 +317,9 @@ class SimtelIOEventHistograms:
|
|
|
310
317
|
dict
|
|
311
318
|
Dictionary containing the cumulative histograms.
|
|
312
319
|
"""
|
|
320
|
+
if not any(isinstance(ds, dict) and "TRIGGERS" in ds for ds in self.reader.data_sets):
|
|
321
|
+
return None
|
|
322
|
+
|
|
313
323
|
cumulative_data = {}
|
|
314
324
|
suffix = "_cumulative"
|
|
315
325
|
|
|
@@ -44,11 +44,11 @@ class TriggeredEventData:
|
|
|
44
44
|
angular_distance: list[float] = field(default_factory=list)
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
class
|
|
47
|
+
class EventDataReader:
|
|
48
48
|
"""Read reduced MC data set stored in astropy tables."""
|
|
49
49
|
|
|
50
50
|
def __init__(self, event_data_file, telescope_list=None):
|
|
51
|
-
"""Initialize
|
|
51
|
+
"""Initialize EventDataReader."""
|
|
52
52
|
self._logger = logging.getLogger(__name__)
|
|
53
53
|
self.telescope_list = telescope_list
|
|
54
54
|
|
|
@@ -61,7 +61,7 @@ class SimtelIOEventDataReader:
|
|
|
61
61
|
|
|
62
62
|
Rearrange dictionary with tables names into a list of dictionaries
|
|
63
63
|
under the assumption that the file contains the tables "SHOWERS",
|
|
64
|
-
"TRIGGERS", and "FILE_INFO".
|
|
64
|
+
"TRIGGERS", and "FILE_INFO". Note that not all tables need to be present.
|
|
65
65
|
|
|
66
66
|
Parameters
|
|
67
67
|
----------
|
|
@@ -88,13 +88,13 @@ class SimtelIOEventDataReader:
|
|
|
88
88
|
except (ValueError, AttributeError):
|
|
89
89
|
sorted_indices = [0] # Handle the case where the key is only "SHOWERS"
|
|
90
90
|
for i in sorted_indices:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
)
|
|
91
|
+
entry = {
|
|
92
|
+
"SHOWERS": dataset_dict["SHOWERS"][i],
|
|
93
|
+
"FILE_INFO": dataset_dict["FILE_INFO"][i],
|
|
94
|
+
}
|
|
95
|
+
if i < len(dataset_dict["TRIGGERS"]) and dataset_dict["TRIGGERS"][i]:
|
|
96
|
+
entry["TRIGGERS"] = dataset_dict["TRIGGERS"][i]
|
|
97
|
+
data_sets.append(entry)
|
|
98
98
|
|
|
99
99
|
return data_sets
|
|
100
100
|
|
|
@@ -248,20 +248,23 @@ class SimtelIOEventDataReader:
|
|
|
248
248
|
tuple
|
|
249
249
|
A tuple with file info table, shower, triggered shower, and triggered event data.
|
|
250
250
|
"""
|
|
251
|
-
table_name_map = table_name_map or {}
|
|
252
251
|
|
|
253
|
-
def get_name(
|
|
254
|
-
return table_name_map.get(
|
|
252
|
+
def get_name(k):
|
|
253
|
+
return k if table_name_map is None else table_name_map.get(k)
|
|
255
254
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
)
|
|
255
|
+
table_names = [
|
|
256
|
+
name for k in ("SHOWERS", "TRIGGERS", "FILE_INFO") if (name := get_name(k)) is not None
|
|
257
|
+
]
|
|
258
|
+
tables = table_handler.read_tables(event_data_file, table_names=table_names)
|
|
260
259
|
self.reduced_file_info = self.get_reduced_simulation_file_info(
|
|
261
260
|
tables[get_name("FILE_INFO")]
|
|
262
261
|
)
|
|
263
262
|
|
|
264
263
|
shower_data = self._table_to_shower_data(tables[get_name("SHOWERS")])
|
|
264
|
+
if tables.get(get_name("TRIGGERS")) is None:
|
|
265
|
+
self._logger.info("No triggered event data found in the file.")
|
|
266
|
+
return tables[get_name("FILE_INFO")], shower_data, None, None
|
|
267
|
+
|
|
265
268
|
triggered_data = self._table_to_triggered_data(tables[get_name("TRIGGERS")])
|
|
266
269
|
triggered_shower = self._get_triggered_shower_data(
|
|
267
270
|
shower_data,
|