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.
- {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/METADATA +2 -1
- {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/RECORD +134 -130
- {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/entry_points.txt +3 -1
- {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/licenses/LICENSE +1 -1
- simtools/_version.py +2 -2
- simtools/application_control.py +78 -0
- 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 +5 -1
- simtools/applications/derive_pulse_shape_parameters.py +194 -0
- 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 +64 -108
- 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 +3 -4
- simtools/applications/simulate_illuminator.py +0 -1
- simtools/applications/simulate_pedestals.py +2 -6
- simtools/applications/simulate_prod.py +9 -28
- simtools/applications/simulate_prod_htcondor_generator.py +8 -1
- simtools/applications/submit_array_layouts.py +7 -7
- 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_file_using_schema.py +49 -123
- 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 +43 -8
- simtools/configuration/configurator.py +6 -11
- simtools/corsika/corsika_config.py +204 -99
- 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 +27 -17
- simtools/data_model/schema.py +112 -5
- simtools/data_model/validate_data.py +80 -48
- simtools/db/db_handler.py +19 -8
- simtools/db/db_model_upload.py +2 -1
- simtools/db/mongo_db.py +133 -42
- simtools/dependencies.py +83 -44
- simtools/io/ascii_handler.py +4 -2
- simtools/io/table_handler.py +1 -1
- simtools/job_execution/htcondor_script_generator.py +0 -2
- simtools/layout/array_layout.py +4 -12
- simtools/layout/array_layout_utils.py +227 -58
- simtools/model/array_model.py +37 -18
- simtools/model/calibration_model.py +0 -4
- simtools/model/legacy_model_parameter.py +134 -0
- simtools/model/model_parameter.py +24 -14
- simtools/model/model_repository.py +18 -5
- 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 +29 -27
- simtools/ray_tracing/psf_parameter_optimisation.py +822 -680
- simtools/ray_tracing/ray_tracing.py +6 -15
- simtools/reporting/docs_auto_report_generator.py +8 -13
- simtools/reporting/docs_read_parameters.py +70 -16
- simtools/runners/corsika_runner.py +15 -10
- simtools/runners/corsika_simtel_runner.py +9 -8
- simtools/runners/runner_services.py +17 -7
- simtools/runners/simtel_runner.py +11 -58
- simtools/runners/simtools_runner.py +2 -4
- simtools/schemas/model_parameters/flasher_pulse_exp_decay.schema.yml +2 -0
- simtools/schemas/model_parameters/flasher_pulse_shape.schema.yml +50 -0
- simtools/schemas/model_parameters/flasher_pulse_width.schema.yml +2 -0
- simtools/schemas/simulation_models_info.schema.yml +2 -0
- simtools/settings.py +154 -0
- simtools/sim_events/file_info.py +128 -0
- 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 +273 -0
- simtools/simtel/simtel_config_writer.py +146 -22
- simtools/simtel/simtel_table_reader.py +6 -4
- simtools/simtel/simulator_array.py +62 -23
- simtools/simtel/simulator_camera_efficiency.py +4 -6
- simtools/simtel/simulator_light_emission.py +101 -19
- simtools/simtel/simulator_ray_tracing.py +4 -10
- simtools/simulator.py +360 -353
- simtools/telescope_trigger_rates.py +3 -4
- simtools/testing/assertions.py +115 -8
- simtools/testing/configuration.py +2 -3
- simtools/testing/helpers.py +2 -3
- simtools/testing/log_inspector.py +5 -1
- simtools/testing/sim_telarray_metadata.py +1 -1
- simtools/testing/validate_output.py +69 -23
- simtools/utils/general.py +37 -0
- simtools/utils/geometry.py +0 -77
- simtools/utils/names.py +7 -9
- simtools/version.py +37 -0
- simtools/visualization/legend_handlers.py +21 -10
- simtools/visualization/plot_array_layout.py +312 -41
- simtools/visualization/plot_corsika_histograms.py +143 -605
- simtools/visualization/plot_mirrors.py +834 -0
- 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
- simtools/simtel/simtel_io_file_info.py +0 -62
- {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.24.0.dist-info → gammasimtools-0.26.0.dist-info}/top_level.txt +0 -0
|
@@ -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")
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
%YAML 1.2
|
|
2
2
|
---
|
|
3
3
|
title: Schema for flasher_pulse_exp_decay model parameter
|
|
4
|
+
deprecated: true
|
|
5
|
+
deprecation_note: "Replaced by updated definition of flasher_pulse_shape"
|
|
4
6
|
schema_version: 0.1.0
|
|
5
7
|
meta_schema: simpipe-schema
|
|
6
8
|
meta_schema_url: https://raw.githubusercontent.com/gammasim/simtools/main/src/simtools/schemas/model_parameter_and_data_schema.metaschema.yml
|
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
%YAML 1.2
|
|
2
2
|
---
|
|
3
3
|
title: Schema for flasher_pulse_shape model parameter
|
|
4
|
+
schema_version: 0.2.0
|
|
5
|
+
meta_schema: simpipe-schema
|
|
6
|
+
meta_schema_url: https://raw.githubusercontent.com/gammasim/simtools/main/src/simtools/schemas/model_parameter_and_data_schema.metaschema.yml
|
|
7
|
+
meta_schema_version: 0.1.0
|
|
8
|
+
name: flasher_pulse_shape
|
|
9
|
+
short_description: |-
|
|
10
|
+
Definition of flasher pulse shape.
|
|
11
|
+
description: |-
|
|
12
|
+
Definition of flasher pulse shape both shape and relevant
|
|
13
|
+
timing parameters.
|
|
14
|
+
data:
|
|
15
|
+
- type: string
|
|
16
|
+
description: Shape of the flasher pulse.
|
|
17
|
+
default: Gauss
|
|
18
|
+
allowed_values:
|
|
19
|
+
- Gauss
|
|
20
|
+
- TopHat
|
|
21
|
+
- Exponential
|
|
22
|
+
- Gauss-Exponential
|
|
23
|
+
- type: float64
|
|
24
|
+
description: |-
|
|
25
|
+
Characteristic width of the flasher pulse shape.
|
|
26
|
+
For 'TopHat', this is the pulse width, for 'Gauss' and 'Gauss-Exponential'
|
|
27
|
+
the rms width. Ignored if shape is 'Exponential'.
|
|
28
|
+
unit: ns
|
|
29
|
+
default: 0
|
|
30
|
+
allowed_range:
|
|
31
|
+
min: 0
|
|
32
|
+
- type: float64
|
|
33
|
+
description: |-
|
|
34
|
+
Exponential decay time of the flasher pulse shape.
|
|
35
|
+
Only relevant if shape is 'Exponential' or 'Gauss-Exponential'.
|
|
36
|
+
unit: ns
|
|
37
|
+
default: 0
|
|
38
|
+
allowed_range:
|
|
39
|
+
min: 0
|
|
40
|
+
instrument:
|
|
41
|
+
class: Calibration
|
|
42
|
+
activity:
|
|
43
|
+
setting:
|
|
44
|
+
- SetParameterFromExternal
|
|
45
|
+
validation:
|
|
46
|
+
- ValidateParameterByExpert
|
|
47
|
+
source:
|
|
48
|
+
- Initial instrument setup
|
|
49
|
+
simulation_software:
|
|
50
|
+
- name: simtools
|
|
51
|
+
version: ">0.24.0"
|
|
52
|
+
---
|
|
53
|
+
title: Schema for flasher_pulse_shape model parameter
|
|
4
54
|
schema_version: 0.1.0
|
|
5
55
|
meta_schema: simpipe-schema
|
|
6
56
|
meta_schema_url: https://raw.githubusercontent.com/gammasim/simtools/main/src/simtools/schemas/model_parameter_and_data_schema.metaschema.yml
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
%YAML 1.2
|
|
2
2
|
---
|
|
3
3
|
title: Schema for flasher_pulse_width model parameter
|
|
4
|
+
deprecated: true
|
|
5
|
+
deprecation_note: "Replaced by updated definition of flasher_pulse_shape"
|
|
4
6
|
schema_version: 0.1.0
|
|
5
7
|
meta_schema: simpipe-schema
|
|
6
8
|
meta_schema_url: https://raw.githubusercontent.com/gammasim/simtools/main/src/simtools/schemas/model_parameter_and_data_schema.metaschema.yml
|
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()
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
"""Read file info and run headers from eventio (CORSIKA IACT, sim_telarray) files."""
|
|
3
|
+
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
from eventio import EventIOFile, iact
|
|
7
|
+
from eventio.simtel import MCRunHeader, MCShower, RunHeader
|
|
8
|
+
|
|
9
|
+
# Suppress all UserWarnings from corsikaio - no CORSIKA versions <7.7 are supported anyway
|
|
10
|
+
warnings.filterwarnings("ignore", category=UserWarning, module=r"corsikaio\.subblocks\..*")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_corsika_run_number(file):
|
|
14
|
+
"""
|
|
15
|
+
Return the CORSIKA run number from an eventio (CORSIKA IACT or sim_telarray) file.
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
file: str
|
|
20
|
+
Path to the eventio file.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
int, None
|
|
25
|
+
CORSIKA run number. Returns None if not found.
|
|
26
|
+
"""
|
|
27
|
+
run_header = get_combined_eventio_run_header(file)
|
|
28
|
+
if run_header and "run" in run_header:
|
|
29
|
+
return run_header["run"]
|
|
30
|
+
run_header, _ = get_corsika_run_and_event_headers(file)
|
|
31
|
+
try:
|
|
32
|
+
return int(run_header["run_number"])
|
|
33
|
+
except (TypeError, KeyError, ValueError):
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_combined_eventio_run_header(sim_telarray_file):
|
|
38
|
+
"""
|
|
39
|
+
Return the CORSIKA run header information from an eventio (sim_telarray) file.
|
|
40
|
+
|
|
41
|
+
Reads both RunHeader and MCRunHeader object from file and returns a merged dictionary.
|
|
42
|
+
Adds primary id from the first event.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
sim_telarray_file: str
|
|
47
|
+
Path to the sim_telarray file.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
dict, None
|
|
52
|
+
CORSIKA run header. Returns None if not found.
|
|
53
|
+
"""
|
|
54
|
+
run_header = mc_run_header = None
|
|
55
|
+
primary_id = None
|
|
56
|
+
|
|
57
|
+
with EventIOFile(sim_telarray_file) as f:
|
|
58
|
+
for o in f:
|
|
59
|
+
if isinstance(o, RunHeader) and run_header is None:
|
|
60
|
+
run_header = o.parse()
|
|
61
|
+
elif isinstance(o, MCRunHeader) and mc_run_header is None:
|
|
62
|
+
mc_run_header = o.parse()
|
|
63
|
+
elif isinstance(o, MCShower): # get primary_id from first MCShower
|
|
64
|
+
primary_id = o.parse().get("primary_id")
|
|
65
|
+
if run_header and mc_run_header and primary_id is not None:
|
|
66
|
+
break
|
|
67
|
+
|
|
68
|
+
run_header = run_header or {}
|
|
69
|
+
mc_run_header = mc_run_header or {}
|
|
70
|
+
if primary_id is not None:
|
|
71
|
+
mc_run_header["primary_id"] = primary_id
|
|
72
|
+
return run_header | mc_run_header or None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_corsika_run_and_event_headers(corsika_iact_file):
|
|
76
|
+
"""
|
|
77
|
+
Return the CORSIKA run and event headers from a CORSIKA IACT eventio file.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
corsika_iact_file: str, Path
|
|
82
|
+
Path to the CORSIKA IACT eventio file.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
tuple
|
|
87
|
+
CORSIKA run header and event header as dictionaries.
|
|
88
|
+
"""
|
|
89
|
+
run_header = event_header = None
|
|
90
|
+
|
|
91
|
+
with EventIOFile(corsika_iact_file) as f:
|
|
92
|
+
for o in f:
|
|
93
|
+
if isinstance(o, iact.RunHeader) and run_header is None:
|
|
94
|
+
run_header = o.parse()
|
|
95
|
+
elif isinstance(o, iact.EventHeader) and event_header is None:
|
|
96
|
+
event_header = o.parse()
|
|
97
|
+
if run_header and event_header:
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
return run_header, event_header
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_simulated_events(event_io_file):
|
|
104
|
+
"""
|
|
105
|
+
Return the number of shower and MC events from a simulation (eventio) file.
|
|
106
|
+
|
|
107
|
+
For a sim_telarray file, the number of simulated showers and MC events is
|
|
108
|
+
determined by counting the number of MCShower (type id 2020) and MCEvent
|
|
109
|
+
objects (type id 2021). For a CORSIKA IACT file, the number of simulated
|
|
110
|
+
showers is determined by counting the number of IACTShower (type id 1202).
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
event_io_file: str, Path
|
|
115
|
+
Path to the eventio file.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
tuple
|
|
120
|
+
Number of showers and number of MC events (MC events for sim_telarray files only).
|
|
121
|
+
"""
|
|
122
|
+
counts = {1202: 0, 2020: 0, 2021: 0}
|
|
123
|
+
with EventIOFile(event_io_file) as f:
|
|
124
|
+
for o in f:
|
|
125
|
+
t = o.header.type
|
|
126
|
+
if t in counts:
|
|
127
|
+
counts[t] += 1
|
|
128
|
+
return counts[2020] if counts[2020] else counts[1202], counts[2021]
|
|
@@ -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,
|