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
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"""Generate a reduced dataset from given simulation event list and save the output to file."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import tables
|
|
8
|
+
from eventio import EventIOFile
|
|
9
|
+
from eventio.simtel import (
|
|
10
|
+
ArrayEvent,
|
|
11
|
+
MCEvent,
|
|
12
|
+
MCRunHeader,
|
|
13
|
+
MCShower,
|
|
14
|
+
TrackingPosition,
|
|
15
|
+
TriggerInformation,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from simtools.utils.geometry import calculate_circular_mean
|
|
19
|
+
|
|
20
|
+
DEFAULT_FILTERS = tables.Filters(complevel=5, complib="zlib", shuffle=True, bitshuffle=False)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ShowerEventData:
|
|
25
|
+
"""Shower event data."""
|
|
26
|
+
|
|
27
|
+
simulated_energy: list = field(default_factory=list)
|
|
28
|
+
x_core: list = field(default_factory=list)
|
|
29
|
+
y_core: list = field(default_factory=list)
|
|
30
|
+
shower_azimuth: list = field(default_factory=list)
|
|
31
|
+
shower_altitude: list = field(default_factory=list)
|
|
32
|
+
shower_id: list = field(default_factory=list)
|
|
33
|
+
area_weight: list = field(default_factory=list)
|
|
34
|
+
|
|
35
|
+
x_core_shower: list = field(default_factory=list)
|
|
36
|
+
y_core_shower: list = field(default_factory=list)
|
|
37
|
+
core_distance_shower: list = field(default_factory=list)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class TriggeredEventData:
|
|
42
|
+
"""Triggered event data."""
|
|
43
|
+
|
|
44
|
+
triggered_id: list = field(default_factory=list)
|
|
45
|
+
array_altitudes: list = field(default_factory=list)
|
|
46
|
+
array_azimuths: list = field(default_factory=list)
|
|
47
|
+
trigger_telescope_list_list: list = field(default_factory=list)
|
|
48
|
+
angular_distance: list = field(default_factory=list)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class SimtelIOEventDataWriter:
|
|
52
|
+
"""
|
|
53
|
+
Generate a reduced dataset from given simulation event list and save the output to file.
|
|
54
|
+
|
|
55
|
+
Attributes
|
|
56
|
+
----------
|
|
57
|
+
input_files : list
|
|
58
|
+
List of input file paths to process.
|
|
59
|
+
output_file : str
|
|
60
|
+
Path to the output file.
|
|
61
|
+
max_files : int, optional
|
|
62
|
+
Maximum number of files to process.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(self, input_files, output_file, max_files=100):
|
|
66
|
+
"""Initialize class."""
|
|
67
|
+
self._logger = logging.getLogger(__name__)
|
|
68
|
+
self.input_files = input_files
|
|
69
|
+
self.output_file = output_file
|
|
70
|
+
try:
|
|
71
|
+
self.max_files = max_files if max_files < len(input_files) else len(input_files)
|
|
72
|
+
except TypeError as exc:
|
|
73
|
+
raise TypeError("No input files provided.") from exc
|
|
74
|
+
self.shower = None
|
|
75
|
+
self.n_use = None
|
|
76
|
+
self.shower_id_offset = 0
|
|
77
|
+
self.event_data = ShowerEventData()
|
|
78
|
+
self.triggered_data = TriggeredEventData()
|
|
79
|
+
self.file_names = []
|
|
80
|
+
|
|
81
|
+
def process_files(self):
|
|
82
|
+
"""Process the input files and store them in an file."""
|
|
83
|
+
self.shower_id_offset = 0
|
|
84
|
+
|
|
85
|
+
for i, file in enumerate(self.input_files[: self.max_files], start=1):
|
|
86
|
+
self._logger.info(f"Processing file {i}/{self.max_files}: {file}")
|
|
87
|
+
self._process_file(file)
|
|
88
|
+
if i == 1 or len(self.event_data.simulated_energy) >= 1e7:
|
|
89
|
+
self._write_data(mode="w" if i == 1 else "a")
|
|
90
|
+
self.shower_id_offset += len(self.event_data.simulated_energy)
|
|
91
|
+
self._reset_data()
|
|
92
|
+
|
|
93
|
+
self._write_data(mode="a")
|
|
94
|
+
|
|
95
|
+
def get_event_data(self):
|
|
96
|
+
"""
|
|
97
|
+
Return shower and triggered event data.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
ShowerEventData, TriggeredEventData
|
|
102
|
+
Shower and triggered event data.
|
|
103
|
+
"""
|
|
104
|
+
return self.event_data, self.triggered_data
|
|
105
|
+
|
|
106
|
+
def _process_file(self, file):
|
|
107
|
+
"""Process a single file and update data lists."""
|
|
108
|
+
with EventIOFile(file) as f:
|
|
109
|
+
for eventio_object in f:
|
|
110
|
+
if isinstance(eventio_object, MCRunHeader):
|
|
111
|
+
self._process_mc_run_header(eventio_object)
|
|
112
|
+
elif isinstance(eventio_object, MCShower):
|
|
113
|
+
self._process_mc_shower(eventio_object)
|
|
114
|
+
elif isinstance(eventio_object, MCEvent):
|
|
115
|
+
self._process_mc_event(eventio_object)
|
|
116
|
+
elif isinstance(eventio_object, ArrayEvent):
|
|
117
|
+
self._process_array_event(eventio_object)
|
|
118
|
+
self.file_names.append(str(file))
|
|
119
|
+
|
|
120
|
+
def _process_mc_run_header(self, eventio_object):
|
|
121
|
+
"""Process MC run header and update data lists."""
|
|
122
|
+
mc_head = eventio_object.parse()
|
|
123
|
+
self.n_use = mc_head["n_use"] # reuse factor n_use needed to extend the values below
|
|
124
|
+
self._logger.info(f"Shower reuse factor: {self.n_use} (viewcone: {mc_head['viewcone']})")
|
|
125
|
+
|
|
126
|
+
def _process_mc_shower(self, eventio_object):
|
|
127
|
+
"""
|
|
128
|
+
Process MC shower and update shower event list.
|
|
129
|
+
|
|
130
|
+
Duplicated entries 'self.n_use' times to match the number simulated events with
|
|
131
|
+
different core positions.
|
|
132
|
+
"""
|
|
133
|
+
self.shower = eventio_object.parse()
|
|
134
|
+
|
|
135
|
+
self.event_data.simulated_energy.extend([self.shower["energy"]] * self.n_use)
|
|
136
|
+
self.event_data.shower_azimuth.extend([self.shower["azimuth"]] * self.n_use)
|
|
137
|
+
self.event_data.shower_altitude.extend([self.shower["altitude"]] * self.n_use)
|
|
138
|
+
|
|
139
|
+
def _process_mc_event(self, eventio_object):
|
|
140
|
+
"""Process MC event and update shower event list."""
|
|
141
|
+
event = eventio_object.parse()
|
|
142
|
+
|
|
143
|
+
self.event_data.shower_id.append(event["shower_num"])
|
|
144
|
+
self.event_data.x_core.append(event["xcore"])
|
|
145
|
+
self.event_data.y_core.append(event["ycore"])
|
|
146
|
+
self.event_data.area_weight.append(event["aweight"])
|
|
147
|
+
|
|
148
|
+
def _process_array_event(self, eventio_object):
|
|
149
|
+
"""Process array event and update triggered event list."""
|
|
150
|
+
tracking_positions = []
|
|
151
|
+
|
|
152
|
+
for _, obj in enumerate(eventio_object):
|
|
153
|
+
if isinstance(obj, TriggerInformation):
|
|
154
|
+
self._process_trigger_information(obj)
|
|
155
|
+
|
|
156
|
+
if isinstance(obj, TrackingPosition):
|
|
157
|
+
tracking_position = obj.parse()
|
|
158
|
+
tracking_positions.append(
|
|
159
|
+
{
|
|
160
|
+
"altitude": tracking_position["altitude_raw"],
|
|
161
|
+
"azimuth": tracking_position["azimuth_raw"],
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if tracking_positions:
|
|
166
|
+
self._process_tracking_positions(tracking_positions)
|
|
167
|
+
|
|
168
|
+
def _process_tracking_positions(self, tracking_positions):
|
|
169
|
+
"""
|
|
170
|
+
Process collected tracking positions and update triggered event list.
|
|
171
|
+
|
|
172
|
+
Use mean telescope tracking positions, averaged over all triggered telescopes.
|
|
173
|
+
"""
|
|
174
|
+
altitudes = [pos["altitude"] for pos in tracking_positions]
|
|
175
|
+
azimuths = [pos["azimuth"] for pos in tracking_positions]
|
|
176
|
+
|
|
177
|
+
self.triggered_data.array_altitudes.append(np.mean(altitudes))
|
|
178
|
+
self.triggered_data.array_azimuths.append(calculate_circular_mean(azimuths))
|
|
179
|
+
|
|
180
|
+
def _process_trigger_information(self, trigger_info):
|
|
181
|
+
"""Process trigger information and update triggered event list."""
|
|
182
|
+
trigger_info = trigger_info.parse()
|
|
183
|
+
telescopes = trigger_info["triggered_telescopes"]
|
|
184
|
+
if len(telescopes) > 0:
|
|
185
|
+
# add offset to obtain unique shower IDs among all files
|
|
186
|
+
self.triggered_data.triggered_id.append(self.shower["shower"] + self.shower_id_offset)
|
|
187
|
+
self.triggered_data.trigger_telescope_list_list.append(
|
|
188
|
+
np.array(telescopes, dtype=np.int16)
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def _table_descriptions(self):
|
|
192
|
+
"""HDF5 table descriptions for shower data, triggered data, and file names."""
|
|
193
|
+
shower_data_desc = {
|
|
194
|
+
"shower_id": tables.Int32Col(),
|
|
195
|
+
"simulated_energy": tables.Float32Col(),
|
|
196
|
+
"x_core": tables.Float32Col(),
|
|
197
|
+
"y_core": tables.Float32Col(),
|
|
198
|
+
"area_weight": tables.Float32Col(),
|
|
199
|
+
"shower_azimuth": tables.Float32Col(),
|
|
200
|
+
"shower_altitude": tables.Float32Col(),
|
|
201
|
+
}
|
|
202
|
+
triggered_data_desc = {
|
|
203
|
+
"triggered_id": tables.Int32Col(),
|
|
204
|
+
"array_altitudes": tables.Float32Col(),
|
|
205
|
+
"array_azimuths": tables.Float32Col(),
|
|
206
|
+
"telescope_list_index": tables.Int32Col(), # Index into VLArray
|
|
207
|
+
}
|
|
208
|
+
file_names_desc = {
|
|
209
|
+
"file_names": tables.StringCol(256),
|
|
210
|
+
}
|
|
211
|
+
return shower_data_desc, triggered_data_desc, file_names_desc
|
|
212
|
+
|
|
213
|
+
def _tables(self, output_file, data_group, mode="a"):
|
|
214
|
+
"""Create or get HDF5 tables."""
|
|
215
|
+
descriptions = self._table_descriptions()
|
|
216
|
+
table_names = ["reduced_data", "triggered_data", "file_names"]
|
|
217
|
+
|
|
218
|
+
table_dict = {}
|
|
219
|
+
for name, desc in zip(table_names, descriptions):
|
|
220
|
+
path = f"/data/{name}"
|
|
221
|
+
table_dict[name] = (
|
|
222
|
+
output_file.create_table(
|
|
223
|
+
data_group, name, desc, name.replace("_", " ").title(), filters=DEFAULT_FILTERS
|
|
224
|
+
)
|
|
225
|
+
if mode == "w" or path not in output_file
|
|
226
|
+
else output_file.get_node(path)
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
return table_dict["reduced_data"], table_dict["triggered_data"], table_dict["file_names"]
|
|
230
|
+
|
|
231
|
+
def _write_event_data(self, reduced_table):
|
|
232
|
+
"""Fill event data tables."""
|
|
233
|
+
if len(self.event_data.simulated_energy) == 0:
|
|
234
|
+
return
|
|
235
|
+
row = reduced_table.row
|
|
236
|
+
for i, energy in enumerate(self.event_data.simulated_energy):
|
|
237
|
+
row["shower_id"] = (
|
|
238
|
+
self.event_data.shower_id[i] if i < len(self.event_data.shower_id) else 0
|
|
239
|
+
)
|
|
240
|
+
row["simulated_energy"] = energy
|
|
241
|
+
row["x_core"] = self.event_data.x_core[i] if i < len(self.event_data.x_core) else 0
|
|
242
|
+
row["y_core"] = self.event_data.y_core[i] if i < len(self.event_data.y_core) else 0
|
|
243
|
+
row["area_weight"] = (
|
|
244
|
+
self.event_data.area_weight[i] if i < len(self.event_data.area_weight) else 0
|
|
245
|
+
)
|
|
246
|
+
row["shower_azimuth"] = (
|
|
247
|
+
self.event_data.shower_azimuth[i] if i < len(self.event_data.shower_azimuth) else 0
|
|
248
|
+
)
|
|
249
|
+
row["shower_altitude"] = (
|
|
250
|
+
self.event_data.shower_altitude[i]
|
|
251
|
+
if i < len(self.event_data.shower_altitude)
|
|
252
|
+
else 0
|
|
253
|
+
)
|
|
254
|
+
row.append()
|
|
255
|
+
reduced_table.flush()
|
|
256
|
+
|
|
257
|
+
def _writer_triggered_data(self, triggered_table, vlarray):
|
|
258
|
+
"""Fill triggered event data tables."""
|
|
259
|
+
# Get or create VLArray for telescope lists
|
|
260
|
+
if len(self.triggered_data.triggered_id) == 0:
|
|
261
|
+
return
|
|
262
|
+
row = triggered_table.row
|
|
263
|
+
start_idx = vlarray.nrows
|
|
264
|
+
for i, triggered_id in enumerate(self.triggered_data.triggered_id):
|
|
265
|
+
row["triggered_id"] = triggered_id
|
|
266
|
+
row["array_altitudes"] = (
|
|
267
|
+
self.triggered_data.array_altitudes[i]
|
|
268
|
+
if i < len(self.triggered_data.array_altitudes)
|
|
269
|
+
else 0
|
|
270
|
+
)
|
|
271
|
+
row["array_azimuths"] = (
|
|
272
|
+
self.triggered_data.array_azimuths[i]
|
|
273
|
+
if i < len(self.triggered_data.array_azimuths)
|
|
274
|
+
else 0
|
|
275
|
+
)
|
|
276
|
+
row["telescope_list_index"] = start_idx + i # Index into the VLArray
|
|
277
|
+
row.append()
|
|
278
|
+
vlarray.append(
|
|
279
|
+
self.triggered_data.trigger_telescope_list_list[i]
|
|
280
|
+
if i < len(self.triggered_data.trigger_telescope_list_list)
|
|
281
|
+
else []
|
|
282
|
+
)
|
|
283
|
+
triggered_table.flush()
|
|
284
|
+
|
|
285
|
+
def _write_data(self, mode="a"):
|
|
286
|
+
"""Write data to HDF5 file."""
|
|
287
|
+
with tables.open_file(self.output_file, mode=mode) as f:
|
|
288
|
+
data_group = (
|
|
289
|
+
f.create_group("/", "data", "Data group")
|
|
290
|
+
if mode == "w" or "/data" not in f
|
|
291
|
+
else f.get_node("/data")
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
reduced_table, triggered_table, file_names_table = self._tables(f, data_group, mode)
|
|
295
|
+
self._write_event_data(reduced_table)
|
|
296
|
+
|
|
297
|
+
vlarray = (
|
|
298
|
+
f.create_vlarray(
|
|
299
|
+
data_group,
|
|
300
|
+
"trigger_telescope_list_list",
|
|
301
|
+
tables.Int16Atom(),
|
|
302
|
+
"List of triggered telescope IDs",
|
|
303
|
+
)
|
|
304
|
+
if mode == "w" or "/data/trigger_telescope_list_list" not in f
|
|
305
|
+
else f.get_node("/data/trigger_telescope_list_list")
|
|
306
|
+
)
|
|
307
|
+
self._writer_triggered_data(triggered_table, vlarray)
|
|
308
|
+
|
|
309
|
+
if self.file_names:
|
|
310
|
+
file_names_table.append([[name] for name in self.file_names])
|
|
311
|
+
file_names_table.flush()
|
|
312
|
+
|
|
313
|
+
def _reset_data(self):
|
|
314
|
+
"""Reset data structures for batch processing."""
|
|
315
|
+
self.event_data = ShowerEventData()
|
|
316
|
+
self.triggered_data = TriggeredEventData()
|
|
317
|
+
self.file_names = []
|
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import stat
|
|
5
|
+
import subprocess
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
import astropy.units as u
|
|
8
9
|
import numpy as np
|
|
9
10
|
|
|
11
|
+
from simtools.corsika.corsika_histograms_visualize import save_figs_to_pdf
|
|
10
12
|
from simtools.io_operations import io_handler
|
|
11
13
|
from simtools.runners.simtel_runner import SimtelRunner
|
|
12
14
|
from simtools.utils.general import clear_default_sim_telarray_cfg_directories
|
|
15
|
+
from simtools.visualization.visualize import plot_simtel_ctapipe
|
|
13
16
|
|
|
14
17
|
__all__ = ["SimulatorLightEmission"]
|
|
15
18
|
|
|
@@ -18,36 +21,7 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
18
21
|
"""
|
|
19
22
|
Interface with sim_telarray to perform light emission package simulations.
|
|
20
23
|
|
|
21
|
-
The light emission package is used to simulate
|
|
22
|
-
|
|
23
|
-
The angle and pointing vector calculations use the convention north (x) towards
|
|
24
|
-
east (-y).
|
|
25
|
-
|
|
26
|
-
Parameters
|
|
27
|
-
----------
|
|
28
|
-
telescope_model:
|
|
29
|
-
Instance of the TelescopeModel class.
|
|
30
|
-
calibration_model:
|
|
31
|
-
CalibrationModel instance to define calibration device.
|
|
32
|
-
site_model:
|
|
33
|
-
SiteModel instance to define the site specific parameters.
|
|
34
|
-
default_le_config: dict
|
|
35
|
-
defines parameters for running the sim_telarray light emission application.
|
|
36
|
-
le_application: str
|
|
37
|
-
Name of the application. Default sim_telarray application running
|
|
38
|
-
the sim_telarray LightEmission package is xyzls.
|
|
39
|
-
simtel_path: str or Path
|
|
40
|
-
Location of sim_telarray installation.
|
|
41
|
-
light_source_type: str
|
|
42
|
-
The light source type.
|
|
43
|
-
label: str
|
|
44
|
-
Label for output directory.
|
|
45
|
-
config_data: dict
|
|
46
|
-
Dict containing the configurable parameters.
|
|
47
|
-
config_file: str or Path
|
|
48
|
-
Path of the yaml file containing the configurable parameters.
|
|
49
|
-
test: bool
|
|
50
|
-
Test flag.
|
|
24
|
+
The light emission package is used to simulate an artificial light source, used for calibration.
|
|
51
25
|
"""
|
|
52
26
|
|
|
53
27
|
def __init__(
|
|
@@ -55,7 +29,7 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
55
29
|
telescope_model,
|
|
56
30
|
calibration_model,
|
|
57
31
|
site_model,
|
|
58
|
-
|
|
32
|
+
light_emission_config,
|
|
59
33
|
le_application,
|
|
60
34
|
simtel_path,
|
|
61
35
|
light_source_type,
|
|
@@ -86,8 +60,8 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
86
60
|
)
|
|
87
61
|
|
|
88
62
|
self.le_application = le_application
|
|
89
|
-
self.
|
|
90
|
-
self.distance =
|
|
63
|
+
self.light_emission_config = light_emission_config
|
|
64
|
+
self.distance = None
|
|
91
65
|
self.light_source_type = light_source_type
|
|
92
66
|
self._telescope_model.export_config_file()
|
|
93
67
|
self.test = test
|
|
@@ -179,36 +153,6 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
179
153
|
)
|
|
180
154
|
return pointing_vector.tolist(), [tel_theta, tel_phi, laser_theta, laser_phi]
|
|
181
155
|
|
|
182
|
-
def telescope_calibration_device_distance(self):
|
|
183
|
-
"""
|
|
184
|
-
Calculate the distance between the telescope and the calibration device.
|
|
185
|
-
|
|
186
|
-
Returns
|
|
187
|
-
-------
|
|
188
|
-
astropy Quantity
|
|
189
|
-
The distance between the telescope and the calibration device.
|
|
190
|
-
"""
|
|
191
|
-
if not self.default_le_config:
|
|
192
|
-
x_cal, y_cal, z_cal = self._calibration_model.get_parameter_value(
|
|
193
|
-
"array_element_position_ground"
|
|
194
|
-
)
|
|
195
|
-
x_tel, y_tel, z_tel = self._telescope_model.get_parameter_value(
|
|
196
|
-
"array_element_position_ground"
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
else:
|
|
200
|
-
x_tel = self.default_le_config["x_pos"]["default"].to(u.m).value
|
|
201
|
-
y_tel = self.default_le_config["y_pos"]["default"].to(u.m).value
|
|
202
|
-
z_tel = self.default_le_config["z_pos"]["default"].to(u.m).value
|
|
203
|
-
|
|
204
|
-
x_cal, y_cal, z_cal = 0, 0, 0
|
|
205
|
-
|
|
206
|
-
tel_vect = np.array([x_tel, y_tel, z_tel])
|
|
207
|
-
cal_vect = np.array([x_cal, y_cal, z_cal])
|
|
208
|
-
distance = np.linalg.norm(cal_vect - tel_vect)
|
|
209
|
-
|
|
210
|
-
return distance * u.m
|
|
211
|
-
|
|
212
156
|
def _make_light_emission_script(self):
|
|
213
157
|
"""
|
|
214
158
|
Create the light emission script to run the light emission package.
|
|
@@ -235,11 +179,11 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
235
179
|
|
|
236
180
|
if self.light_source_type == "led":
|
|
237
181
|
if self.le_application[1] == "variable":
|
|
238
|
-
command += f" -x {self.
|
|
239
|
-
command += f" -y {self.
|
|
240
|
-
command += f" -z {self.
|
|
182
|
+
command += f" -x {self.light_emission_config['x_pos']['default'].to(u.cm).value}"
|
|
183
|
+
command += f" -y {self.light_emission_config['y_pos']['default'].to(u.cm).value}"
|
|
184
|
+
command += f" -z {self.light_emission_config['z_pos']['default'].to(u.cm).value}"
|
|
241
185
|
command += (
|
|
242
|
-
f" -d {','.join(map(str, self.
|
|
186
|
+
f" -d {','.join(map(str, self.light_emission_config['direction']['default']))}"
|
|
243
187
|
)
|
|
244
188
|
command += f" -n {self.photons_per_run}"
|
|
245
189
|
|
|
@@ -470,3 +414,173 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
470
414
|
|
|
471
415
|
_script_file.chmod(_script_file.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP)
|
|
472
416
|
return _script_file
|
|
417
|
+
|
|
418
|
+
def process_simulation_output(self, args_dict, figures):
|
|
419
|
+
"""Process the simulation output, including plotting and saving figures."""
|
|
420
|
+
try:
|
|
421
|
+
filename = self._get_simulation_output_filename()
|
|
422
|
+
distance = self._get_distance_for_plotting()
|
|
423
|
+
|
|
424
|
+
fig = self._plot_simulation_output(
|
|
425
|
+
filename,
|
|
426
|
+
args_dict["boundary_thresh"],
|
|
427
|
+
args_dict["picture_thresh"],
|
|
428
|
+
args_dict["min_neighbors"],
|
|
429
|
+
distance,
|
|
430
|
+
args_dict["return_cleaned"],
|
|
431
|
+
)
|
|
432
|
+
figures.append(fig)
|
|
433
|
+
|
|
434
|
+
except AttributeError:
|
|
435
|
+
msg = (
|
|
436
|
+
f"Telescope not triggered at distance of "
|
|
437
|
+
f"{self.light_emission_config['z_pos']['default']}"
|
|
438
|
+
)
|
|
439
|
+
self._logger.warning(msg)
|
|
440
|
+
|
|
441
|
+
def _get_simulation_output_filename(self):
|
|
442
|
+
"""Get the filename of the simulation output."""
|
|
443
|
+
return (
|
|
444
|
+
f"{self.output_directory}/{self.le_application[0]}_{self.le_application[1]}.simtel.gz"
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
def _get_distance_for_plotting(self):
|
|
448
|
+
"""Get the distance to be used for plotting."""
|
|
449
|
+
try:
|
|
450
|
+
return self.light_emission_config["z_pos"]["default"]
|
|
451
|
+
except KeyError:
|
|
452
|
+
return round(self.distance, 2)
|
|
453
|
+
|
|
454
|
+
def _plot_simulation_output(
|
|
455
|
+
self, filename, boundary_thresh, picture_thresh, min_neighbors, distance, return_cleaned
|
|
456
|
+
):
|
|
457
|
+
"""Plot the simulation output."""
|
|
458
|
+
return plot_simtel_ctapipe(
|
|
459
|
+
filename,
|
|
460
|
+
cleaning_args=[boundary_thresh, picture_thresh, min_neighbors],
|
|
461
|
+
distance=distance,
|
|
462
|
+
return_cleaned=return_cleaned,
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
def save_figures_to_pdf(self, figures, telescope):
|
|
466
|
+
"""Save the generated figures to a PDF file."""
|
|
467
|
+
save_figs_to_pdf(
|
|
468
|
+
figures,
|
|
469
|
+
f"{self.output_directory}/"
|
|
470
|
+
f"{telescope}_{self.le_application[0]}_{self.le_application[1]}.pdf",
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
def run_simulation(self, args_dict, figures):
|
|
474
|
+
"""Run the light emission simulation."""
|
|
475
|
+
run_script = self.prepare_script(generate_postscript=True, **args_dict)
|
|
476
|
+
log_file = Path(self.output_directory) / "logfile.log"
|
|
477
|
+
with open(log_file, "w", encoding="utf-8") as log_file:
|
|
478
|
+
subprocess.run(
|
|
479
|
+
run_script,
|
|
480
|
+
shell=False,
|
|
481
|
+
check=False,
|
|
482
|
+
text=True,
|
|
483
|
+
stdout=log_file,
|
|
484
|
+
stderr=log_file,
|
|
485
|
+
)
|
|
486
|
+
self.process_simulation_output(args_dict, figures)
|
|
487
|
+
|
|
488
|
+
def distance_list(self, arg):
|
|
489
|
+
"""
|
|
490
|
+
Convert distance list to astropy quantities.
|
|
491
|
+
|
|
492
|
+
Parameters
|
|
493
|
+
----------
|
|
494
|
+
arg: list
|
|
495
|
+
List of distances.
|
|
496
|
+
|
|
497
|
+
Returns
|
|
498
|
+
-------
|
|
499
|
+
values: list
|
|
500
|
+
List of distances as astropy quantities.
|
|
501
|
+
"""
|
|
502
|
+
try:
|
|
503
|
+
return [float(x) * u.m for x in arg]
|
|
504
|
+
except ValueError as exc:
|
|
505
|
+
raise ValueError("Distances must be numeric values") from exc
|
|
506
|
+
|
|
507
|
+
def update_light_emission_config(self, key: str, value):
|
|
508
|
+
"""
|
|
509
|
+
Update the light emission configuration.
|
|
510
|
+
|
|
511
|
+
Parameters
|
|
512
|
+
----------
|
|
513
|
+
key : str
|
|
514
|
+
The key in the configuration to update.
|
|
515
|
+
value : Any
|
|
516
|
+
The new value to set for the key.
|
|
517
|
+
"""
|
|
518
|
+
if key in self.light_emission_config:
|
|
519
|
+
self.light_emission_config[key]["default"] = value
|
|
520
|
+
else:
|
|
521
|
+
raise KeyError(f"Key '{key}' not found in light emission configuration.")
|
|
522
|
+
|
|
523
|
+
def calculate_distance_telescope_calibration_device(self):
|
|
524
|
+
"""
|
|
525
|
+
Calculate the distance(s) between the telescope and the calibration device.
|
|
526
|
+
|
|
527
|
+
Returns
|
|
528
|
+
-------
|
|
529
|
+
list of astropy.Quantity
|
|
530
|
+
A list of distances for variable positions or a single distance for layout positions.
|
|
531
|
+
"""
|
|
532
|
+
if not self.light_emission_config:
|
|
533
|
+
# Layout positions: Use DB coordinates
|
|
534
|
+
x_cal, y_cal, z_cal = self._calibration_model.get_parameter_value(
|
|
535
|
+
"array_element_position_ground"
|
|
536
|
+
)
|
|
537
|
+
x_tel, y_tel, z_tel = self._telescope_model.get_parameter_value(
|
|
538
|
+
"array_element_position_ground"
|
|
539
|
+
)
|
|
540
|
+
tel_vect = np.array([x_tel, y_tel, z_tel])
|
|
541
|
+
cal_vect = np.array([x_cal, y_cal, z_cal])
|
|
542
|
+
distance = np.linalg.norm(cal_vect - tel_vect)
|
|
543
|
+
return [distance * u.m]
|
|
544
|
+
|
|
545
|
+
# Variable positions: Calculate distances for all positions
|
|
546
|
+
x_tel = self.light_emission_config["x_pos"]["default"].to(u.m).value
|
|
547
|
+
y_tel = self.light_emission_config["y_pos"]["default"].to(u.m).value
|
|
548
|
+
z_positions = self.light_emission_config["z_pos"]["default"]
|
|
549
|
+
|
|
550
|
+
distances = []
|
|
551
|
+
for z in z_positions:
|
|
552
|
+
tel_vect = np.array([x_tel, y_tel, z.to(u.m).value])
|
|
553
|
+
cal_vect = np.array([0, 0, 0]) # Calibration device at origin
|
|
554
|
+
distances.append(np.linalg.norm(cal_vect - tel_vect) * u.m)
|
|
555
|
+
return distances
|
|
556
|
+
|
|
557
|
+
def simulate_variable_distances(self, args_dict):
|
|
558
|
+
"""Simulate light emission for variable distances."""
|
|
559
|
+
if args_dict["distances_ls"] is not None:
|
|
560
|
+
self.update_light_emission_config(
|
|
561
|
+
"z_pos", self.distance_list(args_dict["distances_ls"])
|
|
562
|
+
)
|
|
563
|
+
self._logger.info(
|
|
564
|
+
f"Simulating for distances: {self.light_emission_config['z_pos']['default']}"
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
figures = []
|
|
568
|
+
distances = self.calculate_distance_telescope_calibration_device()
|
|
569
|
+
|
|
570
|
+
for current_distance, z_pos in zip(
|
|
571
|
+
distances, self.light_emission_config["z_pos"]["default"]
|
|
572
|
+
):
|
|
573
|
+
self.update_light_emission_config("z_pos", z_pos)
|
|
574
|
+
self.distance = current_distance
|
|
575
|
+
self.run_simulation(args_dict, figures)
|
|
576
|
+
|
|
577
|
+
self.save_figures_to_pdf(figures, args_dict["telescope"])
|
|
578
|
+
|
|
579
|
+
def simulate_layout_positions(self, args_dict):
|
|
580
|
+
"""Simulate light emission for layout positions."""
|
|
581
|
+
figures = []
|
|
582
|
+
self.distance = self.calculate_distance_telescope_calibration_device()[
|
|
583
|
+
0
|
|
584
|
+
] # Single distance for layout
|
|
585
|
+
self.run_simulation(args_dict, figures)
|
|
586
|
+
self.save_figures_to_pdf(figures, args_dict["telescope"])
|
simtools/simulator.py
CHANGED
|
@@ -329,7 +329,7 @@ class Simulator:
|
|
|
329
329
|
input_file_list = self._enforce_list_type(input_file_list)
|
|
330
330
|
_runs_and_files = {self._guess_run_from_file(file): file for file in input_file_list}
|
|
331
331
|
elif self.simulation_software in ["corsika", "corsika_simtel"]:
|
|
332
|
-
_runs_and_files =
|
|
332
|
+
_runs_and_files = dict.fromkeys(self._get_runs_to_simulate())
|
|
333
333
|
if len(_runs_and_files) == 0:
|
|
334
334
|
raise ValueError("No runs to submit.")
|
|
335
335
|
return _runs_and_files
|
|
@@ -392,7 +392,7 @@ class Simulator:
|
|
|
392
392
|
|
|
393
393
|
"""
|
|
394
394
|
keys = ["output", "sub_out", "log", "input", "hist", "corsika_log"]
|
|
395
|
-
defaults =
|
|
395
|
+
defaults = dict.fromkeys(keys)
|
|
396
396
|
results = {key: defaults[key] for key in keys}
|
|
397
397
|
results["output"] = str(
|
|
398
398
|
self._simulation_runner.get_file_name(file_type="output", run_number=run_number)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Integration test configuration."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
import os
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
import yaml
|
|
@@ -14,6 +15,10 @@ class VersionError(Exception):
|
|
|
14
15
|
"""Raise if model version requested is not supported."""
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
class ProductionDBError(Exception):
|
|
19
|
+
"""Raise if production db is used."""
|
|
20
|
+
|
|
21
|
+
|
|
17
22
|
def get_list_of_test_configurations(config_files):
|
|
18
23
|
"""
|
|
19
24
|
Return list of test configuration dictionaries or test names.
|
|
@@ -100,6 +105,7 @@ def configure(config, tmp_test_directory, request):
|
|
|
100
105
|
|
|
101
106
|
if "CONFIGURATION" in config:
|
|
102
107
|
_skip_test_for_model_version(config, model_version_requested)
|
|
108
|
+
_skip_test_for_production_db(config)
|
|
103
109
|
|
|
104
110
|
config_file, config_string, config_file_model_version = _prepare_test_options(
|
|
105
111
|
config["CONFIGURATION"],
|
|
@@ -130,6 +136,18 @@ def _skip_test_for_model_version(config, model_version_requested):
|
|
|
130
136
|
)
|
|
131
137
|
|
|
132
138
|
|
|
139
|
+
def _skip_test_for_production_db(config):
|
|
140
|
+
"""Skip test if production db is used."""
|
|
141
|
+
if not config.get("SKIP_FOR_PRODUCTION_DB"):
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
if "db.zeuthen.desy.de" in os.getenv("SIMTOOLS_DB_SERVER", ""):
|
|
145
|
+
raise ProductionDBError("Production database used for this test")
|
|
146
|
+
|
|
147
|
+
if "simpipe" in os.getenv("SIMTOOLS_DB_API_USER", ""):
|
|
148
|
+
raise ProductionDBError("Production database used for this test")
|
|
149
|
+
|
|
150
|
+
|
|
133
151
|
def _prepare_test_options(config, output_path, model_version=None):
|
|
134
152
|
"""
|
|
135
153
|
Prepare test configuration.
|