gammasimtools 0.19.0__py3-none-any.whl → 0.21.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.19.0.dist-info → gammasimtools-0.21.0.dist-info}/METADATA +1 -3
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/RECORD +54 -51
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/entry_points.txt +3 -3
- simtools/_version.py +2 -2
- simtools/applications/calculate_incident_angles.py +182 -0
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +17 -14
- simtools/applications/db_add_value_from_json_to_db.py +6 -9
- simtools/applications/db_generate_compound_indexes.py +7 -3
- simtools/applications/db_get_file_from_db.py +11 -23
- simtools/applications/derive_psf_parameters.py +58 -39
- simtools/applications/derive_trigger_rates.py +91 -0
- simtools/applications/generate_corsika_histograms.py +7 -184
- simtools/applications/maintain_simulation_model_add_production.py +105 -0
- simtools/applications/plot_simtel_events.py +5 -189
- simtools/applications/print_version.py +8 -7
- simtools/applications/validate_file_using_schema.py +7 -4
- simtools/configuration/commandline_parser.py +17 -11
- simtools/corsika/corsika_histograms.py +81 -0
- simtools/data_model/validate_data.py +8 -3
- simtools/db/db_handler.py +122 -31
- simtools/db/db_model_upload.py +51 -30
- simtools/dependencies.py +10 -5
- simtools/layout/array_layout_utils.py +37 -5
- simtools/model/array_model.py +18 -1
- simtools/model/model_repository.py +118 -63
- simtools/model/site_model.py +25 -0
- simtools/production_configuration/derive_corsika_limits.py +9 -34
- simtools/ray_tracing/incident_angles.py +706 -0
- simtools/ray_tracing/psf_parameter_optimisation.py +999 -565
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +2 -2
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_spectrum.schema.yml +22 -29
- simtools/schemas/model_parameters/stars.schema.yml +1 -1
- simtools/schemas/production_tables.schema.yml +5 -0
- simtools/simtel/simtel_config_writer.py +18 -20
- simtools/simtel/simtel_io_event_histograms.py +253 -516
- simtools/simtel/simtel_io_event_reader.py +51 -2
- simtools/simtel/simtel_io_event_writer.py +31 -11
- simtools/simtel/simtel_io_metadata.py +1 -1
- simtools/simtel/simtel_table_reader.py +3 -3
- simtools/simulator.py +1 -4
- simtools/telescope_trigger_rates.py +119 -0
- simtools/testing/log_inspector.py +13 -11
- simtools/utils/geometry.py +20 -0
- simtools/version.py +89 -0
- simtools/{corsika/corsika_histograms_visualize.py → visualization/plot_corsika_histograms.py} +109 -0
- simtools/visualization/plot_incident_angles.py +431 -0
- simtools/visualization/plot_psf.py +673 -0
- simtools/visualization/plot_simtel_event_histograms.py +376 -0
- simtools/visualization/{simtel_event_plots.py → plot_simtel_events.py} +284 -87
- simtools/visualization/visualize.py +1 -3
- simtools/applications/calculate_trigger_rate.py +0 -187
- simtools/applications/generate_sim_telarray_histograms.py +0 -196
- simtools/applications/maintain_simulation_model_add_production_table.py +0 -71
- simtools/simtel/simtel_io_histogram.py +0 -623
- simtools/simtel/simtel_io_histograms.py +0 -556
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"""Histograms for shower and triggered events."""
|
|
2
2
|
|
|
3
|
+
import copy
|
|
3
4
|
import logging
|
|
4
5
|
|
|
5
6
|
import astropy.units as u
|
|
6
|
-
import matplotlib.pyplot as plt
|
|
7
7
|
import numpy as np
|
|
8
|
-
from matplotlib.colors import LogNorm
|
|
9
8
|
|
|
10
9
|
from simtools.simtel.simtel_io_event_reader import SimtelIOEventDataReader
|
|
11
10
|
|
|
@@ -15,6 +14,7 @@ class SimtelIOEventHistograms:
|
|
|
15
14
|
Generate and fill histograms for shower and triggered events.
|
|
16
15
|
|
|
17
16
|
Event data is read from the reduced MC event data file.
|
|
17
|
+
Calculate cumulative and relative (efficiency) distributions.
|
|
18
18
|
|
|
19
19
|
Parameters
|
|
20
20
|
----------
|
|
@@ -31,54 +31,25 @@ class SimtelIOEventHistograms:
|
|
|
31
31
|
self._logger = logging.getLogger(__name__)
|
|
32
32
|
self.event_data_file = event_data_file
|
|
33
33
|
self.array_name = array_name
|
|
34
|
-
self.telescope_list = telescope_list
|
|
35
34
|
|
|
36
35
|
self.histograms = {}
|
|
37
36
|
self.file_info = {}
|
|
38
37
|
|
|
39
38
|
self.reader = SimtelIOEventDataReader(event_data_file, telescope_list=telescope_list)
|
|
40
39
|
|
|
41
|
-
def _fill_histogram_and_bin_edges(self, name, data, bins, hist1d=True):
|
|
42
|
-
"""
|
|
43
|
-
Fill histogram and bin edges and it both to histogram dictionary.
|
|
44
|
-
|
|
45
|
-
Adds histogram to existing histogram if it exists, otherwise initializes it.
|
|
46
|
-
|
|
47
|
-
"""
|
|
48
|
-
if name in self.histograms:
|
|
49
|
-
if hist1d:
|
|
50
|
-
bins = self.histograms[f"{name}_bin_edges"]
|
|
51
|
-
hist, _ = np.histogram(data, bins=bins)
|
|
52
|
-
self.histograms[name] += hist
|
|
53
|
-
else:
|
|
54
|
-
x_bins = self.histograms[f"{name}_bin_x_edges"]
|
|
55
|
-
y_bins = self.histograms[f"{name}_bin_y_edges"]
|
|
56
|
-
hist, _, _ = np.histogram2d(data[0], data[1], bins=[x_bins, y_bins])
|
|
57
|
-
self.histograms[name] += hist
|
|
58
|
-
else:
|
|
59
|
-
if hist1d:
|
|
60
|
-
hist, bin_edges = np.histogram(data, bins=bins)
|
|
61
|
-
self.histograms[name] = hist
|
|
62
|
-
self.histograms[f"{name}_bin_edges"] = bin_edges
|
|
63
|
-
else:
|
|
64
|
-
hist, x_edges, y_edges = np.histogram2d(data[0], data[1], bins=bins)
|
|
65
|
-
self.histograms[name] = hist
|
|
66
|
-
self.histograms[f"{name}_bin_x_edges"] = x_edges
|
|
67
|
-
self.histograms[f"{name}_bin_y_edges"] = y_edges
|
|
68
|
-
|
|
69
40
|
def fill(self):
|
|
70
41
|
"""
|
|
71
42
|
Fill histograms with event data.
|
|
72
43
|
|
|
73
44
|
Involves looping over all event data, and therefore is the slowest part of the
|
|
74
|
-
|
|
45
|
+
histogram module. Adds the histograms to the histogram dictionary.
|
|
75
46
|
|
|
76
47
|
Assume that all event data files are generated with similar configurations
|
|
77
|
-
(self.file_info contains the
|
|
48
|
+
(self.file_info contains the file info of the last file).
|
|
78
49
|
"""
|
|
79
50
|
for data_set in self.reader.data_sets:
|
|
80
51
|
self._logger.info(f"Reading event data from {self.event_data_file} for {data_set}")
|
|
81
|
-
_file_info_table,
|
|
52
|
+
_file_info_table, shower_data, event_data, triggered_data = self.reader.read_event_data(
|
|
82
53
|
self.event_data_file, table_name_map=data_set
|
|
83
54
|
)
|
|
84
55
|
_file_info_table = self.reader.get_reduced_simulation_file_info(_file_info_table)
|
|
@@ -86,533 +57,287 @@ class SimtelIOEventHistograms:
|
|
|
86
57
|
"energy_min": _file_info_table["energy_min"].to("TeV"),
|
|
87
58
|
"core_scatter_max": _file_info_table["core_scatter_max"].to("m"),
|
|
88
59
|
"viewcone_max": _file_info_table["viewcone_max"].to("deg"),
|
|
60
|
+
"solid_angle": _file_info_table["solid_angle"].to("sr"),
|
|
61
|
+
"scatter_area": _file_info_table["scatter_area"].to("cm2"),
|
|
89
62
|
}
|
|
90
63
|
|
|
91
|
-
self.
|
|
92
|
-
"energy", event_data.simulated_energy, self.energy_bins
|
|
93
|
-
)
|
|
94
|
-
self._fill_histogram_and_bin_edges(
|
|
95
|
-
"core_distance", event_data.core_distance_shower, self.core_distance_bins
|
|
96
|
-
)
|
|
97
|
-
self._fill_histogram_and_bin_edges(
|
|
98
|
-
"angular_distance", triggered_data.angular_distance, self.view_cone_bins
|
|
99
|
-
)
|
|
64
|
+
self.histograms = self._define_histograms(event_data, triggered_data, shower_data)
|
|
100
65
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
self.
|
|
104
|
-
len(self.core_distance_bins),
|
|
105
|
-
)
|
|
106
|
-
self._fill_histogram_and_bin_edges(
|
|
107
|
-
"shower_cores",
|
|
108
|
-
(event_data.x_core_shower, event_data.y_core_shower),
|
|
109
|
-
[xy_bins, xy_bins],
|
|
110
|
-
hist1d=False,
|
|
111
|
-
)
|
|
112
|
-
self._fill_histogram_and_bin_edges(
|
|
113
|
-
"core_vs_energy",
|
|
114
|
-
(event_data.core_distance_shower, event_data.simulated_energy),
|
|
115
|
-
[self.core_distance_bins, self.energy_bins],
|
|
116
|
-
hist1d=False,
|
|
117
|
-
)
|
|
118
|
-
self._fill_histogram_and_bin_edges(
|
|
119
|
-
"angular_distance_vs_energy",
|
|
120
|
-
(triggered_data.angular_distance, event_data.simulated_energy),
|
|
121
|
-
[self.view_cone_bins, self.energy_bins],
|
|
122
|
-
hist1d=False,
|
|
123
|
-
)
|
|
66
|
+
for name, data in self.histograms.items():
|
|
67
|
+
self._logger.debug(f"Filling histogram {name}")
|
|
68
|
+
self._fill_histogram_and_bin_edges(data)
|
|
124
69
|
|
|
125
|
-
|
|
126
|
-
def energy_bins(self):
|
|
127
|
-
"""Return bins for the energy histogram."""
|
|
128
|
-
if "energy_bin_edges" in self.histograms:
|
|
129
|
-
return self.histograms["energy_bin_edges"]
|
|
130
|
-
return np.logspace(
|
|
131
|
-
np.log10(self.file_info.get("energy_min", 1.0e-3 * u.TeV).to("TeV").value),
|
|
132
|
-
np.log10(self.file_info.get("energy_max", 1.0e3 * u.TeV).to("TeV").value),
|
|
133
|
-
100,
|
|
134
|
-
)
|
|
70
|
+
self.print_summary()
|
|
135
71
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"""Return bins for the core distance histogram."""
|
|
139
|
-
if "core_distance_bin_edges" in self.histograms:
|
|
140
|
-
return self.histograms["core_distance_bin_edges"]
|
|
141
|
-
return np.linspace(
|
|
142
|
-
self.file_info.get("core_scatter_min", 0.0 * u.m).to("m").value,
|
|
143
|
-
self.file_info.get("core_scatter_max", 1.0e5 * u.m).to("m").value,
|
|
144
|
-
100,
|
|
145
|
-
)
|
|
72
|
+
self.calculate_efficiency_data()
|
|
73
|
+
self.calculate_cumulative_data()
|
|
146
74
|
|
|
147
|
-
|
|
148
|
-
def view_cone_bins(self):
|
|
149
|
-
"""Return bins for the viewcone histogram."""
|
|
150
|
-
if "viewcone_bin_edges" in self.histograms:
|
|
151
|
-
return self.histograms["viewcone_bin_edges"]
|
|
152
|
-
return np.linspace(
|
|
153
|
-
self.file_info.get("viewcone_min", 0.0 * u.deg).to("deg").value,
|
|
154
|
-
self.file_info.get("viewcone_max", 20.0 * u.deg).to("deg").value,
|
|
155
|
-
100,
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
def plot_data(self, output_path=None, limits=None, rebin_factor=2):
|
|
75
|
+
def _define_histograms(self, event_data, triggered_data, shower_data):
|
|
159
76
|
"""
|
|
160
|
-
|
|
77
|
+
Define histograms including event data, binning, naming, and labels.
|
|
78
|
+
|
|
79
|
+
All histograms are defined for simulated and triggered events (note
|
|
80
|
+
the subtlety of triggered events being read from event_data and triggered_data).
|
|
161
81
|
|
|
162
82
|
Parameters
|
|
163
83
|
----------
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
- "viewcone_radius": Radius for the viewcone
|
|
171
|
-
rebin_factor: int, optional
|
|
172
|
-
Factor by which to reduce the number of bins in 2D histograms for rebinned plots.
|
|
173
|
-
Default is 2 (merge every 2 bins). Set to 0 or 1 to disable rebinning.
|
|
174
|
-
"""
|
|
175
|
-
# Plot label constants
|
|
176
|
-
core_distance_label = "Core Distance [m]"
|
|
177
|
-
energy_label = "Energy [TeV]"
|
|
178
|
-
pointing_direction_label = "Distance to pointing direction [deg]"
|
|
179
|
-
cumulative_prefix = "Cumulative "
|
|
180
|
-
event_count_label = "Event Count"
|
|
181
|
-
core_x_label = "Core X [m]"
|
|
182
|
-
core_y_label = "Core Y [m]"
|
|
183
|
-
|
|
184
|
-
# Plot parameter constants
|
|
185
|
-
hist_1d_params = {"color": "tab:green", "edgecolor": "tab:green", "lw": 1}
|
|
186
|
-
hist_1d_cumulative_params = {"color": "tab:blue", "edgecolor": "tab:blue", "lw": 1}
|
|
187
|
-
hist_2d_params = {"norm": "log", "cmap": "viridis", "show_contour": False}
|
|
188
|
-
hist_2d_equal_params = {
|
|
189
|
-
"norm": "log",
|
|
190
|
-
"cmap": "viridis",
|
|
191
|
-
"aspect": "equal",
|
|
192
|
-
"show_contour": False,
|
|
193
|
-
}
|
|
194
|
-
hist_2d_normalized_params = {"norm": "linear", "cmap": "viridis", "show_contour": True}
|
|
195
|
-
|
|
196
|
-
self._logger.info(f"Plotting histograms written to {output_path}")
|
|
84
|
+
event_data : EventData
|
|
85
|
+
The event data to use for filling the histograms.
|
|
86
|
+
triggered_data : TriggeredData
|
|
87
|
+
The triggered data to use for filling the histograms.
|
|
88
|
+
shower_data : ShowerData
|
|
89
|
+
The shower data to use for filling the histograms.
|
|
197
90
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
dict
|
|
94
|
+
Dictionary with histogram definitions.
|
|
95
|
+
"""
|
|
96
|
+
xy_bins = np.linspace(
|
|
97
|
+
-1.0 * self.core_distance_bins.max(),
|
|
98
|
+
self.core_distance_bins.max(),
|
|
99
|
+
len(self.core_distance_bins),
|
|
206
100
|
)
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
plots = {
|
|
220
|
-
"core_vs_energy": {
|
|
221
|
-
"data": self.histograms.get("core_vs_energy"),
|
|
222
|
-
"bins": [
|
|
223
|
-
self.histograms.get("core_vs_energy_bin_x_edges"),
|
|
224
|
-
self.histograms.get("core_vs_energy_bin_y_edges"),
|
|
225
|
-
],
|
|
226
|
-
"plot_type": "histogram2d",
|
|
227
|
-
"plot_params": hist_2d_params,
|
|
228
|
-
"labels": {
|
|
229
|
-
"x": core_distance_label,
|
|
230
|
-
"y": energy_label,
|
|
231
|
-
"title": "Triggered events: core distance vs energy",
|
|
232
|
-
},
|
|
233
|
-
"lines": {"x": upper_radius_limit, "y": lower_energy_limit},
|
|
234
|
-
"scales": {"y": "log"},
|
|
235
|
-
"colorbar_label": event_count_label,
|
|
236
|
-
"filename": "core_vs_energy_distribution",
|
|
237
|
-
},
|
|
238
|
-
"energy_distribution": {
|
|
239
|
-
"data": self.histograms.get("energy"),
|
|
240
|
-
"bins": self.histograms.get("energy_bin_edges"),
|
|
241
|
-
"plot_type": "histogram",
|
|
242
|
-
"plot_params": hist_1d_params,
|
|
243
|
-
"labels": {
|
|
244
|
-
"x": energy_label,
|
|
245
|
-
"y": event_count_label,
|
|
246
|
-
"title": "Triggered events: energy distribution",
|
|
247
|
-
},
|
|
248
|
-
"scales": {"x": "log", "y": "log"},
|
|
249
|
-
"lines": {"x": lower_energy_limit},
|
|
250
|
-
"filename": "energy_distribution",
|
|
251
|
-
},
|
|
252
|
-
"energy_distribution_cumulative": {
|
|
253
|
-
"data": cumulative_energy,
|
|
254
|
-
"bins": self.histograms.get("energy_bin_edges"),
|
|
255
|
-
"plot_type": "histogram",
|
|
256
|
-
"plot_params": hist_1d_cumulative_params,
|
|
257
|
-
"labels": {
|
|
258
|
-
"x": energy_label,
|
|
259
|
-
"y": cumulative_prefix + event_count_label,
|
|
260
|
-
"title": "Triggered events: cumulative energy distribution",
|
|
261
|
-
},
|
|
262
|
-
"scales": {"x": "log", "y": "log"},
|
|
263
|
-
"lines": {"x": lower_energy_limit},
|
|
264
|
-
"filename": "energy_distribution_cumulative",
|
|
101
|
+
hists = {}
|
|
102
|
+
|
|
103
|
+
energy_axis_title = "Energy (TeV)"
|
|
104
|
+
event_count_axis_title = "Event Count"
|
|
105
|
+
|
|
106
|
+
definitions = {
|
|
107
|
+
"energy": {
|
|
108
|
+
"event_data_column": "simulated_energy",
|
|
109
|
+
"event_data": event_data,
|
|
110
|
+
"bin_edges": self.energy_bins,
|
|
111
|
+
"axis_titles": [energy_axis_title, event_count_axis_title],
|
|
112
|
+
"plot_scales": {"x": "log", "y": "log"},
|
|
265
113
|
},
|
|
266
114
|
"core_distance": {
|
|
267
|
-
"
|
|
268
|
-
"
|
|
269
|
-
"
|
|
270
|
-
"
|
|
271
|
-
"labels": {
|
|
272
|
-
"x": core_distance_label,
|
|
273
|
-
"y": event_count_label,
|
|
274
|
-
"title": "Triggered events: core distance distribution",
|
|
275
|
-
},
|
|
276
|
-
"lines": {"x": upper_radius_limit},
|
|
277
|
-
"filename": "core_distance_distribution",
|
|
278
|
-
},
|
|
279
|
-
"core_distance_cumulative": {
|
|
280
|
-
"data": cumulative_core_distance,
|
|
281
|
-
"bins": self.histograms.get("core_distance_bin_edges"),
|
|
282
|
-
"plot_type": "histogram",
|
|
283
|
-
"plot_params": hist_1d_cumulative_params,
|
|
284
|
-
"labels": {
|
|
285
|
-
"x": core_distance_label,
|
|
286
|
-
"y": cumulative_prefix + event_count_label,
|
|
287
|
-
"title": "Triggered events: cumulative core distance distribution",
|
|
288
|
-
},
|
|
289
|
-
"lines": {"x": upper_radius_limit},
|
|
290
|
-
"filename": "core_distance_cumulative_distribution",
|
|
291
|
-
},
|
|
292
|
-
"core_xy": {
|
|
293
|
-
"data": self.histograms.get("shower_cores"),
|
|
294
|
-
"bins": [
|
|
295
|
-
self.histograms.get("shower_cores_bin_x_edges"),
|
|
296
|
-
self.histograms.get("shower_cores_bin_y_edges"),
|
|
297
|
-
],
|
|
298
|
-
"plot_type": "histogram2d",
|
|
299
|
-
"plot_params": hist_2d_equal_params,
|
|
300
|
-
"labels": {
|
|
301
|
-
"x": core_x_label,
|
|
302
|
-
"y": core_y_label,
|
|
303
|
-
"title": "Triggered events: core x vs core y",
|
|
304
|
-
},
|
|
305
|
-
"colorbar_label": event_count_label,
|
|
306
|
-
"lines": {
|
|
307
|
-
"r": upper_radius_limit,
|
|
308
|
-
},
|
|
309
|
-
"filename": "core_xy_distribution",
|
|
115
|
+
"event_data_column": "core_distance_shower",
|
|
116
|
+
"event_data": event_data,
|
|
117
|
+
"bin_edges": self.core_distance_bins,
|
|
118
|
+
"axis_titles": ["Core Distance (m)", event_count_axis_title],
|
|
310
119
|
},
|
|
311
120
|
"angular_distance": {
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
"
|
|
315
|
-
"
|
|
316
|
-
"labels": {
|
|
317
|
-
"x": pointing_direction_label,
|
|
318
|
-
"y": event_count_label,
|
|
319
|
-
"title": "Triggered events: angular distance distribution",
|
|
320
|
-
},
|
|
321
|
-
"lines": {"x": viewcone_radius},
|
|
322
|
-
"filename": "angular_distance_distribution",
|
|
323
|
-
},
|
|
324
|
-
"angular_distance_cumulative": {
|
|
325
|
-
"data": cumulative_angular_distance,
|
|
326
|
-
"bins": self.histograms.get("angular_distance_bin_edges"),
|
|
327
|
-
"plot_type": "histogram",
|
|
328
|
-
"plot_params": hist_1d_cumulative_params,
|
|
329
|
-
"labels": {
|
|
330
|
-
"x": pointing_direction_label,
|
|
331
|
-
"y": cumulative_prefix + event_count_label,
|
|
332
|
-
"title": "Triggered events: cumulative angular distance distribution",
|
|
333
|
-
},
|
|
334
|
-
"lines": {"x": viewcone_radius},
|
|
335
|
-
"filename": "angular_distance_cumulative_distribution",
|
|
121
|
+
"event_data_column": "angular_distance",
|
|
122
|
+
"event_data": triggered_data,
|
|
123
|
+
"bin_edges": self.view_cone_bins,
|
|
124
|
+
"axis_titles": ["Angular Distance (deg)", event_count_axis_title],
|
|
336
125
|
},
|
|
337
|
-
"
|
|
338
|
-
"
|
|
339
|
-
"
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
],
|
|
343
|
-
"plot_type": "histogram2d",
|
|
344
|
-
"plot_params": hist_2d_params,
|
|
345
|
-
"labels": {
|
|
346
|
-
"x": pointing_direction_label,
|
|
347
|
-
"y": energy_label,
|
|
348
|
-
"title": "Triggered events: angular distance distance vs energy",
|
|
349
|
-
},
|
|
350
|
-
"lines": {
|
|
351
|
-
"x": viewcone_radius,
|
|
352
|
-
"y": lower_energy_limit,
|
|
353
|
-
},
|
|
354
|
-
"scales": {"y": "log"},
|
|
355
|
-
"colorbar_label": event_count_label,
|
|
356
|
-
"filename": "angular_distance_vs_energy_distribution",
|
|
126
|
+
"x_core_shower_vs_y_core_shower": {
|
|
127
|
+
"event_data_column": ("x_core_shower", "y_core_shower"),
|
|
128
|
+
"event_data": (event_data, event_data),
|
|
129
|
+
"bin_edges": (xy_bins, xy_bins),
|
|
130
|
+
"is_1d": False,
|
|
131
|
+
"axis_titles": ["Core X (m)", "Core Y (m)", event_count_axis_title],
|
|
357
132
|
},
|
|
358
|
-
"
|
|
359
|
-
"
|
|
360
|
-
"
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
],
|
|
364
|
-
"
|
|
365
|
-
"plot_params": hist_2d_normalized_params, # Includes contour line at value=1
|
|
366
|
-
"labels": {
|
|
367
|
-
"x": pointing_direction_label,
|
|
368
|
-
"y": energy_label,
|
|
369
|
-
"title": "Triggered events: fraction of events by angular distance vs energy",
|
|
370
|
-
},
|
|
371
|
-
"lines": {
|
|
372
|
-
"x": viewcone_radius,
|
|
373
|
-
"y": lower_energy_limit,
|
|
374
|
-
},
|
|
375
|
-
"scales": {"y": "log"},
|
|
376
|
-
"colorbar_label": "Fraction of events",
|
|
377
|
-
"filename": "angular_distance_vs_energy_cumulative_distribution",
|
|
133
|
+
"core_vs_energy": {
|
|
134
|
+
"event_data_column": ("core_distance_shower", "simulated_energy"),
|
|
135
|
+
"event_data": (event_data, event_data),
|
|
136
|
+
"bin_edges": (self.core_distance_bins, self.energy_bins),
|
|
137
|
+
"is_1d": False,
|
|
138
|
+
"axis_titles": ["Core Distance (m)", energy_axis_title, event_count_axis_title],
|
|
139
|
+
"plot_scales": {"y": "log"},
|
|
378
140
|
},
|
|
379
|
-
"
|
|
380
|
-
"
|
|
381
|
-
"
|
|
382
|
-
|
|
383
|
-
|
|
141
|
+
"angular_distance_vs_energy": {
|
|
142
|
+
"event_data_column": ("angular_distance", "simulated_energy"),
|
|
143
|
+
"event_data": (triggered_data, event_data),
|
|
144
|
+
"bin_edges": (self.view_cone_bins, self.energy_bins),
|
|
145
|
+
"is_1d": False,
|
|
146
|
+
"axis_titles": [
|
|
147
|
+
"Angular Distance (deg)",
|
|
148
|
+
energy_axis_title,
|
|
149
|
+
event_count_axis_title,
|
|
384
150
|
],
|
|
385
|
-
"
|
|
386
|
-
"plot_params": hist_2d_normalized_params,
|
|
387
|
-
"labels": {
|
|
388
|
-
"x": core_distance_label,
|
|
389
|
-
"y": energy_label,
|
|
390
|
-
"title": "Triggered events: fraction of events by core distance vs energy",
|
|
391
|
-
},
|
|
392
|
-
"lines": {
|
|
393
|
-
"x": upper_radius_limit,
|
|
394
|
-
"y": lower_energy_limit,
|
|
395
|
-
},
|
|
396
|
-
"scales": {"y": "log"},
|
|
397
|
-
"colorbar_label": "Fraction of events",
|
|
398
|
-
"filename": "core_vs_energy_cumulative_distribution",
|
|
151
|
+
"plot_scales": {"y": "log"},
|
|
399
152
|
},
|
|
400
153
|
}
|
|
401
154
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
"""Extract limits from the provided dictionary for plotting."""
|
|
416
|
-
upper_radius_limit = None
|
|
417
|
-
lower_energy_limit = None
|
|
418
|
-
viewcone_radius = None
|
|
419
|
-
if limits:
|
|
420
|
-
upper_radius_limit = (
|
|
421
|
-
limits["upper_radius_limit"].value if "upper_radius_limit" in limits else None
|
|
422
|
-
)
|
|
423
|
-
lower_energy_limit = (
|
|
424
|
-
limits["lower_energy_limit"].value if "lower_energy_limit" in limits else None
|
|
425
|
-
)
|
|
426
|
-
viewcone_radius = (
|
|
427
|
-
limits["viewcone_radius"].value if "viewcone_radius" in limits else None
|
|
155
|
+
hists = {
|
|
156
|
+
name: self.get_histogram_definition(**cfg) | {"suffix": "", "title": "Triggered Events"}
|
|
157
|
+
for name, cfg in definitions.items()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
hists_mc = {}
|
|
161
|
+
for key, hist in hists.items():
|
|
162
|
+
key_mc = f"{key}_mc"
|
|
163
|
+
hists_mc[key_mc] = copy.copy(hist)
|
|
164
|
+
hists_mc[key_mc]["suffix"] = "_mc"
|
|
165
|
+
hists_mc[key_mc]["title"] = "Simulated Events"
|
|
166
|
+
hists_mc[key_mc]["event_data"] = (
|
|
167
|
+
shower_data if hist["1d"] else (shower_data, shower_data)
|
|
428
168
|
)
|
|
429
|
-
return upper_radius_limit, lower_energy_limit, viewcone_radius
|
|
430
169
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
Build the full plot filename with appropriate extensions.
|
|
170
|
+
hists.update(hists_mc)
|
|
171
|
+
return hists
|
|
434
172
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
173
|
+
def get_histogram_definition(
|
|
174
|
+
self,
|
|
175
|
+
event_data_column=None,
|
|
176
|
+
event_data=None,
|
|
177
|
+
histogram=None,
|
|
178
|
+
bin_edges=None,
|
|
179
|
+
title=None,
|
|
180
|
+
axis_titles=None,
|
|
181
|
+
suffix=None,
|
|
182
|
+
is_1d=True,
|
|
183
|
+
plot_scales=None,
|
|
184
|
+
):
|
|
185
|
+
"""Return a single histogram definition."""
|
|
186
|
+
return {
|
|
187
|
+
"histogram": histogram,
|
|
188
|
+
"event_data_column": event_data_column,
|
|
189
|
+
"event_data": event_data,
|
|
190
|
+
"1d": is_1d,
|
|
191
|
+
"bin_edges": bin_edges,
|
|
192
|
+
"title": title,
|
|
193
|
+
"axis_titles": axis_titles,
|
|
194
|
+
"suffix": suffix,
|
|
195
|
+
"plot_scales": plot_scales,
|
|
196
|
+
}
|
|
441
197
|
|
|
442
|
-
|
|
443
|
-
-------
|
|
444
|
-
str
|
|
445
|
-
Complete filename with extension
|
|
198
|
+
def _fill_histogram_and_bin_edges(self, data):
|
|
446
199
|
"""
|
|
447
|
-
|
|
448
|
-
return f"{base_filename}_{array_name}.png"
|
|
449
|
-
return f"{base_filename}.png"
|
|
200
|
+
Fill histogram and bin edges into the histogram dictionary.
|
|
450
201
|
|
|
451
|
-
|
|
202
|
+
Adds to existing histogram if present, otherwise initializes it.
|
|
452
203
|
"""
|
|
453
|
-
|
|
204
|
+
if data["1d"]:
|
|
205
|
+
hist, _ = np.histogram(
|
|
206
|
+
getattr(data["event_data"], data["event_data_column"]),
|
|
207
|
+
bins=data["bin_edges"],
|
|
208
|
+
)
|
|
209
|
+
else:
|
|
210
|
+
hist, _, _ = np.histogram2d(
|
|
211
|
+
getattr(data["event_data"][0], data["event_data_column"][0]),
|
|
212
|
+
getattr(data["event_data"][1], data["event_data_column"][1]),
|
|
213
|
+
bins=[data["bin_edges"][0], data["bin_edges"][1]],
|
|
214
|
+
)
|
|
454
215
|
|
|
455
|
-
|
|
456
|
-
----------
|
|
457
|
-
rebin_factor : int
|
|
458
|
-
Factor by which to rebin the energy axis
|
|
459
|
-
plot_args : dict
|
|
460
|
-
Plot arguments
|
|
461
|
-
plot_key : str
|
|
462
|
-
Key identifying the plot type
|
|
216
|
+
data["histogram"] = hist if data["histogram"] is None else data["histogram"] + hist
|
|
463
217
|
|
|
464
|
-
|
|
465
|
-
-------
|
|
466
|
-
bool
|
|
467
|
-
True if a rebinned plot should be created, False otherwise
|
|
218
|
+
def calculate_efficiency_data(self):
|
|
468
219
|
"""
|
|
469
|
-
|
|
470
|
-
rebin_factor > 1
|
|
471
|
-
and plot_args["plot_type"] == "histogram2d"
|
|
472
|
-
and plot_key.endswith("_cumulative")
|
|
473
|
-
and plot_args.get("plot_params", {}).get("norm") == "linear"
|
|
474
|
-
)
|
|
220
|
+
Calculate efficiency histograms (triggered divided by simulated).
|
|
475
221
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
Create a rebinned version of a 2D histogram plot.
|
|
222
|
+
Assumes that for each histogram with simulated events, there is a
|
|
223
|
+
corresponding histogram with triggered events.
|
|
479
224
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
filename : str
|
|
485
|
-
Filename of the original plot
|
|
486
|
-
output_path : Path or None
|
|
487
|
-
Path to save the plot to, or None
|
|
488
|
-
rebin_factor : int
|
|
489
|
-
Factor by which to rebin the energy axis
|
|
225
|
+
Returns
|
|
226
|
+
-------
|
|
227
|
+
dict
|
|
228
|
+
Dictionary containing the efficiency histograms.
|
|
490
229
|
"""
|
|
491
|
-
data = plot_args["data"]
|
|
492
|
-
bins = plot_args["bins"]
|
|
493
230
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
231
|
+
def calculate_efficiency(trig_hist, mc_hist):
|
|
232
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
233
|
+
return np.divide(
|
|
234
|
+
trig_hist,
|
|
235
|
+
mc_hist,
|
|
236
|
+
out=np.zeros_like(trig_hist, dtype=float),
|
|
237
|
+
where=mc_hist > 0,
|
|
238
|
+
)
|
|
497
239
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
240
|
+
eff_histograms = {}
|
|
241
|
+
for name, mc_hist in self.histograms.items():
|
|
242
|
+
if not name.endswith("_mc"):
|
|
243
|
+
continue
|
|
501
244
|
|
|
502
|
-
|
|
503
|
-
|
|
245
|
+
base_name = name[:-3]
|
|
246
|
+
trig_hist = self.histograms.get(base_name)
|
|
247
|
+
if trig_hist is None:
|
|
248
|
+
continue
|
|
504
249
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
250
|
+
if mc_hist["histogram"].shape != trig_hist["histogram"].shape:
|
|
251
|
+
self._logger.warning(
|
|
252
|
+
f"Shape mismatch for {base_name} and {name}, skipping efficiency calculation."
|
|
253
|
+
)
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
eff = copy.copy(mc_hist)
|
|
257
|
+
eff.update(
|
|
258
|
+
{
|
|
259
|
+
"histogram": calculate_efficiency(trig_hist["histogram"], mc_hist["histogram"]),
|
|
260
|
+
"suffix": "_eff",
|
|
261
|
+
"title": "Efficiency",
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
eff["axis_titles"] = copy.copy(mc_hist["axis_titles"])
|
|
265
|
+
eff["axis_titles"][-1] = "Efficiency"
|
|
266
|
+
eff_histograms[f"{base_name}_eff"] = eff
|
|
508
267
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
data,
|
|
512
|
-
bins=None,
|
|
513
|
-
plot_type="histogram",
|
|
514
|
-
plot_params=None,
|
|
515
|
-
labels=None,
|
|
516
|
-
scales=None,
|
|
517
|
-
colorbar_label=None,
|
|
518
|
-
output_file=None,
|
|
519
|
-
lines=None,
|
|
520
|
-
):
|
|
521
|
-
"""
|
|
522
|
-
Create and save a plot with the given parameters.
|
|
268
|
+
self.histograms.update(eff_histograms)
|
|
269
|
+
return eff_histograms
|
|
523
270
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
""
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
fig, ax = plt.subplots(figsize=(8, 6))
|
|
534
|
-
|
|
535
|
-
if plot_type == "histogram":
|
|
536
|
-
plt.bar(bins[:-1], data, width=np.diff(bins), **plot_params)
|
|
537
|
-
elif plot_type == "histogram2d":
|
|
538
|
-
pcm = self._create_2d_histogram_plot(data, bins, plot_params)
|
|
539
|
-
plt.colorbar(pcm, label=colorbar_label)
|
|
540
|
-
|
|
541
|
-
if "x" in lines:
|
|
542
|
-
plt.axvline(lines["x"], color="r", linestyle="--", linewidth=0.5)
|
|
543
|
-
if "y" in lines:
|
|
544
|
-
plt.axhline(lines["y"], color="r", linestyle="--", linewidth=0.5)
|
|
545
|
-
if "r" in lines:
|
|
546
|
-
circle = plt.Circle(
|
|
547
|
-
(0, 0), lines["r"], color="r", fill=False, linestyle="--", linewidth=0.5
|
|
548
|
-
)
|
|
549
|
-
plt.gca().add_artist(circle)
|
|
550
|
-
|
|
551
|
-
ax.set(
|
|
552
|
-
xlabel=labels.get("x", ""),
|
|
553
|
-
ylabel=labels.get("y", ""),
|
|
554
|
-
title=labels.get("title", ""),
|
|
555
|
-
xscale=scales.get("x", "linear"),
|
|
556
|
-
yscale=scales.get("y", "linear"),
|
|
271
|
+
@property
|
|
272
|
+
def energy_bins(self):
|
|
273
|
+
"""Return bins for the energy histogram."""
|
|
274
|
+
if "energy_bin_edges" in self.histograms:
|
|
275
|
+
return self.histograms["energy_bin_edges"]
|
|
276
|
+
return np.logspace(
|
|
277
|
+
np.log10(self.file_info.get("energy_min", 1.0e-3 * u.TeV).to("TeV").value),
|
|
278
|
+
np.log10(self.file_info.get("energy_max", 1.0e3 * u.TeV).to("TeV").value),
|
|
279
|
+
100,
|
|
557
280
|
)
|
|
558
281
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
282
|
+
@property
|
|
283
|
+
def core_distance_bins(self):
|
|
284
|
+
"""Return bins for the core distance histogram."""
|
|
285
|
+
if "core_distance_bin_edges" in self.histograms:
|
|
286
|
+
return self.histograms["core_distance_bin_edges"]
|
|
287
|
+
return np.linspace(
|
|
288
|
+
self.file_info.get("core_scatter_min", 0.0 * u.m).to("m").value,
|
|
289
|
+
self.file_info.get("core_scatter_max", 1.0e5 * u.m).to("m").value,
|
|
290
|
+
100,
|
|
291
|
+
)
|
|
566
292
|
|
|
567
|
-
|
|
293
|
+
@property
|
|
294
|
+
def view_cone_bins(self):
|
|
295
|
+
"""Return bins for the viewcone histogram."""
|
|
296
|
+
if "viewcone_bin_edges" in self.histograms:
|
|
297
|
+
return self.histograms["viewcone_bin_edges"]
|
|
298
|
+
return np.linspace(
|
|
299
|
+
self.file_info.get("viewcone_min", 0.0 * u.deg).to("deg").value,
|
|
300
|
+
self.file_info.get("viewcone_max", 20.0 * u.deg).to("deg").value,
|
|
301
|
+
100,
|
|
302
|
+
)
|
|
568
303
|
|
|
569
|
-
def
|
|
304
|
+
def calculate_cumulative_data(self):
|
|
570
305
|
"""
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
Parameters
|
|
574
|
-
----------
|
|
575
|
-
data : np.ndarray
|
|
576
|
-
2D histogram data
|
|
577
|
-
bins : tuple of np.ndarray
|
|
578
|
-
Bin edges for x and y axes
|
|
579
|
-
plot_params : dict
|
|
580
|
-
Plot parameters including norm, cmap, and show_contour
|
|
306
|
+
Calculate cumulative distributions for triggered histograms.
|
|
581
307
|
|
|
582
308
|
Returns
|
|
583
309
|
-------
|
|
584
|
-
|
|
585
|
-
|
|
310
|
+
dict
|
|
311
|
+
Dictionary containing the cumulative histograms.
|
|
586
312
|
"""
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
y_centers = (bins[1][1:] + bins[1][:-1]) / 2
|
|
600
|
-
x_mesh, y_mesh = np.meshgrid(x_centers, y_centers)
|
|
601
|
-
plt.contour(
|
|
602
|
-
x_mesh,
|
|
603
|
-
y_mesh,
|
|
604
|
-
data.T,
|
|
605
|
-
levels=[0.999999], # very close to 1 for floating point precision
|
|
606
|
-
colors=["tab:red"],
|
|
607
|
-
linestyles=["--"],
|
|
608
|
-
linewidths=[0.5],
|
|
609
|
-
)
|
|
610
|
-
else:
|
|
611
|
-
pcm = plt.pcolormesh(
|
|
612
|
-
bins[0], bins[1], data.T, norm=LogNorm(vmin=1, vmax=data.max()), cmap="viridis"
|
|
313
|
+
cumulative_data = {}
|
|
314
|
+
suffix = "_cumulative"
|
|
315
|
+
|
|
316
|
+
def add_cumulative(name, hist, **kwargs):
|
|
317
|
+
new = copy.copy(hist)
|
|
318
|
+
new["histogram"] = self._calculate_cumulative_histogram(hist["histogram"], **kwargs)
|
|
319
|
+
new["axis_titles"] = copy.copy(hist["axis_titles"])
|
|
320
|
+
new.update(
|
|
321
|
+
{
|
|
322
|
+
"suffix": suffix,
|
|
323
|
+
"title": "Cumulative triggered events",
|
|
324
|
+
}
|
|
613
325
|
)
|
|
326
|
+
new["axis_titles"][-1] = "Fraction of Events"
|
|
327
|
+
cumulative_data[f"{name}{suffix}"] = new
|
|
614
328
|
|
|
615
|
-
|
|
329
|
+
# 2D histograms vs energy
|
|
330
|
+
for name, hist in self.histograms.items():
|
|
331
|
+
if name.endswith("_vs_energy") and not name.endswith("_mc"):
|
|
332
|
+
add_cumulative(name, hist, axis=0, normalize=True)
|
|
333
|
+
|
|
334
|
+
# 1D histograms
|
|
335
|
+
for name in ["energy", "core_distance", "angular_distance"]:
|
|
336
|
+
if (hist := self.histograms.get(name)) is not None:
|
|
337
|
+
add_cumulative(name, hist, reverse=name == "energy")
|
|
338
|
+
|
|
339
|
+
self.histograms.update(cumulative_data)
|
|
340
|
+
return cumulative_data
|
|
616
341
|
|
|
617
342
|
def _calculate_cumulative_histogram(self, hist, reverse=False, axis=None, normalize=False):
|
|
618
343
|
"""
|
|
@@ -647,12 +372,13 @@ class SimtelIOEventHistograms:
|
|
|
647
372
|
result = result / np.sum(hist)
|
|
648
373
|
return result
|
|
649
374
|
|
|
650
|
-
if axis is None
|
|
651
|
-
axis = 1
|
|
652
|
-
|
|
375
|
+
axis = axis if axis is not None else 1
|
|
653
376
|
result = self._apply_cumsum_along_axis(hist.copy(), axis, reverse)
|
|
654
377
|
|
|
655
378
|
if normalize:
|
|
379
|
+
# Ensure floating dtype to allow in-place normalization without casting errors
|
|
380
|
+
if not np.issubdtype(result.dtype, np.floating):
|
|
381
|
+
result = result.astype(float)
|
|
656
382
|
self._normalize_along_axis(result, hist, axis)
|
|
657
383
|
|
|
658
384
|
return result
|
|
@@ -693,9 +419,7 @@ class SimtelIOEventHistograms:
|
|
|
693
419
|
|
|
694
420
|
def _calculate_cumulative_2d(self, hist, reverse, axis=None):
|
|
695
421
|
"""Calculate cumulative distribution for 2D histogram."""
|
|
696
|
-
if axis is None
|
|
697
|
-
axis = 1
|
|
698
|
-
|
|
422
|
+
axis = axis if axis is not None else 1
|
|
699
423
|
return self._apply_cumsum_along_axis(hist, axis, reverse)
|
|
700
424
|
|
|
701
425
|
def _apply_cumsum_along_axis(self, hist, axis, reverse):
|
|
@@ -706,7 +430,8 @@ class SimtelIOEventHistograms:
|
|
|
706
430
|
|
|
707
431
|
return np.apply_along_axis(cumsum_func, axis, hist)
|
|
708
432
|
|
|
709
|
-
|
|
433
|
+
@staticmethod
|
|
434
|
+
def rebin_2d_histogram(hist, x_bins, y_bins, rebin_factor=2):
|
|
710
435
|
"""
|
|
711
436
|
Rebin a 2D histogram by merging neighboring bins along the energy dimension (y-axis) only.
|
|
712
437
|
|
|
@@ -725,7 +450,7 @@ class SimtelIOEventHistograms:
|
|
|
725
450
|
Returns
|
|
726
451
|
-------
|
|
727
452
|
tuple
|
|
728
|
-
(
|
|
453
|
+
(re-binned_hist, x_bins, re-binned_y_bins)
|
|
729
454
|
"""
|
|
730
455
|
if rebin_factor <= 1:
|
|
731
456
|
return hist, x_bins, y_bins
|
|
@@ -744,3 +469,15 @@ class SimtelIOEventHistograms:
|
|
|
744
469
|
new_y_bins = y_bins[::rebin_factor]
|
|
745
470
|
|
|
746
471
|
return new_hist, x_bins, new_y_bins
|
|
472
|
+
|
|
473
|
+
def print_summary(self):
|
|
474
|
+
"""
|
|
475
|
+
Print a summary of the histogram statistics.
|
|
476
|
+
|
|
477
|
+
Total number of events is retrieved from the 'energy' histograms.
|
|
478
|
+
"""
|
|
479
|
+
total_simulated = np.sum(self.histograms.get("energy_mc", {}).get("histogram", []))
|
|
480
|
+
total_triggered = np.sum(self.histograms.get("energy", {}).get("histogram", []))
|
|
481
|
+
|
|
482
|
+
self._logger.info(f"Total simulated events: {total_simulated}")
|
|
483
|
+
self._logger.info(f"Total triggered events: {total_triggered}")
|