gammasimtools 0.16.0__py3-none-any.whl → 0.18.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.16.0.dist-info → gammasimtools-0.18.0.dist-info}/METADATA +5 -2
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/RECORD +82 -74
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/entry_points.txt +4 -1
- simtools/_version.py +2 -2
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +10 -1
- simtools/applications/derive_ctao_array_layouts.py +5 -5
- simtools/applications/derive_mirror_rnda.py +1 -1
- simtools/applications/generate_simtel_event_data.py +128 -46
- simtools/applications/merge_tables.py +102 -0
- simtools/applications/plot_array_layout.py +145 -258
- simtools/applications/plot_tabular_data.py +12 -1
- simtools/applications/plot_tabular_data_for_model_parameter.py +103 -0
- simtools/applications/production_derive_corsika_limits.py +78 -225
- simtools/applications/production_derive_statistics.py +77 -43
- simtools/applications/simulate_light_emission.py +1 -0
- simtools/applications/simulate_prod.py +30 -18
- simtools/applications/simulate_prod_htcondor_generator.py +0 -1
- simtools/applications/submit_array_layouts.py +93 -0
- simtools/applications/verify_simulation_model_production_tables.py +52 -0
- simtools/camera/camera_efficiency.py +3 -3
- simtools/configuration/commandline_parser.py +30 -35
- simtools/configuration/configurator.py +0 -4
- simtools/constants.py +2 -0
- simtools/corsika/corsika_config.py +17 -12
- simtools/corsika/primary_particle.py +46 -13
- simtools/data_model/metadata_collector.py +7 -3
- simtools/data_model/schema.py +15 -1
- simtools/db/db_handler.py +16 -11
- simtools/db/db_model_upload.py +2 -2
- simtools/io_operations/io_handler.py +2 -2
- simtools/io_operations/io_table_handler.py +345 -0
- simtools/job_execution/htcondor_script_generator.py +2 -2
- simtools/job_execution/job_manager.py +7 -121
- simtools/layout/array_layout_utils.py +389 -0
- simtools/model/array_model.py +10 -1
- simtools/model/model_repository.py +134 -0
- simtools/production_configuration/{calculate_statistical_errors_grid_point.py → calculate_statistical_uncertainties_grid_point.py} +101 -112
- simtools/production_configuration/derive_corsika_limits.py +239 -111
- simtools/production_configuration/derive_corsika_limits_grid.py +232 -0
- simtools/production_configuration/derive_production_statistics.py +57 -26
- simtools/production_configuration/derive_production_statistics_handler.py +70 -37
- simtools/production_configuration/interpolation_handler.py +296 -94
- simtools/ray_tracing/ray_tracing.py +7 -6
- simtools/reporting/docs_read_parameters.py +104 -62
- simtools/resources/array-element-ids.json +126 -0
- simtools/runners/corsika_simtel_runner.py +4 -1
- simtools/runners/runner_services.py +5 -4
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +5 -1
- simtools/schemas/model_parameters/atmospheric_profile.schema.yml +41 -0
- simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +43 -0
- simtools/schemas/model_parameters/camera_filter.schema.yml +10 -0
- simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +10 -0
- simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +31 -0
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +12 -0
- simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +10 -0
- simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +10 -0
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +12 -0
- simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +19 -0
- simtools/schemas/model_parameters/quantum_efficiency.schema.yml +10 -0
- simtools/schemas/plot_configuration.metaschema.yml +46 -57
- simtools/schemas/production_configuration_metrics.schema.yml +2 -2
- simtools/simtel/simtel_config_writer.py +34 -14
- simtools/simtel/simtel_io_event_reader.py +301 -194
- simtools/simtel/simtel_io_event_writer.py +237 -221
- simtools/simtel/simtel_io_file_info.py +9 -4
- simtools/simtel/simtel_io_metadata.py +119 -8
- simtools/simtel/simulator_array.py +2 -2
- simtools/simtel/simulator_light_emission.py +79 -34
- simtools/simtel/simulator_ray_tracing.py +2 -2
- simtools/simulator.py +101 -68
- simtools/testing/validate_output.py +4 -1
- simtools/utils/general.py +1 -3
- simtools/utils/names.py +76 -7
- simtools/visualization/plot_array_layout.py +242 -0
- simtools/visualization/plot_pixels.py +680 -0
- simtools/visualization/plot_tables.py +81 -2
- simtools/visualization/visualize.py +3 -219
- simtools/applications/production_generate_simulation_config.py +0 -152
- simtools/layout/ctao_array_layouts.py +0 -172
- simtools/production_configuration/generate_simulation_config.py +0 -158
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/top_level.txt +0 -0
- /simtools/{schemas → resources}/array_elements.yml +0 -0
|
@@ -1,205 +1,303 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Read a reduced dataset from file.
|
|
3
|
-
|
|
4
|
-
Allow to filter the events based on the triggered telescopes.
|
|
5
|
-
Provide functionality to list events, e.g. through
|
|
6
|
-
|
|
7
|
-
.. code-block:: console
|
|
8
|
-
|
|
9
|
-
from simtools.simtel.simtel_io_event_reader import SimtelIOEventDataReader
|
|
10
|
-
reader = SimtelIOEventDataReader("gamma_diffuse_60deg.hdf5", [1,2,3,4])
|
|
11
|
-
reader.print_event_table()
|
|
12
|
-
|
|
13
|
-
"""
|
|
1
|
+
"""Read reduced datasets in form of astropy tables from file."""
|
|
14
2
|
|
|
15
3
|
import logging
|
|
4
|
+
from dataclasses import dataclass, field
|
|
16
5
|
|
|
17
6
|
import astropy.units as u
|
|
18
7
|
import numpy as np
|
|
19
|
-
import tables
|
|
20
8
|
from astropy.coordinates import AltAz, angular_separation
|
|
21
9
|
from ctapipe.coordinates import GroundFrame, TiltedGroundFrame
|
|
22
10
|
|
|
23
|
-
from simtools.
|
|
11
|
+
from simtools.corsika.primary_particle import PrimaryParticle
|
|
12
|
+
from simtools.io_operations import io_table_handler
|
|
24
13
|
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
@dataclass
|
|
16
|
+
class ShowerEventData:
|
|
17
|
+
"""Container for shower event data."""
|
|
29
18
|
|
|
30
|
-
|
|
19
|
+
shower_id: list[np.uint32] = field(default_factory=list)
|
|
20
|
+
event_id: list[np.uint32] = field(default_factory=list)
|
|
21
|
+
file_id: list[np.uint32] = field(default_factory=list)
|
|
22
|
+
simulated_energy: list[np.float64] = field(default_factory=list)
|
|
23
|
+
x_core: list[np.float64] = field(default_factory=list)
|
|
24
|
+
y_core: list[np.float64] = field(default_factory=list)
|
|
25
|
+
shower_azimuth: list[np.float64] = field(default_factory=list)
|
|
26
|
+
shower_altitude: list[np.float64] = field(default_factory=list)
|
|
27
|
+
area_weight: list[np.float64] = field(default_factory=list)
|
|
28
|
+
x_core_shower: list[np.float64] = field(default_factory=list)
|
|
29
|
+
y_core_shower: list[np.float64] = field(default_factory=list)
|
|
30
|
+
core_distance_shower: list[np.float64] = field(default_factory=list)
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class TriggeredEventData:
|
|
35
|
+
"""Container for triggered event data."""
|
|
36
|
+
|
|
37
|
+
shower_id: list[np.uint32] = field(default_factory=list)
|
|
38
|
+
event_id: list[np.uint32] = field(default_factory=list)
|
|
39
|
+
file_id: list[np.uint32] = field(default_factory=list)
|
|
40
|
+
array_altitude: list[float] = field(default_factory=list)
|
|
41
|
+
array_azimuth: list[float] = field(default_factory=list)
|
|
42
|
+
telescope_list: list[np.ndarray] = field(default_factory=list)
|
|
43
|
+
angular_distance: list[float] = field(default_factory=list)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class SimtelIOEventDataReader:
|
|
47
|
+
"""Read reduced MC data set stored in astropy tables."""
|
|
39
48
|
|
|
40
49
|
def __init__(self, event_data_file, telescope_list=None):
|
|
41
|
-
"""Initialize SimtelIOEventDataReader
|
|
50
|
+
"""Initialize SimtelIOEventDataReader."""
|
|
42
51
|
self._logger = logging.getLogger(__name__)
|
|
43
52
|
self.telescope_list = telescope_list
|
|
44
53
|
|
|
45
|
-
self.
|
|
46
|
-
event_data_file
|
|
47
|
-
)
|
|
48
|
-
self._derived_event_data()
|
|
54
|
+
self.data_sets = self.read_table_list(event_data_file)
|
|
49
55
|
|
|
50
|
-
def
|
|
56
|
+
def read_table_list(self, event_data_file):
|
|
51
57
|
"""
|
|
52
|
-
Read
|
|
58
|
+
Read available tables from the event data file.
|
|
59
|
+
|
|
60
|
+
Rearrange dictionary with tables names into a list of dictionaries
|
|
61
|
+
under the assumption that the file contains the tables "SHOWERS",
|
|
62
|
+
"TRIGGERS", and "FILE_INFO".
|
|
53
63
|
|
|
54
64
|
Parameters
|
|
55
65
|
----------
|
|
56
|
-
event_data_file : str
|
|
57
|
-
Path to the
|
|
66
|
+
event_data_file : str
|
|
67
|
+
Path to the event data file.
|
|
58
68
|
|
|
59
69
|
Returns
|
|
60
70
|
-------
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
list
|
|
72
|
+
List of dictionaries containing the data from the tables.
|
|
63
73
|
"""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
reduced_data = f.root.data.reduced_data
|
|
69
|
-
event_data.simulated_energy = reduced_data.col("simulated_energy")
|
|
70
|
-
event_data.x_core = reduced_data.col("x_core")
|
|
71
|
-
event_data.y_core = reduced_data.col("y_core")
|
|
72
|
-
event_data.shower_azimuth = reduced_data.col("shower_azimuth")
|
|
73
|
-
event_data.shower_altitude = reduced_data.col("shower_altitude")
|
|
74
|
-
event_data.shower_id = reduced_data.col("shower_id")
|
|
75
|
-
event_data.area_weight = reduced_data.col("area_weight")
|
|
76
|
-
|
|
77
|
-
triggered_data = f.root.data.triggered_data
|
|
78
|
-
triggered_event_data.triggered_id = triggered_data.col("triggered_id")
|
|
79
|
-
triggered_event_data.array_altitudes = triggered_data.col("array_altitudes")
|
|
80
|
-
triggered_event_data.array_azimuths = triggered_data.col("array_azimuths")
|
|
81
|
-
|
|
82
|
-
telescope_indices = triggered_data.col("telescope_list_index")
|
|
83
|
-
telescope_list_array = f.root.data.trigger_telescope_list_list
|
|
84
|
-
|
|
85
|
-
triggered_event_data.trigger_telescope_list_list = []
|
|
86
|
-
for index in telescope_indices:
|
|
87
|
-
if index < telescope_list_array.nrows:
|
|
88
|
-
triggered_event_data.trigger_telescope_list_list.append(
|
|
89
|
-
telescope_list_array[index]
|
|
90
|
-
)
|
|
91
|
-
else:
|
|
92
|
-
self._logger.warning(f"Invalid telescope list index: {index}")
|
|
93
|
-
triggered_event_data.trigger_telescope_list_list.append(
|
|
94
|
-
np.array([], dtype=np.int16)
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
triggered_shower, triggered_data = self._reduce_to_triggered_events(
|
|
98
|
-
event_data, triggered_event_data
|
|
74
|
+
dataset_dict = io_table_handler.read_table_list(
|
|
75
|
+
event_data_file,
|
|
76
|
+
["SHOWERS", "TRIGGERS", "FILE_INFO"],
|
|
77
|
+
include_indexed_tables=True,
|
|
99
78
|
)
|
|
100
|
-
return event_data, triggered_shower, triggered_data
|
|
101
79
|
|
|
102
|
-
|
|
80
|
+
data_sets = []
|
|
81
|
+
for i in range(len(dataset_dict["SHOWERS"])):
|
|
82
|
+
data_sets.append(
|
|
83
|
+
{
|
|
84
|
+
"SHOWERS": dataset_dict["SHOWERS"][i],
|
|
85
|
+
"TRIGGERS": dataset_dict["TRIGGERS"][i],
|
|
86
|
+
"FILE_INFO": dataset_dict["FILE_INFO"][i],
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return data_sets
|
|
91
|
+
|
|
92
|
+
def _table_to_shower_data(self, table):
|
|
103
93
|
"""
|
|
104
|
-
|
|
94
|
+
Convert tables with shower event data and add derived quantities.
|
|
105
95
|
|
|
106
96
|
Parameters
|
|
107
97
|
----------
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
triggered_data : TriggeredEventData
|
|
111
|
-
Triggered event data.
|
|
98
|
+
table : astropy.table.Table
|
|
99
|
+
Table "SHOWERS"
|
|
112
100
|
|
|
113
101
|
Returns
|
|
114
102
|
-------
|
|
115
|
-
ShowerEventData
|
|
116
|
-
|
|
103
|
+
ShowerEventData
|
|
104
|
+
An instance of ShowerEventData with the data from the table.
|
|
117
105
|
"""
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
106
|
+
shower_data = ShowerEventData()
|
|
107
|
+
|
|
108
|
+
for col in table.colnames:
|
|
109
|
+
setattr(shower_data, col, np.array(table[col].data))
|
|
110
|
+
if table[col].unit:
|
|
111
|
+
setattr(shower_data, f"{col}_unit", table[col].unit)
|
|
112
|
+
|
|
113
|
+
shower_data.x_core_shower, shower_data.y_core_shower = (
|
|
114
|
+
self._transform_to_shower_coordinates(
|
|
115
|
+
shower_data.x_core,
|
|
116
|
+
shower_data.y_core,
|
|
117
|
+
shower_data.shower_azimuth,
|
|
118
|
+
shower_data.shower_altitude,
|
|
119
|
+
)
|
|
122
120
|
)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
y_core=event_data.y_core[filtered_shower_ids],
|
|
126
|
-
simulated_energy=event_data.simulated_energy[filtered_shower_ids],
|
|
127
|
-
shower_azimuth=event_data.shower_azimuth[filtered_shower_ids],
|
|
128
|
-
shower_altitude=event_data.shower_altitude[filtered_shower_ids],
|
|
121
|
+
shower_data.core_distance_shower = np.sqrt(
|
|
122
|
+
shower_data.x_core_shower**2 + shower_data.y_core_shower**2
|
|
129
123
|
)
|
|
130
124
|
|
|
131
|
-
|
|
132
|
-
triggered_data.trigger_telescope_list_list[i] for i in triggered_indices
|
|
133
|
-
]
|
|
125
|
+
return shower_data
|
|
134
126
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
127
|
+
def _table_to_triggered_data(self, table):
|
|
128
|
+
"""
|
|
129
|
+
Convert table with triggered event data.
|
|
130
|
+
|
|
131
|
+
Converts telescope lists from comma-separated string to numpy array.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
table : astropy.table.Table
|
|
136
|
+
Table "TRIGGERS"
|
|
144
137
|
|
|
145
|
-
|
|
146
|
-
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
TriggeredEventData
|
|
141
|
+
An instance of TriggeredEventData with the data from the table.
|
|
142
|
+
"""
|
|
143
|
+
triggered_data = TriggeredEventData()
|
|
144
|
+
for col in table.colnames:
|
|
145
|
+
if col == "telescope_list":
|
|
146
|
+
arrays = [
|
|
147
|
+
np.array(list(map(str, tel_list.split(","))), dtype=np.str_)
|
|
148
|
+
for tel_list in table[col]
|
|
149
|
+
]
|
|
150
|
+
triggered_data.telescope_list = arrays
|
|
151
|
+
else:
|
|
152
|
+
data = np.array(table[col].data)
|
|
153
|
+
setattr(triggered_data, col, data)
|
|
154
|
+
if table[col].unit:
|
|
155
|
+
setattr(triggered_data, f"{col}_unit", table[col].unit)
|
|
156
|
+
return triggered_data
|
|
157
|
+
|
|
158
|
+
def _get_triggered_shower_data(
|
|
159
|
+
self, shower_data, triggered_file_id, triggered_event_id, triggered_shower_id
|
|
147
160
|
):
|
|
148
161
|
"""
|
|
149
|
-
|
|
162
|
+
Get shower data corresponding to triggered events.
|
|
163
|
+
|
|
164
|
+
Matches triggered events with showers based on shower_id, event_id, and file_id.
|
|
150
165
|
|
|
151
166
|
Parameters
|
|
152
167
|
----------
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
List of
|
|
168
|
+
shower_data : ShowerEventData
|
|
169
|
+
The shower data containing all showers.
|
|
170
|
+
triggered_file_id : list
|
|
171
|
+
List of file IDs for triggered events.
|
|
172
|
+
triggered_event_id : list
|
|
173
|
+
List of event IDs for triggered events.
|
|
174
|
+
triggered_shower_id : list
|
|
175
|
+
List of shower IDs for triggered events.
|
|
159
176
|
|
|
160
177
|
Returns
|
|
161
178
|
-------
|
|
162
|
-
|
|
163
|
-
|
|
179
|
+
ShowerEventData
|
|
180
|
+
An instance of ShowerEventData containing only the triggered showers.
|
|
181
|
+
|
|
164
182
|
"""
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
183
|
+
triggered_shower = ShowerEventData()
|
|
184
|
+
|
|
185
|
+
matched_indices = []
|
|
186
|
+
for tr_shower_id, tr_event_id, tr_file_id in zip(
|
|
187
|
+
triggered_shower_id, triggered_event_id, triggered_file_id
|
|
188
|
+
):
|
|
189
|
+
mask = (
|
|
190
|
+
(shower_data.shower_id == tr_shower_id)
|
|
191
|
+
& (shower_data.event_id == tr_event_id)
|
|
192
|
+
& (shower_data.file_id == tr_file_id)
|
|
172
193
|
)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
event_data.x_core_shower, event_data.y_core_shower = (
|
|
181
|
-
self._transform_to_shower_coordinates(
|
|
182
|
-
event_data.x_core,
|
|
183
|
-
event_data.y_core,
|
|
184
|
-
event_data.shower_azimuth,
|
|
185
|
-
event_data.shower_altitude,
|
|
194
|
+
matched_idx = np.where(mask)[0]
|
|
195
|
+
if len(matched_idx) == 1:
|
|
196
|
+
matched_indices.append(matched_idx[0])
|
|
197
|
+
else:
|
|
198
|
+
self._logger.warning(
|
|
199
|
+
f"Found {len(matched_idx)} matches for shower {tr_shower_id}"
|
|
200
|
+
f" event {tr_event_id} file {tr_file_id}"
|
|
186
201
|
)
|
|
187
|
-
)
|
|
188
|
-
event_data.core_distance_shower = np.sqrt(
|
|
189
|
-
event_data.x_core_shower**2 + event_data.y_core_shower**2
|
|
190
|
-
)
|
|
191
202
|
|
|
192
|
-
|
|
203
|
+
for attr in vars(shower_data):
|
|
204
|
+
if not attr.endswith("_unit"):
|
|
205
|
+
value = getattr(shower_data, attr)
|
|
206
|
+
if isinstance(value, list | np.ndarray):
|
|
207
|
+
setattr(triggered_shower, attr, np.array(value)[matched_indices])
|
|
208
|
+
|
|
209
|
+
return triggered_shower
|
|
210
|
+
|
|
211
|
+
def read_event_data(self, event_data_file, table_name_map=None):
|
|
212
|
+
"""
|
|
213
|
+
Read event data and file info tables from file and apply transformations.
|
|
214
|
+
|
|
215
|
+
Allows to map tables names to their actual names in the file
|
|
216
|
+
(e.g., "SHOWER" to "SHOWER_1").
|
|
217
|
+
|
|
218
|
+
Parameters
|
|
219
|
+
----------
|
|
220
|
+
event_data_file : str
|
|
221
|
+
Path to the event data file.
|
|
222
|
+
table_name_map : dict, optional
|
|
223
|
+
Mapping of table names to their actual names in the file.
|
|
224
|
+
Defaults to using the standard names "SHOWERS", "TRIGGERS", and "FILE_INFO".
|
|
225
|
+
|
|
226
|
+
Returns
|
|
227
|
+
-------
|
|
228
|
+
tuple
|
|
229
|
+
A tuple with file info table, shower, triggered shower, and triggered event data.
|
|
230
|
+
"""
|
|
231
|
+
table_name_map = table_name_map or {}
|
|
232
|
+
|
|
233
|
+
def get_name(key):
|
|
234
|
+
return table_name_map.get(key, key)
|
|
235
|
+
|
|
236
|
+
tables = io_table_handler.read_tables(
|
|
237
|
+
event_data_file,
|
|
238
|
+
table_names=[get_name(k) for k in ("SHOWERS", "TRIGGERS", "FILE_INFO")],
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
shower_data = self._table_to_shower_data(tables[get_name("SHOWERS")])
|
|
242
|
+
triggered_data = self._table_to_triggered_data(tables[get_name("TRIGGERS")])
|
|
243
|
+
triggered_shower = self._get_triggered_shower_data(
|
|
244
|
+
shower_data,
|
|
245
|
+
tables[get_name("TRIGGERS")]["file_id"],
|
|
246
|
+
tables[get_name("TRIGGERS")]["event_id"],
|
|
247
|
+
tables[get_name("TRIGGERS")]["shower_id"],
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
triggered_data.angular_distance = (
|
|
193
251
|
angular_separation(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
252
|
+
triggered_shower.shower_azimuth * u.rad,
|
|
253
|
+
triggered_shower.shower_altitude * u.rad,
|
|
254
|
+
triggered_data.array_azimuth * u.rad,
|
|
255
|
+
triggered_data.array_altitude * u.rad,
|
|
256
|
+
)
|
|
257
|
+
.to(u.deg)
|
|
258
|
+
.value
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
if self.telescope_list:
|
|
262
|
+
triggered_data, triggered_shower = self._filter_by_telescopes(
|
|
263
|
+
triggered_data, triggered_shower
|
|
198
264
|
)
|
|
199
|
-
|
|
200
|
-
|
|
265
|
+
|
|
266
|
+
self._logger.info(f"Number of triggered events: {len(triggered_data.array_altitude)}")
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
tables[get_name("FILE_INFO")],
|
|
270
|
+
shower_data,
|
|
271
|
+
triggered_shower,
|
|
272
|
+
triggered_data,
|
|
201
273
|
)
|
|
202
274
|
|
|
275
|
+
def _filter_by_telescopes(self, triggered_data, triggered_shower):
|
|
276
|
+
"""Filter trigger data and triggered shower data by the specified telescope list."""
|
|
277
|
+
mask = np.array(
|
|
278
|
+
[
|
|
279
|
+
any(tel in event for tel in self.telescope_list)
|
|
280
|
+
for event in triggered_data.telescope_list
|
|
281
|
+
]
|
|
282
|
+
)
|
|
283
|
+
filtered_triggered_data = TriggeredEventData(
|
|
284
|
+
shower_id=triggered_data.shower_id[mask],
|
|
285
|
+
event_id=triggered_data.event_id[mask],
|
|
286
|
+
file_id=triggered_data.file_id[mask],
|
|
287
|
+
array_altitude=triggered_data.array_altitude[mask],
|
|
288
|
+
array_azimuth=triggered_data.array_azimuth[mask],
|
|
289
|
+
telescope_list=[triggered_data.telescope_list[i] for i in np.arange(len(mask))[mask]],
|
|
290
|
+
angular_distance=triggered_data.angular_distance[mask],
|
|
291
|
+
)
|
|
292
|
+
filtered_triggered_shower_data = self._get_triggered_shower_data(
|
|
293
|
+
triggered_shower,
|
|
294
|
+
filtered_triggered_data.file_id,
|
|
295
|
+
filtered_triggered_data.event_id,
|
|
296
|
+
filtered_triggered_data.shower_id,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
return filtered_triggered_data, filtered_triggered_shower_data
|
|
300
|
+
|
|
203
301
|
def _transform_to_shower_coordinates(self, x_core, y_core, shower_azimuth, shower_altitude):
|
|
204
302
|
"""
|
|
205
303
|
Transform core positions from ground coordinates to shower coordinates.
|
|
@@ -220,59 +318,68 @@ class SimtelIOEventDataReader:
|
|
|
220
318
|
tuple
|
|
221
319
|
Core positions in shower coordinates (x, y).
|
|
222
320
|
"""
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
321
|
+
ground = GroundFrame(x=x_core * u.m, y=y_core * u.m, z=np.zeros_like(x_core) * u.m)
|
|
322
|
+
shower_frame = ground.transform_to(
|
|
323
|
+
TiltedGroundFrame(
|
|
324
|
+
pointing_direction=AltAz(az=shower_azimuth * u.rad, alt=shower_altitude * u.rad)
|
|
325
|
+
)
|
|
326
|
+
)
|
|
227
327
|
return shower_frame.x.value, shower_frame.y.value
|
|
228
328
|
|
|
229
|
-
def
|
|
230
|
-
"""
|
|
231
|
-
|
|
232
|
-
def print_event_data(data, name):
|
|
233
|
-
"""Print event data."""
|
|
234
|
-
print(f"{name}: {data[:n_events]}")
|
|
235
|
-
|
|
236
|
-
print_event_data(self.triggered_shower_data.simulated_energy, "Simulated energy (TeV)")
|
|
237
|
-
print_event_data(self.triggered_shower_data.x_core, "Core x (m)")
|
|
238
|
-
print_event_data(self.triggered_shower_data.y_core, "Core y (m)")
|
|
239
|
-
print_event_data(self.triggered_shower_data.shower_azimuth, "Shower azimuth (rad)")
|
|
240
|
-
print_event_data(self.triggered_shower_data.shower_altitude, "Shower altitude (rad)")
|
|
241
|
-
print_event_data(self.triggered_shower_data.x_core_shower, "Core x shower (m)")
|
|
242
|
-
print_event_data(self.triggered_shower_data.y_core_shower, "Core y shower (m)")
|
|
243
|
-
print_event_data(
|
|
244
|
-
self.triggered_shower_data.core_distance_shower, "Core distance shower (m)"
|
|
245
|
-
)
|
|
246
|
-
print_event_data(self.triggered_data.array_azimuths, "Array azimuth (rad)")
|
|
247
|
-
print_event_data(self.triggered_data.array_altitudes, "Array altitude (rad)")
|
|
248
|
-
print_event_data(self.triggered_data.trigger_telescope_list_list, "Triggered telescopes")
|
|
249
|
-
print_event_data(
|
|
250
|
-
self.triggered_data.angular_distance, "Angular distance to pointing direction (deg)"
|
|
251
|
-
)
|
|
252
|
-
print("")
|
|
329
|
+
def get_reduced_simulation_file_info(self, simulation_file_info):
|
|
330
|
+
"""
|
|
331
|
+
Return reduced simulation file info assuming single-valued parameters.
|
|
253
332
|
|
|
254
|
-
|
|
255
|
-
|
|
333
|
+
Applies rounding and uniqueness functions extract representative values
|
|
334
|
+
for zenith, azimuth, and NSB level. Assumes all files share identical
|
|
335
|
+
simulation parameters except for file names. Returns particle name instead
|
|
336
|
+
of ID.
|
|
337
|
+
|
|
338
|
+
Logs a warning if multiple unique values are found.
|
|
256
339
|
|
|
257
340
|
Parameters
|
|
258
341
|
----------
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
"""
|
|
262
|
-
print(
|
|
263
|
-
f"{'Counter':<10} {'Simulated Energy (TeV)':<20} {'Triggered Telescopes':<20} "
|
|
264
|
-
f"{'Core distance shower (m)':<20}"
|
|
265
|
-
)
|
|
342
|
+
simulation_file_info : astropy.table.Table
|
|
343
|
+
Dictionary containing simulation file info.
|
|
266
344
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
345
|
+
Returns
|
|
346
|
+
-------
|
|
347
|
+
dict
|
|
348
|
+
Dictionary containing the reduced simulation file info.
|
|
349
|
+
"""
|
|
350
|
+
particle_id = np.unique(simulation_file_info["particle_id"].data)
|
|
351
|
+
keys = [
|
|
352
|
+
"zenith",
|
|
353
|
+
"azimuth",
|
|
354
|
+
"nsb_level",
|
|
355
|
+
"energy_min",
|
|
356
|
+
"energy_max",
|
|
357
|
+
"viewcone_min",
|
|
358
|
+
"viewcone_max",
|
|
359
|
+
"core_scatter_min",
|
|
360
|
+
"core_scatter_max",
|
|
361
|
+
]
|
|
362
|
+
float_arrays = {}
|
|
363
|
+
for key in keys:
|
|
364
|
+
if key == "energy_min":
|
|
365
|
+
float_arrays[key] = np.unique(np.round(simulation_file_info[key].data, decimals=3))
|
|
366
|
+
else:
|
|
367
|
+
float_arrays[key] = np.unique(np.round(simulation_file_info[key].data, decimals=2))
|
|
368
|
+
|
|
369
|
+
if any(len(arr) > 1 for arr in (particle_id, *(float_arrays[key] for key in keys))):
|
|
370
|
+
self._logger.warning("Simulation file info has non-unique values.")
|
|
371
|
+
|
|
372
|
+
reduced_info = {
|
|
373
|
+
"primary_particle": PrimaryParticle(
|
|
374
|
+
particle_id_type="corsika7_id",
|
|
375
|
+
particle_id=int(particle_id[0]),
|
|
376
|
+
).name,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
for key in keys:
|
|
380
|
+
value = float(float_arrays[key][0])
|
|
381
|
+
if simulation_file_info[key].unit is not None:
|
|
382
|
+
value = value * simulation_file_info[key].unit
|
|
383
|
+
reduced_info[key] = value
|
|
384
|
+
|
|
385
|
+
return reduced_info
|