gammasimtools 0.13.0__py3-none-any.whl → 0.15.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.13.0.dist-info → gammasimtools-0.15.0.dist-info}/METADATA +3 -3
- {gammasimtools-0.13.0.dist-info → gammasimtools-0.15.0.dist-info}/RECORD +224 -217
- {gammasimtools-0.13.0.dist-info → gammasimtools-0.15.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.13.0.dist-info → gammasimtools-0.15.0.dist-info}/entry_points.txt +3 -1
- simtools/_version.py +2 -2
- simtools/applications/db_add_file_to_db.py +15 -0
- simtools/applications/db_add_value_from_json_to_db.py +18 -1
- simtools/applications/derive_ctao_array_layouts.py +120 -0
- simtools/applications/derive_photon_electron_spectrum.py +29 -1
- simtools/applications/docs_produce_array_element_report.py +41 -16
- simtools/applications/docs_produce_model_parameter_reports.py +28 -8
- simtools/applications/{production_extract_mc_event_data.py → generate_simtel_event_data.py} +12 -20
- simtools/applications/print_version.py +81 -0
- simtools/applications/production_derive_corsika_limits.py +172 -39
- simtools/applications/production_scale_events.py +59 -36
- simtools/applications/run_application.py +41 -11
- simtools/applications/simulate_light_emission.py +115 -247
- simtools/applications/simulate_prod_htcondor_generator.py +2 -2
- simtools/camera/single_photon_electron_spectrum.py +163 -15
- simtools/data_model/model_data_writer.py +7 -6
- simtools/db/db_handler.py +14 -8
- simtools/dependencies.py +38 -3
- simtools/layout/array_layout.py +1 -0
- simtools/layout/ctao_array_layouts.py +172 -0
- simtools/model/array_model.py +3 -4
- simtools/model/model_parameter.py +30 -87
- simtools/production_configuration/derive_corsika_limits.py +222 -154
- simtools/production_configuration/event_scaler.py +2 -2
- simtools/reporting/docs_auto_report_generator.py +217 -0
- simtools/reporting/docs_read_parameters.py +192 -110
- simtools/schemas/application_workflow.metaschema.yml +3 -0
- simtools/schemas/model_parameter.metaschema.yml +13 -0
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +6 -0
- simtools/schemas/model_parameters/adjust_gain.schema.yml +1 -1
- simtools/schemas/model_parameters/altitude.schema.yml +1 -1
- simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +3 -3
- simtools/schemas/model_parameters/array_element_position_ground.schema.yml +3 -3
- simtools/schemas/model_parameters/array_element_position_utm.schema.yml +3 -3
- simtools/schemas/model_parameters/array_window.schema.yml +1 -1
- simtools/schemas/model_parameters/asum_clipping.schema.yml +1 -1
- simtools/schemas/model_parameters/asum_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/asum_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/axes_offsets.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_body_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_body_shape.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_config_rotate.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_depth.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_pixels.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_transmission.schema.yml +1 -1
- simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_observation_level.schema.yml +1 -1
- simtools/schemas/model_parameters/dark_events.schema.yml +1 -1
- simtools/schemas/model_parameters/disc_bins.schema.yml +1 -1
- simtools/schemas/model_parameters/disc_start.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/dish_shape_length.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_prescale.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_presum_max.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +1 -1
- simtools/schemas/model_parameters/effective_focal_length.schema.yml +5 -5
- simtools/schemas/model_parameters/epsg_code.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_bins.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_max_signal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_max_sum.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_mhz.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_noise.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +1 -1
- simtools/schemas/model_parameters/focal_length.schema.yml +1 -1
- simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +20 -20
- simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +1 -1
- simtools/schemas/model_parameters/focus_offset.schema.yml +4 -4
- simtools/schemas/model_parameters/gain_variation.schema.yml +1 -1
- simtools/schemas/model_parameters/geomag_horizontal.schema.yml +1 -1
- simtools/schemas/model_parameters/geomag_rotation.schema.yml +1 -1
- simtools/schemas/model_parameters/geomag_vertical.schema.yml +1 -1
- simtools/schemas/model_parameters/hg_lg_variation.schema.yml +1 -1
- simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
- simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_external_trigger.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_var_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_wavelength.schema.yml +1 -1
- simtools/schemas/model_parameters/led_events.schema.yml +1 -1
- simtools/schemas/model_parameters/led_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/led_pulse_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +1 -1
- simtools/schemas/model_parameters/led_var_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
- simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +4 -4
- simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +4 -4
- simtools/schemas/model_parameters/mirror_class.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_focal_length.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +3 -3
- simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +3 -3
- simtools/schemas/model_parameters/multiplicity_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +45 -0
- simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +2 -2
- simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_offaxis.schema.yml +5 -5
- simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_reference_value.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_spectrum.schema.yml +2 -2
- simtools/schemas/model_parameters/num_gains.schema.yml +1 -1
- simtools/schemas/model_parameters/pedestal_events.schema.yml +1 -1
- simtools/schemas/model_parameters/photon_delay.schema.yml +1 -1
- simtools/schemas/model_parameters/photons_per_run.schema.yml +1 -1
- simtools/schemas/model_parameters/pixel_cells.schema.yml +1 -1
- simtools/schemas/model_parameters/pixels_parallel.schema.yml +1 -1
- simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_average_gain.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_gain_index.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_transit_time.schema.yml +4 -4
- simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +7 -3
- simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +20 -20
- simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +1 -1
- simtools/schemas/model_parameters/qe_variation.schema.yml +1 -1
- simtools/schemas/model_parameters/random_focal_length.schema.yml +2 -2
- simtools/schemas/model_parameters/random_mono_probability.schema.yml +38 -0
- simtools/schemas/model_parameters/reference_point_altitude.schema.yml +1 -1
- simtools/schemas/model_parameters/reference_point_latitude.schema.yml +4 -1
- simtools/schemas/model_parameters/reference_point_longitude.schema.yml +4 -1
- simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +1 -1
- simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +5 -5
- simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +20 -20
- simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/stars.schema.yml +36 -0
- simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
- simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_axis_height.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_random_angle.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_random_error.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_transmission.schema.yml +6 -6
- simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +1 -1
- simtools/schemas/model_parameters/teltrig_min_time.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_error.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_jitter.schema.yml +1 -1
- simtools/schemas/model_parameters/trigger_current_limit.schema.yml +1 -1
- simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +4 -4
- simtools/schemas/model_parameters/trigger_pixels.schema.yml +1 -1
- simtools/simtel/simtel_config_writer.py +70 -38
- simtools/simtel/simtel_io_event_reader.py +278 -0
- simtools/simtel/simtel_io_event_writer.py +317 -0
- simtools/simtel/simulator_light_emission.py +181 -67
- simtools/simulator.py +2 -2
- simtools/testing/configuration.py +18 -0
- simtools/utils/general.py +33 -7
- simtools/utils/geometry.py +19 -0
- simtools/utils/names.py +7 -1
- simtools/visualization/visualize.py +2 -2
- simtools/production_configuration/extract_mc_event_data.py +0 -253
- simtools/simtel/simtel_io_events.py +0 -265
- {gammasimtools-0.13.0.dist-info → gammasimtools-0.15.0.dist-info/licenses}/LICENSE +0 -0
- {gammasimtools-0.13.0.dist-info → gammasimtools-0.15.0.dist-info}/top_level.txt +0 -0
- /simtools/schemas/model_parameters/{nsb_skymap.schema.yml → nsb_sky_map.schema.yml} +0 -0
simtools/utils/general.py
CHANGED
|
@@ -180,13 +180,17 @@ def collect_data_from_file(file_name, yaml_document=None):
|
|
|
180
180
|
return collect_data_from_http(file_name)
|
|
181
181
|
|
|
182
182
|
suffix = Path(file_name).suffix.lower()
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
183
|
+
try:
|
|
184
|
+
with open(file_name, encoding="utf-8") as file:
|
|
185
|
+
if suffix == ".json":
|
|
186
|
+
return json.load(file)
|
|
187
|
+
if suffix == ".list":
|
|
188
|
+
return [line.strip() for line in file.readlines()]
|
|
189
|
+
if suffix in [".yml", ".yaml"]:
|
|
190
|
+
return _collect_data_from_yaml_file(file, file_name, yaml_document)
|
|
191
|
+
# broad exception to catch all possible errors in reading the file
|
|
192
|
+
except Exception as exc: # pylint: disable=broad-except
|
|
193
|
+
raise type(exc)(f"Failed to read file {file_name}: {exc}") from exc
|
|
190
194
|
return None
|
|
191
195
|
|
|
192
196
|
|
|
@@ -842,6 +846,28 @@ def _load_yaml_using_astropy(file):
|
|
|
842
846
|
return astropy_yaml.load(file)
|
|
843
847
|
|
|
844
848
|
|
|
849
|
+
def is_utf8_file(file_name):
|
|
850
|
+
"""
|
|
851
|
+
Check if a file is encoded in UTF-8.
|
|
852
|
+
|
|
853
|
+
Parameters
|
|
854
|
+
----------
|
|
855
|
+
file_name: str, Path
|
|
856
|
+
Name of the file to be checked.
|
|
857
|
+
|
|
858
|
+
Returns
|
|
859
|
+
-------
|
|
860
|
+
bool
|
|
861
|
+
True if the file is encoded in UTF-8, False otherwise.
|
|
862
|
+
"""
|
|
863
|
+
try:
|
|
864
|
+
with open(file_name, encoding="utf-8") as file:
|
|
865
|
+
file.read()
|
|
866
|
+
return True
|
|
867
|
+
except UnicodeDecodeError:
|
|
868
|
+
return False
|
|
869
|
+
|
|
870
|
+
|
|
845
871
|
def read_file_encoded_in_utf_or_latin(file_name):
|
|
846
872
|
"""
|
|
847
873
|
Read a file encoded in UTF-8 or Latin-1.
|
simtools/utils/geometry.py
CHANGED
|
@@ -161,3 +161,22 @@ def rotate(x, y, rotation_around_z_axis, rotation_around_y_axis=0):
|
|
|
161
161
|
y_trans = x * np.sin(rotation_around_z_axis) + y * np.cos(rotation_around_z_axis)
|
|
162
162
|
|
|
163
163
|
return x_trans, y_trans
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def calculate_circular_mean(angles):
|
|
167
|
+
"""
|
|
168
|
+
Calculate circular mean of angles in radians.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
angles: numpy.array
|
|
173
|
+
Array of angles in radians.
|
|
174
|
+
|
|
175
|
+
Returns
|
|
176
|
+
-------
|
|
177
|
+
float
|
|
178
|
+
Circular mean of the angles.
|
|
179
|
+
"""
|
|
180
|
+
sin_sum = np.sum(np.sin(angles))
|
|
181
|
+
cos_sum = np.sum(np.cos(angles))
|
|
182
|
+
return np.arctan2(sin_sum, cos_sum)
|
simtools/utils/names.py
CHANGED
|
@@ -513,6 +513,7 @@ def get_collection_name_from_parameter_name(parameter_name):
|
|
|
513
513
|
def get_simulation_software_name_from_parameter_name(
|
|
514
514
|
parameter_name,
|
|
515
515
|
simulation_software="sim_telarray",
|
|
516
|
+
set_meta_parameter=False,
|
|
516
517
|
):
|
|
517
518
|
"""
|
|
518
519
|
Get the name used in the given simulation software from the model parameter name.
|
|
@@ -526,6 +527,8 @@ def get_simulation_software_name_from_parameter_name(
|
|
|
526
527
|
Model parameter name.
|
|
527
528
|
simulation_software: str
|
|
528
529
|
Simulation software name.
|
|
530
|
+
set_meta_parameter: bool
|
|
531
|
+
If True, return values with 'set_meta_parameter' field set to True.
|
|
529
532
|
|
|
530
533
|
Returns
|
|
531
534
|
-------
|
|
@@ -537,7 +540,10 @@ def get_simulation_software_name_from_parameter_name(
|
|
|
537
540
|
raise KeyError(f"Parameter {parameter_name} without schema definition")
|
|
538
541
|
|
|
539
542
|
for software in _parameter.get("simulation_software", []):
|
|
540
|
-
if
|
|
543
|
+
if (
|
|
544
|
+
software.get("name") == simulation_software
|
|
545
|
+
and software.get("set_meta_parameter", False) is set_meta_parameter
|
|
546
|
+
):
|
|
541
547
|
return software.get("internal_parameter_name", parameter_name)
|
|
542
548
|
|
|
543
549
|
return None
|
|
@@ -197,7 +197,7 @@ def set_style(palette="default", big_plot=False):
|
|
|
197
197
|
raise KeyError(f"palette must be one of {', '.join(COLORS)}")
|
|
198
198
|
|
|
199
199
|
fontsize = {"default": 17, "big_plot": 30}
|
|
200
|
-
markersize = {"default":
|
|
200
|
+
markersize = {"default": 6, "big_plot": 18}
|
|
201
201
|
plot_size = "big_plot" if big_plot else "default"
|
|
202
202
|
|
|
203
203
|
plt.rc("lines", linewidth=2, markersize=markersize[plot_size])
|
|
@@ -740,7 +740,7 @@ def plot_array(
|
|
|
740
740
|
|
|
741
741
|
|
|
742
742
|
def initialize_tel_counters():
|
|
743
|
-
return
|
|
743
|
+
return dict.fromkeys(names.get_list_of_array_element_types(), 0)
|
|
744
744
|
|
|
745
745
|
|
|
746
746
|
def get_rotated_positions(telescopes, rotate_angle):
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
"""Generate a reduced dataset from given simulation event list and save the output to file."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
|
|
5
|
-
import numpy as np
|
|
6
|
-
import tables
|
|
7
|
-
from ctapipe.core import Container, Field
|
|
8
|
-
from ctapipe.io import HDF5TableWriter
|
|
9
|
-
from eventio import EventIOFile
|
|
10
|
-
from eventio.simtel import ArrayEvent, MCEvent, MCRunHeader, MCShower, TriggerInformation
|
|
11
|
-
|
|
12
|
-
DEFAULT_FILTERS = tables.Filters(complevel=5, complib="zlib", shuffle=True, bitshuffle=False)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class ReducedDatasetContainer(Container):
|
|
16
|
-
"""Container for reduced dataset information."""
|
|
17
|
-
|
|
18
|
-
simulated = Field(None, "Simulated energy")
|
|
19
|
-
core_x = Field(None, "X-coordinate of the shower core")
|
|
20
|
-
core_y = Field(None, "Y-coordinate of the shower core")
|
|
21
|
-
shower_sim_azimuth = Field(None, "Simulated azimuth angle of the shower")
|
|
22
|
-
shower_sim_altitude = Field(None, "Simulated altitude angle of the shower")
|
|
23
|
-
array_altitudes = Field(None, "Altitudes for the array")
|
|
24
|
-
array_azimuths = Field(None, "Azimuths for the array")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class TriggeredShowerContainer(Container):
|
|
28
|
-
"""Container for triggered shower information."""
|
|
29
|
-
|
|
30
|
-
shower_id_triggered = Field(None, "Triggered shower ID")
|
|
31
|
-
triggered_energies = Field(None, "Triggered energies")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class FileNamesContainer(Container):
|
|
35
|
-
"""Container for file names."""
|
|
36
|
-
|
|
37
|
-
file_names = Field(None, "Input file names")
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class MCEventExtractor:
|
|
41
|
-
"""
|
|
42
|
-
Generate a reduced dataset from given simulation event list and save the output to file.
|
|
43
|
-
|
|
44
|
-
Attributes
|
|
45
|
-
----------
|
|
46
|
-
input_files : list
|
|
47
|
-
List of input file paths to process.
|
|
48
|
-
output_file : str
|
|
49
|
-
Path to the output HDF5 file.
|
|
50
|
-
max_files : int, optional
|
|
51
|
-
Maximum number of files to process.
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
def __init__(self, input_files, output_file, max_files=100):
|
|
55
|
-
"""
|
|
56
|
-
Initialize the MCEventExtractor with input files, output file, and max file limit.
|
|
57
|
-
|
|
58
|
-
Parameters
|
|
59
|
-
----------
|
|
60
|
-
input_files : list
|
|
61
|
-
List of input file paths to process.
|
|
62
|
-
output_file : str
|
|
63
|
-
Path to the output HDF5 file.
|
|
64
|
-
max_files : int, optional
|
|
65
|
-
Maximum number of files to process.
|
|
66
|
-
"""
|
|
67
|
-
self._logger = logging.getLogger(__name__)
|
|
68
|
-
self.input_files = input_files
|
|
69
|
-
self.output_file = output_file
|
|
70
|
-
self.max_files = max_files
|
|
71
|
-
self.shower = None
|
|
72
|
-
self.n_use = None
|
|
73
|
-
self.shower_id_offset = 0
|
|
74
|
-
|
|
75
|
-
def process_files(self):
|
|
76
|
-
"""Process the input files and store them in an HDF5 file."""
|
|
77
|
-
if not self.input_files:
|
|
78
|
-
self._logger.warning("No input files provided.")
|
|
79
|
-
return
|
|
80
|
-
|
|
81
|
-
data_lists = self._initialize_data_lists()
|
|
82
|
-
self.shower_id_offset = 0
|
|
83
|
-
# Process the first file in write mode
|
|
84
|
-
self._logger.info(f"Processing file 1/{self.max_files}: {self.input_files[0]}")
|
|
85
|
-
self._process_file(self.input_files[0], data_lists, str(self.input_files[0]))
|
|
86
|
-
self._write_all_data(data_lists, mode="w")
|
|
87
|
-
self.shower_id_offset = len(data_lists["simulated"])
|
|
88
|
-
self._reset_data_lists(data_lists)
|
|
89
|
-
|
|
90
|
-
# Process remaining files in append mode
|
|
91
|
-
for i_file, file in enumerate(self.input_files[1 : self.max_files], start=2):
|
|
92
|
-
self._logger.info(f"Processing file {i_file}/{self.max_files}: {file}")
|
|
93
|
-
self._process_file(file, data_lists, str(file))
|
|
94
|
-
if len(data_lists["simulated"]) >= 1e7:
|
|
95
|
-
self._write_all_data(data_lists, mode="a")
|
|
96
|
-
self.shower_id_offset += len(data_lists["simulated"])
|
|
97
|
-
self._reset_data_lists(data_lists)
|
|
98
|
-
|
|
99
|
-
# Final write for any remaining data
|
|
100
|
-
self._write_all_data(data_lists, mode="a")
|
|
101
|
-
|
|
102
|
-
def _write_all_data(self, data_lists, mode):
|
|
103
|
-
"""Write all data sections at once helper method."""
|
|
104
|
-
self._write_data(data_lists, mode=mode)
|
|
105
|
-
self._write_variable_length_data(data_lists["trigger_telescope_list_list"], mode="a")
|
|
106
|
-
self._write_file_names(data_lists["file_names"], mode="a")
|
|
107
|
-
|
|
108
|
-
def _write_file_names(self, file_names, mode="a"):
|
|
109
|
-
"""Write file names to HDF5 file."""
|
|
110
|
-
print("file_names", file_names)
|
|
111
|
-
with HDF5TableWriter(
|
|
112
|
-
self.output_file, group_name="data", mode=mode, filters=DEFAULT_FILTERS
|
|
113
|
-
) as writer:
|
|
114
|
-
file_names_container = FileNamesContainer()
|
|
115
|
-
for file_name in file_names:
|
|
116
|
-
file_names_container.file_names = file_name
|
|
117
|
-
writer.write(table_name="file_names", containers=[file_names_container])
|
|
118
|
-
|
|
119
|
-
def _write_variable_length_data(self, trigger_telescope_list_list, mode="a"):
|
|
120
|
-
"""Write variable-length array data to HDF5 file."""
|
|
121
|
-
with tables.open_file(self.output_file, mode=mode) as f:
|
|
122
|
-
if "trigger_telescope_list_list" in f.root.data:
|
|
123
|
-
vlarray = f.root.data.trigger_telescope_list_list
|
|
124
|
-
else:
|
|
125
|
-
vlarray = f.create_vlarray(
|
|
126
|
-
f.root.data,
|
|
127
|
-
"trigger_telescope_list_list",
|
|
128
|
-
tables.Int16Atom(),
|
|
129
|
-
"List of triggered telescope IDs",
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
for item in trigger_telescope_list_list:
|
|
133
|
-
vlarray.append(item)
|
|
134
|
-
|
|
135
|
-
def _initialize_data_lists(self):
|
|
136
|
-
"""Initialize data lists."""
|
|
137
|
-
return {
|
|
138
|
-
"simulated": [],
|
|
139
|
-
"shower_id_triggered": [],
|
|
140
|
-
"triggered_energies": [],
|
|
141
|
-
"core_x": [],
|
|
142
|
-
"core_y": [],
|
|
143
|
-
"trigger_telescope_list_list": [],
|
|
144
|
-
"file_names": [],
|
|
145
|
-
"shower_sim_azimuth": [],
|
|
146
|
-
"shower_sim_altitude": [],
|
|
147
|
-
"array_altitudes": [],
|
|
148
|
-
"array_azimuths": [],
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
def _process_file(self, file, data_lists, file_name):
|
|
152
|
-
"""Process a single file and update data lists."""
|
|
153
|
-
with EventIOFile(file) as f:
|
|
154
|
-
array_altitude = None
|
|
155
|
-
array_azimuth = None
|
|
156
|
-
for eventio_object in f:
|
|
157
|
-
if isinstance(eventio_object, MCRunHeader):
|
|
158
|
-
self._process_mc_run_header(eventio_object, data_lists)
|
|
159
|
-
elif isinstance(eventio_object, MCShower):
|
|
160
|
-
self._process_mc_shower(
|
|
161
|
-
eventio_object, data_lists, array_altitude, array_azimuth
|
|
162
|
-
)
|
|
163
|
-
elif isinstance(eventio_object, MCEvent):
|
|
164
|
-
self._process_mc_event(eventio_object, data_lists)
|
|
165
|
-
elif isinstance(eventio_object, ArrayEvent):
|
|
166
|
-
self._process_array_event(eventio_object, data_lists)
|
|
167
|
-
data_lists["file_names"].extend([file_name])
|
|
168
|
-
|
|
169
|
-
def _process_mc_run_header(self, eventio_object, data_lists):
|
|
170
|
-
"""Process MC run header and update data lists."""
|
|
171
|
-
mc_head = eventio_object.parse()
|
|
172
|
-
self.n_use = mc_head["n_use"] # reuse factor n_use needed to extend the values below
|
|
173
|
-
array_altitude = np.mean(mc_head["alt_range"])
|
|
174
|
-
array_azimuth = np.mean(mc_head["az_range"])
|
|
175
|
-
data_lists["array_altitudes"].extend(self.n_use * [array_altitude])
|
|
176
|
-
data_lists["array_azimuths"].extend(self.n_use * [array_azimuth])
|
|
177
|
-
|
|
178
|
-
def _process_mc_shower(self, eventio_object, data_lists, array_altitude, array_azimuth):
|
|
179
|
-
"""Process MC shower and update data lists."""
|
|
180
|
-
self.shower = eventio_object.parse()
|
|
181
|
-
data_lists["simulated"].extend(self.n_use * [self.shower["energy"]])
|
|
182
|
-
data_lists["shower_sim_azimuth"].extend(self.n_use * [self.shower["azimuth"]])
|
|
183
|
-
data_lists["shower_sim_altitude"].extend(self.n_use * [self.shower["altitude"]])
|
|
184
|
-
data_lists["array_altitudes"].extend(self.n_use * [array_altitude])
|
|
185
|
-
data_lists["array_azimuths"].extend(self.n_use * [array_azimuth])
|
|
186
|
-
|
|
187
|
-
def _process_mc_event(self, eventio_object, data_lists):
|
|
188
|
-
"""Process MC event and update data lists."""
|
|
189
|
-
event = eventio_object.parse()
|
|
190
|
-
data_lists["core_x"].append(event["xcore"])
|
|
191
|
-
data_lists["core_y"].append(event["ycore"])
|
|
192
|
-
|
|
193
|
-
def _process_array_event(self, eventio_object, data_lists):
|
|
194
|
-
"""Process array event and update data lists."""
|
|
195
|
-
for i, obj in enumerate(eventio_object):
|
|
196
|
-
if i == 0 and isinstance(obj, TriggerInformation):
|
|
197
|
-
self._process_trigger_information(obj, data_lists)
|
|
198
|
-
|
|
199
|
-
def _process_trigger_information(self, trigger_info, data_lists):
|
|
200
|
-
"""Process trigger information and update data lists."""
|
|
201
|
-
trigger_info = trigger_info.parse()
|
|
202
|
-
telescopes = trigger_info["telescopes_with_data"]
|
|
203
|
-
if len(telescopes) > 0:
|
|
204
|
-
data_lists["shower_id_triggered"].append(self.shower["shower"] + self.shower_id_offset)
|
|
205
|
-
data_lists["triggered_energies"].append(self.shower["energy"])
|
|
206
|
-
data_lists["trigger_telescope_list_list"].append(np.array(telescopes, dtype=np.int16))
|
|
207
|
-
|
|
208
|
-
def _write_data(self, data_lists, mode="a"):
|
|
209
|
-
"""Write data to HDF5 file using HDF5TableWriter."""
|
|
210
|
-
with HDF5TableWriter(
|
|
211
|
-
self.output_file, group_name="data", mode=mode, filters=DEFAULT_FILTERS
|
|
212
|
-
) as writer:
|
|
213
|
-
# Write reduced dataset container
|
|
214
|
-
reduced_container = ReducedDatasetContainer()
|
|
215
|
-
for i in range(len(data_lists["simulated"])):
|
|
216
|
-
reduced_container.simulated = data_lists["simulated"][i]
|
|
217
|
-
reduced_container.core_x = data_lists["core_x"][i]
|
|
218
|
-
reduced_container.core_y = data_lists["core_y"][i]
|
|
219
|
-
reduced_container.shower_sim_azimuth = data_lists["shower_sim_azimuth"][i]
|
|
220
|
-
reduced_container.shower_sim_altitude = data_lists["shower_sim_altitude"][i]
|
|
221
|
-
reduced_container.array_altitudes = data_lists["array_altitudes"][i]
|
|
222
|
-
reduced_container.array_azimuths = data_lists["array_azimuths"][i]
|
|
223
|
-
writer.write(table_name="reduced_data", containers=[reduced_container])
|
|
224
|
-
|
|
225
|
-
# Write triggered shower container
|
|
226
|
-
triggered_container = TriggeredShowerContainer()
|
|
227
|
-
for i in range(len(data_lists["shower_id_triggered"])):
|
|
228
|
-
triggered_container.shower_id_triggered = data_lists["shower_id_triggered"][i]
|
|
229
|
-
triggered_container.triggered_energies = data_lists["triggered_energies"][i]
|
|
230
|
-
writer.write(table_name="triggered_data", containers=[triggered_container])
|
|
231
|
-
|
|
232
|
-
def _reset_data_lists(self, data_lists):
|
|
233
|
-
"""Reset data lists during batch processing."""
|
|
234
|
-
for key in data_lists:
|
|
235
|
-
data_lists[key] = []
|
|
236
|
-
|
|
237
|
-
def print_dataset_information(self):
|
|
238
|
-
"""Print information about the datasets in the generated HDF5 file."""
|
|
239
|
-
try:
|
|
240
|
-
with tables.open_file(self.output_file, mode="r") as reader:
|
|
241
|
-
print("Datasets in file:")
|
|
242
|
-
for key in reader.root.data._v_children.keys(): # pylint: disable=protected-access
|
|
243
|
-
dset = reader.root.data._v_children[key] # pylint: disable=protected-access
|
|
244
|
-
print(f"- {key}: shape={dset.shape}, dtype={dset.dtype}")
|
|
245
|
-
|
|
246
|
-
# Print first 5 values each
|
|
247
|
-
print(f" First 5 values: {dset[:5]}")
|
|
248
|
-
|
|
249
|
-
# Print units if available
|
|
250
|
-
# units = dset.attrs.get("units", "N/A")
|
|
251
|
-
# print(f" Units: {units}")
|
|
252
|
-
except Exception as exc:
|
|
253
|
-
raise ValueError("An error occurred while reading the HDF5 file") from exc
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
"""Read sim_telarray events from file."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
import math
|
|
5
|
-
from copy import copy
|
|
6
|
-
|
|
7
|
-
import astropy.units as u
|
|
8
|
-
import numpy as np
|
|
9
|
-
from eventio.simtel import SimTelFile
|
|
10
|
-
|
|
11
|
-
__all__ = ["InconsistentInputFileError", "SimtelIOEvents"]
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class InconsistentInputFileError(Exception):
|
|
15
|
-
"""Exception for inconsistent input file."""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class SimtelIOEvents:
|
|
19
|
-
"""
|
|
20
|
-
Read sim_telarray events from file.
|
|
21
|
-
|
|
22
|
-
sim_telarray files are read with eventio package.
|
|
23
|
-
|
|
24
|
-
Parameters
|
|
25
|
-
----------
|
|
26
|
-
input_files: list
|
|
27
|
-
List of sim_telarray output files (str of Path).
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
def __init__(self, input_files=None):
|
|
31
|
-
"""Initialize SimtelIOEvents."""
|
|
32
|
-
self._logger = logging.getLogger(__name__)
|
|
33
|
-
self.load_input_files(input_files)
|
|
34
|
-
if self.number_of_files > 0:
|
|
35
|
-
self.load_header_and_summary()
|
|
36
|
-
|
|
37
|
-
def load_input_files(self, files=None):
|
|
38
|
-
"""
|
|
39
|
-
Store list of input files into input_files attribute.
|
|
40
|
-
|
|
41
|
-
Parameters
|
|
42
|
-
----------
|
|
43
|
-
files: list
|
|
44
|
-
List of sim_telarray files (str or Path).
|
|
45
|
-
"""
|
|
46
|
-
if not hasattr(self, "input_files"):
|
|
47
|
-
self.input_files = []
|
|
48
|
-
|
|
49
|
-
if files is None:
|
|
50
|
-
msg = "No input file was given"
|
|
51
|
-
self._logger.debug(msg)
|
|
52
|
-
return
|
|
53
|
-
|
|
54
|
-
if not isinstance(files, list):
|
|
55
|
-
files = [files]
|
|
56
|
-
|
|
57
|
-
for file in files:
|
|
58
|
-
self.input_files.append(file)
|
|
59
|
-
|
|
60
|
-
@property
|
|
61
|
-
def number_of_files(self):
|
|
62
|
-
"""Return number of files loaded.
|
|
63
|
-
|
|
64
|
-
Returns
|
|
65
|
-
-------
|
|
66
|
-
int
|
|
67
|
-
Number of files loaded.
|
|
68
|
-
"""
|
|
69
|
-
return len(self.input_files) if hasattr(self, "input_files") else 0
|
|
70
|
-
|
|
71
|
-
def load_header_and_summary(self):
|
|
72
|
-
"""
|
|
73
|
-
Read MC header from sim_telarray files and store it into _mc_header.
|
|
74
|
-
|
|
75
|
-
Also fills summary_events with energy and core radius of triggered events.
|
|
76
|
-
"""
|
|
77
|
-
self._number_of_files = len(self.input_files)
|
|
78
|
-
keys_to_grab = [
|
|
79
|
-
"obsheight",
|
|
80
|
-
"n_showers",
|
|
81
|
-
"n_use",
|
|
82
|
-
"core_range",
|
|
83
|
-
"diffuse",
|
|
84
|
-
"viewcone",
|
|
85
|
-
"E_range",
|
|
86
|
-
"spectral_index",
|
|
87
|
-
"B_total",
|
|
88
|
-
]
|
|
89
|
-
self._mc_header = {}
|
|
90
|
-
|
|
91
|
-
def _are_headers_consistent(header0, header1):
|
|
92
|
-
comparison = {}
|
|
93
|
-
for k in keys_to_grab:
|
|
94
|
-
value = header0[k] == header1[k]
|
|
95
|
-
comparison[k] = value if isinstance(value, bool) else all(value)
|
|
96
|
-
|
|
97
|
-
return all(comparison)
|
|
98
|
-
|
|
99
|
-
is_first_file = True
|
|
100
|
-
number_of_triggered_events = 0
|
|
101
|
-
summary_energy, summary_rcore = [], []
|
|
102
|
-
for file in self.input_files:
|
|
103
|
-
with SimTelFile(file) as f:
|
|
104
|
-
for event in f:
|
|
105
|
-
en = event["mc_shower"]["energy"]
|
|
106
|
-
rc = math.sqrt(
|
|
107
|
-
math.pow(event["mc_event"]["xcore"], 2)
|
|
108
|
-
+ math.pow(event["mc_event"]["ycore"], 2)
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
summary_energy.append(en)
|
|
112
|
-
summary_rcore.append(rc)
|
|
113
|
-
number_of_triggered_events += 1
|
|
114
|
-
|
|
115
|
-
if is_first_file:
|
|
116
|
-
# First file - grabbing parameters
|
|
117
|
-
self._mc_header.update({k: copy(f.mc_run_headers[0][k]) for k in keys_to_grab})
|
|
118
|
-
else:
|
|
119
|
-
# Remaining files - Checking whether the parameters are consistent
|
|
120
|
-
if not _are_headers_consistent(self._mc_header, f.mc_run_headers[0]):
|
|
121
|
-
msg = "MC header pamameters from different files are inconsistent"
|
|
122
|
-
self._logger.error(msg)
|
|
123
|
-
raise InconsistentInputFileError(msg)
|
|
124
|
-
|
|
125
|
-
is_first_file = False
|
|
126
|
-
|
|
127
|
-
self.summary_events = {
|
|
128
|
-
"energy": np.array(summary_energy),
|
|
129
|
-
"r_core": np.array(summary_rcore),
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
# Calculating number of events
|
|
133
|
-
self._mc_header["n_events"] = (
|
|
134
|
-
self._mc_header["n_use"] * self._mc_header["n_showers"] * self._number_of_files
|
|
135
|
-
)
|
|
136
|
-
self._mc_header["n_triggered"] = number_of_triggered_events
|
|
137
|
-
|
|
138
|
-
@u.quantity_input(core_max=u.m)
|
|
139
|
-
def count_triggered_events(self, energy_range=None, core_max=None):
|
|
140
|
-
"""
|
|
141
|
-
Count number of triggered events within a certain energy range and core radius.
|
|
142
|
-
|
|
143
|
-
Parameters
|
|
144
|
-
----------
|
|
145
|
-
energy_range: Tuple with len 2
|
|
146
|
-
Max and min energy of energy range, e.g. energy_range=(100 * u.GeV, 10 * u.TeV).
|
|
147
|
-
core_max: astropy.Quantity distance
|
|
148
|
-
Maximum core radius for selecting showers, e.g. core_max=1000 * u.m.
|
|
149
|
-
|
|
150
|
-
Returns
|
|
151
|
-
-------
|
|
152
|
-
int
|
|
153
|
-
Number of triggered events.
|
|
154
|
-
"""
|
|
155
|
-
energy_range = self._validate_energy_range(energy_range)
|
|
156
|
-
core_max = self._validate_core_max(core_max)
|
|
157
|
-
|
|
158
|
-
is_in_energy_range = [
|
|
159
|
-
energy_range[0] < e < energy_range[1] for e in self.summary_events["energy"]
|
|
160
|
-
]
|
|
161
|
-
is_in_core_range = [r < core_max for r in self.summary_events["r_core"]]
|
|
162
|
-
return np.sum(np.array(is_in_energy_range) * np.array(is_in_core_range))
|
|
163
|
-
|
|
164
|
-
@u.quantity_input(core_max=u.m)
|
|
165
|
-
def select_events(self, energy_range=None, core_max=None):
|
|
166
|
-
"""
|
|
167
|
-
Select sim_telarray events within a certain energy range and core radius.
|
|
168
|
-
|
|
169
|
-
Parameters
|
|
170
|
-
----------
|
|
171
|
-
energy_range: Tuple len 2
|
|
172
|
-
Max and min energy of energy range, e.g. energy_range=(100 * u.GeV, 10 * u.TeV).
|
|
173
|
-
core_max: astropy.Quantity distance
|
|
174
|
-
Maximum core radius for selecting showers, e.g. core_max=1000 * u.m.
|
|
175
|
-
|
|
176
|
-
Returns
|
|
177
|
-
-------
|
|
178
|
-
list
|
|
179
|
-
List of events.
|
|
180
|
-
"""
|
|
181
|
-
energy_range = self._validate_energy_range(energy_range)
|
|
182
|
-
core_max = self._validate_core_max(core_max)
|
|
183
|
-
|
|
184
|
-
selected_events = []
|
|
185
|
-
for file in self.input_files:
|
|
186
|
-
with SimTelFile(file) as f:
|
|
187
|
-
for event in f:
|
|
188
|
-
energy = event["mc_shower"]["energy"]
|
|
189
|
-
if energy < energy_range[0] or energy > energy_range[1]:
|
|
190
|
-
continue
|
|
191
|
-
|
|
192
|
-
x_core = event["mc_event"]["xcore"]
|
|
193
|
-
y_core = event["mc_event"]["ycore"]
|
|
194
|
-
r_core = math.sqrt(math.pow(x_core, 2) + math.pow(y_core, 2))
|
|
195
|
-
if r_core > core_max:
|
|
196
|
-
continue
|
|
197
|
-
|
|
198
|
-
selected_events.append(event)
|
|
199
|
-
return selected_events
|
|
200
|
-
|
|
201
|
-
@u.quantity_input(core_max=u.m)
|
|
202
|
-
def count_simulated_events(self, energy_range=None, core_max=None):
|
|
203
|
-
"""
|
|
204
|
-
Determine number of simulated events within a certain energy range and core radius.
|
|
205
|
-
|
|
206
|
-
Use the simulated power law.
|
|
207
|
-
This calculation assumes the simulated spectrum is given by a single power law.
|
|
208
|
-
|
|
209
|
-
Parameters
|
|
210
|
-
----------
|
|
211
|
-
energy_range: Tuple len 2
|
|
212
|
-
Max and min energy of energy range, e.g. energy_range=(100 * u.GeV, 10 * u.TeV).
|
|
213
|
-
core_max: astropy.Quantity distance
|
|
214
|
-
Maximum core radius for selecting showers, e.g. core_max=1000 * u.m.
|
|
215
|
-
|
|
216
|
-
Returns
|
|
217
|
-
-------
|
|
218
|
-
int
|
|
219
|
-
Number of simulated events.
|
|
220
|
-
"""
|
|
221
|
-
energy_range = self._validate_energy_range(energy_range)
|
|
222
|
-
core_max = self._validate_core_max(core_max)
|
|
223
|
-
|
|
224
|
-
# energy factor
|
|
225
|
-
def integral(erange):
|
|
226
|
-
power = self._mc_header["spectral_index"] + 1
|
|
227
|
-
return math.pow(erange[0], power) - math.pow(erange[1], power)
|
|
228
|
-
|
|
229
|
-
energy_factor = integral(energy_range) / integral(self._mc_header["E_range"])
|
|
230
|
-
|
|
231
|
-
# core factor
|
|
232
|
-
core_factor = math.pow(core_max, 2) / math.pow(self._mc_header["core_range"][1], 2)
|
|
233
|
-
|
|
234
|
-
return self._mc_header["n_events"] * energy_factor * core_factor
|
|
235
|
-
|
|
236
|
-
def _validate_energy_range(self, energy_range):
|
|
237
|
-
"""
|
|
238
|
-
Return the default energy range from mc_header in case energy_range=None.
|
|
239
|
-
|
|
240
|
-
Check units, convert it to TeV and return it in the right format, otherwise.
|
|
241
|
-
"""
|
|
242
|
-
if energy_range is None:
|
|
243
|
-
return self._mc_header["E_range"]
|
|
244
|
-
|
|
245
|
-
if not isinstance(energy_range[0], u.Quantity) or not isinstance(
|
|
246
|
-
energy_range[1], u.Quantity
|
|
247
|
-
):
|
|
248
|
-
msg = "energy_range must be given as u.Quantity in units of energy"
|
|
249
|
-
self._logger.error(msg)
|
|
250
|
-
raise TypeError(msg)
|
|
251
|
-
|
|
252
|
-
try:
|
|
253
|
-
return (energy_range[0].to(u.TeV).value, energy_range[1].to(u.TeV).value)
|
|
254
|
-
except u.core.UnitConversionError as e:
|
|
255
|
-
msg = "energy_range must be in units of energy"
|
|
256
|
-
self._logger.error(msg)
|
|
257
|
-
raise TypeError(msg) from e
|
|
258
|
-
|
|
259
|
-
def _validate_core_max(self, core_max):
|
|
260
|
-
"""
|
|
261
|
-
Return the default core_max from mc_header in case core_max=None.
|
|
262
|
-
|
|
263
|
-
Check units, convert it to m and return it in the right format, otherwise.
|
|
264
|
-
"""
|
|
265
|
-
return self._mc_header["core_range"][1] if core_max is None else core_max.to(u.m).value
|
|
File without changes
|
|
File without changes
|
|
File without changes
|