gammasimtools 0.15.0__py3-none-any.whl → 0.16.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.15.0.dist-info → gammasimtools-0.16.0.dist-info}/METADATA +2 -32
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/RECORD +222 -214
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/entry_points.txt +5 -2
- simtools/_version.py +2 -2
- simtools/applications/calculate_trigger_rate.py +10 -10
- simtools/applications/convert_all_model_parameters_from_simtel.py +16 -16
- simtools/applications/convert_model_parameter_from_simtel.py +1 -1
- simtools/applications/derive_psf_parameters.py +12 -9
- simtools/applications/docs_produce_array_element_report.py +3 -3
- simtools/applications/docs_produce_calibration_reports.py +49 -0
- simtools/applications/docs_produce_simulation_configuration_report.py +50 -0
- simtools/applications/{generate_simtel_array_histograms.py → generate_sim_telarray_histograms.py} +2 -2
- simtools/applications/production_derive_corsika_limits.py +63 -10
- simtools/applications/production_derive_statistics.py +125 -0
- simtools/applications/production_generate_grid.py +197 -0
- simtools/applications/production_generate_simulation_config.py +0 -10
- simtools/applications/simulate_light_emission.py +5 -13
- simtools/applications/simulate_prod.py +16 -4
- simtools/applications/validate_cumulative_psf.py +6 -4
- simtools/applications/validate_file_using_schema.py +7 -3
- simtools/applications/validate_optics.py +5 -4
- simtools/camera/camera_efficiency.py +14 -39
- simtools/configuration/commandline_parser.py +4 -3
- simtools/configuration/configurator.py +10 -0
- simtools/corsika/corsika_config.py +103 -5
- simtools/data_model/format_checkers.py +9 -0
- simtools/data_model/model_data_writer.py +3 -0
- simtools/data_model/schema.py +27 -16
- simtools/data_model/validate_data.py +27 -7
- simtools/db/db_handler.py +10 -4
- simtools/layout/array_layout.py +1 -0
- simtools/model/array_model.py +63 -29
- simtools/model/model_parameter.py +76 -51
- simtools/model/model_utils.py +43 -1
- simtools/model/site_model.py +3 -2
- simtools/model/telescope_model.py +4 -4
- simtools/production_configuration/calculate_statistical_errors_grid_point.py +0 -4
- simtools/production_configuration/{event_scaler.py → derive_production_statistics.py} +24 -20
- simtools/production_configuration/derive_production_statistics_handler.py +119 -0
- simtools/production_configuration/generate_production_grid.py +364 -0
- simtools/production_configuration/generate_simulation_config.py +9 -9
- simtools/production_configuration/interpolation_handler.py +16 -11
- simtools/ray_tracing/mirror_panel_psf.py +16 -20
- simtools/ray_tracing/psf_analysis.py +2 -2
- simtools/ray_tracing/ray_tracing.py +5 -1
- simtools/reporting/docs_read_parameters.py +361 -58
- simtools/runners/corsika_runner.py +11 -1
- simtools/runners/corsika_simtel_runner.py +80 -89
- simtools/runners/runner_services.py +17 -4
- simtools/runners/simtel_runner.py +27 -10
- simtools/schemas/model_parameter.metaschema.yml +4 -0
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +1 -0
- simtools/schemas/model_parameters/adjust_gain.schema.yml +2 -2
- simtools/schemas/model_parameters/array_element_position_ground.schema.yml +2 -2
- simtools/schemas/model_parameters/array_element_position_utm.schema.yml +2 -2
- simtools/schemas/model_parameters/array_window.schema.yml +2 -2
- simtools/schemas/model_parameters/asum_offset.schema.yml +2 -2
- simtools/schemas/model_parameters/asum_shaping.schema.yml +2 -2
- simtools/schemas/model_parameters/asum_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/axes_offsets.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_body_diameter.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_body_shape.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_config_file.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_config_rotate.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_degraded_map.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_depth.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_filter.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_pixels.schema.yml +2 -2
- simtools/schemas/model_parameters/camera_transmission.schema.yml +2 -2
- simtools/schemas/model_parameters/channels_per_chip.schema.yml +2 -2
- simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +2 -2
- simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +90 -1
- simtools/schemas/model_parameters/default_trigger.schema.yml +2 -2
- simtools/schemas/model_parameters/design_model.schema.yml +2 -2
- simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +2 -2
- simtools/schemas/model_parameters/disc_bins.schema.yml +2 -2
- simtools/schemas/model_parameters/disc_start.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/dish_shape_length.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_clipping.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_offset.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_pedsub.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_prescale.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_presum_max.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_shaping.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +3 -3
- simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +2 -2
- simtools/schemas/model_parameters/effective_focal_length.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_amplitude.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_bins.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_max_signal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_mhz.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_noise.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +2 -2
- simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +2 -2
- simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
- simtools/schemas/model_parameters/flatfielding.schema.yml +2 -2
- simtools/schemas/model_parameters/focal_length.schema.yml +2 -2
- simtools/schemas/model_parameters/focus_offset.schema.yml +2 -2
- simtools/schemas/model_parameters/gain_variation.schema.yml +2 -2
- simtools/schemas/model_parameters/hg_lg_variation.schema.yml +2 -2
- simtools/schemas/model_parameters/iobuf_maximum.schema.yml +2 -2
- simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +2 -2
- simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
- simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +2 -2
- simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +2 -2
- simtools/schemas/model_parameters/min_photoelectrons.schema.yml +2 -2
- simtools/schemas/model_parameters/min_photons.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_class.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_focal_length.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_list.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_offset.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +2 -2
- simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +2 -2
- simtools/schemas/model_parameters/multiplicity_offset.schema.yml +2 -2
- simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +2 -2
- simtools/schemas/model_parameters/nsb_offaxis.schema.yml +2 -2
- simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +2 -2
- simtools/schemas/model_parameters/num_gains.schema.yml +2 -2
- simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +2 -2
- simtools/schemas/model_parameters/optics_properties.schema.yml +2 -2
- simtools/schemas/model_parameters/pedestal_events.schema.yml +7 -3
- simtools/schemas/model_parameters/photon_delay.schema.yml +2 -2
- simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +2 -2
- simtools/schemas/model_parameters/pm_average_gain.schema.yml +2 -2
- simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +2 -2
- simtools/schemas/model_parameters/pm_gain_index.schema.yml +2 -2
- simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +2 -2
- simtools/schemas/model_parameters/pm_transit_time.schema.yml +2 -2
- simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +2 -2
- simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +2 -2
- simtools/schemas/model_parameters/qe_variation.schema.yml +2 -2
- simtools/schemas/model_parameters/quantum_efficiency.schema.yml +2 -2
- simtools/schemas/model_parameters/random_focal_length.schema.yml +2 -2
- simtools/schemas/model_parameters/random_generator.schema.yml +2 -2
- simtools/schemas/model_parameters/random_mono_probability.schema.yml +2 -2
- simtools/schemas/model_parameters/sampled_output.schema.yml +2 -2
- simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +2 -2
- simtools/schemas/model_parameters/store_photoelectrons.schema.yml +2 -2
- simtools/schemas/model_parameters/tailcut_scale.schema.yml +2 -2
- simtools/schemas/model_parameters/telescope_axis_height.schema.yml +2 -2
- simtools/schemas/model_parameters/telescope_random_angle.schema.yml +2 -2
- simtools/schemas/model_parameters/telescope_random_error.schema.yml +2 -2
- simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +2 -2
- simtools/schemas/model_parameters/telescope_transmission.schema.yml +2 -2
- simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +2 -2
- simtools/schemas/model_parameters/teltrig_min_time.schema.yml +2 -2
- simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +2 -2
- simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +2 -2
- simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +2 -2
- simtools/schemas/model_parameters/transit_time_error.schema.yml +2 -2
- simtools/schemas/model_parameters/transit_time_jitter.schema.yml +2 -2
- simtools/schemas/model_parameters/trigger_current_limit.schema.yml +2 -2
- simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +2 -2
- simtools/schemas/model_parameters/trigger_pixels.schema.yml +2 -2
- simtools/simtel/simtel_config_reader.py +21 -17
- simtools/simtel/simtel_config_writer.py +237 -65
- simtools/simtel/simtel_io_file_info.py +57 -0
- simtools/simtel/simtel_io_histogram.py +10 -14
- simtools/simtel/simtel_io_histograms.py +2 -2
- simtools/simtel/simtel_io_metadata.py +91 -0
- simtools/simtel/simulator_array.py +26 -12
- simtools/simtel/simulator_camera_efficiency.py +12 -6
- simtools/simtel/simulator_light_emission.py +6 -11
- simtools/simtel/simulator_ray_tracing.py +14 -4
- simtools/simulator.py +230 -66
- simtools/testing/configuration.py +5 -0
- simtools/testing/helpers.py +18 -0
- simtools/testing/sim_telarray_metadata.py +212 -0
- simtools/testing/validate_output.py +12 -5
- simtools/utils/general.py +18 -27
- simtools/utils/names.py +27 -5
- simtools/visualization/visualize.py +2 -2
- simtools/applications/production_scale_events.py +0 -185
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.16.0.dist-info}/top_level.txt +0 -0
simtools/simulator.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Simulator class for managing simulations of showers and array of telescopes."""
|
|
2
2
|
|
|
3
|
+
import gzip
|
|
3
4
|
import logging
|
|
4
5
|
import re
|
|
5
6
|
import shutil
|
|
@@ -17,6 +18,7 @@ from simtools.model.array_model import ArrayModel
|
|
|
17
18
|
from simtools.runners.corsika_runner import CorsikaRunner
|
|
18
19
|
from simtools.runners.corsika_simtel_runner import CorsikaSimtelRunner
|
|
19
20
|
from simtools.simtel.simulator_array import SimulatorArray
|
|
21
|
+
from simtools.testing.sim_telarray_metadata import assert_sim_telarray_metadata
|
|
20
22
|
|
|
21
23
|
__all__ = [
|
|
22
24
|
"InvalidRunsToSimulateError",
|
|
@@ -74,7 +76,14 @@ class Simulator:
|
|
|
74
76
|
self._submit_options = self.args_dict.get("submit_options", None)
|
|
75
77
|
self._extra_commands = extra_commands
|
|
76
78
|
|
|
77
|
-
self.
|
|
79
|
+
self.sim_telarray_seeds = {
|
|
80
|
+
"seed": self.args_dict.get("sim_telarray_instrument_seeds"),
|
|
81
|
+
"random_instrument_instances": self.args_dict.get(
|
|
82
|
+
"sim_telarray_random_instrument_instances"
|
|
83
|
+
),
|
|
84
|
+
"seed_file_name": "sim_telarray_instrument_seeds.txt", # name only; no directory
|
|
85
|
+
}
|
|
86
|
+
self.array_models = self._initialize_array_models(mongo_db_config)
|
|
78
87
|
self._simulation_runner = self._initialize_simulation_runner(mongo_db_config)
|
|
79
88
|
|
|
80
89
|
@property
|
|
@@ -89,8 +98,8 @@ class Simulator:
|
|
|
89
98
|
|
|
90
99
|
Parameters
|
|
91
100
|
----------
|
|
92
|
-
simulation_software: choices: [
|
|
93
|
-
implemented are sim_telarray and CORSIKA or
|
|
101
|
+
simulation_software: choices: [sim_telarray, corsika, corsika_sim_telarray]
|
|
102
|
+
implemented are sim_telarray and CORSIKA or corsika_sim_telarray
|
|
94
103
|
(running CORSIKA and piping it directly to sim_telarray)
|
|
95
104
|
|
|
96
105
|
Raises
|
|
@@ -98,14 +107,14 @@ class Simulator:
|
|
|
98
107
|
gen.InvalidConfigDataError
|
|
99
108
|
|
|
100
109
|
"""
|
|
101
|
-
if simulation_software not in ["
|
|
110
|
+
if simulation_software not in ["sim_telarray", "corsika", "corsika_sim_telarray"]:
|
|
102
111
|
self._logger.error(f"Invalid simulation software: {simulation_software}")
|
|
103
112
|
raise gen.InvalidConfigDataError
|
|
104
113
|
self._simulation_software = simulation_software.lower()
|
|
105
114
|
|
|
106
|
-
def
|
|
115
|
+
def _initialize_array_models(self, mongo_db_config):
|
|
107
116
|
"""
|
|
108
|
-
Initialize array simulation
|
|
117
|
+
Initialize array simulation models.
|
|
109
118
|
|
|
110
119
|
Parameters
|
|
111
120
|
----------
|
|
@@ -114,16 +123,59 @@ class Simulator:
|
|
|
114
123
|
|
|
115
124
|
Returns
|
|
116
125
|
-------
|
|
117
|
-
|
|
118
|
-
ArrayModel
|
|
119
|
-
"""
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
list
|
|
127
|
+
List of ArrayModel objects.
|
|
128
|
+
"""
|
|
129
|
+
model_version = self.args_dict.get("model_version", [])
|
|
130
|
+
versions = [model_version] if not isinstance(model_version, list) else model_version
|
|
131
|
+
|
|
132
|
+
return [
|
|
133
|
+
ArrayModel(
|
|
134
|
+
label=self.label,
|
|
135
|
+
site=self.args_dict.get("site"),
|
|
136
|
+
layout_name=self.args_dict.get("array_layout_name"),
|
|
137
|
+
mongo_db_config=mongo_db_config,
|
|
138
|
+
model_version=version,
|
|
139
|
+
sim_telarray_seeds={
|
|
140
|
+
"seed": self._get_seed_for_random_instrument_instances(
|
|
141
|
+
self.sim_telarray_seeds["seed"], version
|
|
142
|
+
),
|
|
143
|
+
"random_instrument_instances": self.sim_telarray_seeds[
|
|
144
|
+
"random_instrument_instances"
|
|
145
|
+
],
|
|
146
|
+
"seed_file_name": self.sim_telarray_seeds["seed_file_name"],
|
|
147
|
+
},
|
|
148
|
+
)
|
|
149
|
+
for version in versions
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
def _get_seed_for_random_instrument_instances(self, seed, model_version):
|
|
153
|
+
"""
|
|
154
|
+
Generate seed for random instances of the instrument.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
seed : str
|
|
159
|
+
Seed string given through configuration.
|
|
160
|
+
model_version: str
|
|
161
|
+
Model version.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
int
|
|
166
|
+
Seed for random instances of the instrument.
|
|
167
|
+
"""
|
|
168
|
+
if seed:
|
|
169
|
+
return int(seed.split(",")[0].strip())
|
|
170
|
+
|
|
171
|
+
def semver_to_int(version: str):
|
|
172
|
+
major, minor, patch = map(int, version.split("."))
|
|
173
|
+
return major * 10000 + minor * 100 + patch
|
|
174
|
+
|
|
175
|
+
seed = semver_to_int(model_version) * 10000000
|
|
176
|
+
seed = seed + 1000000 if self.args_dict.get("site") != "North" else seed + 2000000
|
|
177
|
+
seed = seed + (int)(self.args_dict["zenith_angle"].value) * 1000
|
|
178
|
+
return seed + (int)(self.args_dict["azimuth_angle"].value)
|
|
127
179
|
|
|
128
180
|
def _initialize_run_list(self):
|
|
129
181
|
"""
|
|
@@ -214,22 +266,33 @@ class Simulator:
|
|
|
214
266
|
CorsikaRunner or SimulatorArray or CorsikaSimtelRunner
|
|
215
267
|
Simulation runner object.
|
|
216
268
|
"""
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
269
|
+
corsika_configurations = []
|
|
270
|
+
for array_model in self.array_models:
|
|
271
|
+
corsika_configurations.append(
|
|
272
|
+
CorsikaConfig(
|
|
273
|
+
array_model=array_model,
|
|
274
|
+
label=self.label,
|
|
275
|
+
args_dict=self.args_dict,
|
|
276
|
+
db_config=db_config,
|
|
277
|
+
)
|
|
278
|
+
)
|
|
223
279
|
|
|
224
280
|
runner_class = {
|
|
225
281
|
"corsika": CorsikaRunner,
|
|
226
|
-
"
|
|
227
|
-
"
|
|
282
|
+
"sim_telarray": SimulatorArray,
|
|
283
|
+
"corsika_sim_telarray": CorsikaSimtelRunner,
|
|
228
284
|
}.get(self.simulation_software)
|
|
229
285
|
|
|
286
|
+
# In case of CorsikaSimtelRunner we should pass all corsika_configurations
|
|
287
|
+
# to the runner, since we define multiple configurations to run in a single job
|
|
288
|
+
# using multipipe. In other cases we pass only the first one (there's only one anyway).
|
|
230
289
|
runner_args = {
|
|
231
290
|
"label": self.label,
|
|
232
|
-
"corsika_config":
|
|
291
|
+
"corsika_config": (
|
|
292
|
+
corsika_configurations
|
|
293
|
+
if runner_class is CorsikaSimtelRunner
|
|
294
|
+
else corsika_configurations[0]
|
|
295
|
+
),
|
|
233
296
|
"simtel_path": self.args_dict.get("simtel_path"),
|
|
234
297
|
"use_multipipe": runner_class is CorsikaSimtelRunner,
|
|
235
298
|
}
|
|
@@ -237,7 +300,7 @@ class Simulator:
|
|
|
237
300
|
if runner_class is not SimulatorArray:
|
|
238
301
|
runner_args["keep_seeds"] = self.args_dict.get("corsika_test_seeds", False)
|
|
239
302
|
if runner_class is not CorsikaRunner:
|
|
240
|
-
runner_args["sim_telarray_seeds"] = self.
|
|
303
|
+
runner_args["sim_telarray_seeds"] = self.sim_telarray_seeds
|
|
241
304
|
|
|
242
305
|
return runner_class(**runner_args)
|
|
243
306
|
|
|
@@ -325,10 +388,10 @@ class Simulator:
|
|
|
325
388
|
_runs_and_files = {}
|
|
326
389
|
self._logger.debug(f"Getting runs and files to submit ({input_file_list})")
|
|
327
390
|
|
|
328
|
-
if self.simulation_software == "
|
|
391
|
+
if self.simulation_software == "sim_telarray":
|
|
329
392
|
input_file_list = self._enforce_list_type(input_file_list)
|
|
330
393
|
_runs_and_files = {self._guess_run_from_file(file): file for file in input_file_list}
|
|
331
|
-
elif self.simulation_software in ["corsika", "
|
|
394
|
+
elif self.simulation_software in ["corsika", "corsika_sim_telarray"]:
|
|
332
395
|
_runs_and_files = dict.fromkeys(self._get_runs_to_simulate())
|
|
333
396
|
if len(_runs_and_files) == 0:
|
|
334
397
|
raise ValueError("No runs to submit.")
|
|
@@ -392,39 +455,66 @@ class Simulator:
|
|
|
392
455
|
|
|
393
456
|
"""
|
|
394
457
|
keys = ["output", "sub_out", "log", "input", "hist", "corsika_log"]
|
|
395
|
-
|
|
396
|
-
results = {key: defaults[key] for key in keys}
|
|
397
|
-
results["output"] = str(
|
|
398
|
-
self._simulation_runner.get_file_name(file_type="output", run_number=run_number)
|
|
399
|
-
)
|
|
400
|
-
results["sub_out"] = str(
|
|
401
|
-
self._simulation_runner.get_file_name(
|
|
402
|
-
file_type="sub_log", mode="out", run_number=run_number
|
|
403
|
-
)
|
|
404
|
-
)
|
|
458
|
+
results = {key: [] for key in keys}
|
|
405
459
|
|
|
406
|
-
if "
|
|
407
|
-
results["
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
)
|
|
412
|
-
results["input"] = str(file)
|
|
413
|
-
results["hist"] = str(
|
|
460
|
+
if "sim_telarray" in self.simulation_software:
|
|
461
|
+
results["input"].append(str(file))
|
|
462
|
+
|
|
463
|
+
results["sub_out"].append(
|
|
464
|
+
str(
|
|
414
465
|
self._simulation_runner.get_file_name(
|
|
415
|
-
file_type="
|
|
466
|
+
file_type="sub_log",
|
|
467
|
+
mode="out",
|
|
468
|
+
run_number=run_number,
|
|
416
469
|
)
|
|
417
470
|
)
|
|
471
|
+
)
|
|
418
472
|
|
|
419
|
-
|
|
420
|
-
results["
|
|
421
|
-
|
|
422
|
-
|
|
473
|
+
for model_version_index, _ in enumerate(self.array_models):
|
|
474
|
+
results["output"].append(
|
|
475
|
+
str(
|
|
476
|
+
self._simulation_runner.get_file_name(
|
|
477
|
+
file_type="output",
|
|
478
|
+
run_number=run_number,
|
|
479
|
+
model_version_index=model_version_index,
|
|
480
|
+
)
|
|
423
481
|
)
|
|
424
482
|
)
|
|
483
|
+
if "sim_telarray" in self.simulation_software:
|
|
484
|
+
results["log"].append(
|
|
485
|
+
str(
|
|
486
|
+
self._simulation_runner.get_file_name(
|
|
487
|
+
file_type="log",
|
|
488
|
+
simulation_software="sim_telarray",
|
|
489
|
+
run_number=run_number,
|
|
490
|
+
model_version_index=model_version_index,
|
|
491
|
+
)
|
|
492
|
+
)
|
|
493
|
+
)
|
|
494
|
+
results["hist"].append(
|
|
495
|
+
str(
|
|
496
|
+
self._simulation_runner.get_file_name(
|
|
497
|
+
file_type="histogram",
|
|
498
|
+
simulation_software="sim_telarray",
|
|
499
|
+
run_number=run_number,
|
|
500
|
+
model_version_index=model_version_index,
|
|
501
|
+
)
|
|
502
|
+
)
|
|
503
|
+
)
|
|
504
|
+
if "corsika" in self.simulation_software:
|
|
505
|
+
results["corsika_log"].append(
|
|
506
|
+
str(
|
|
507
|
+
self._simulation_runner.get_file_name(
|
|
508
|
+
file_type="corsika_log",
|
|
509
|
+
simulation_software="corsika",
|
|
510
|
+
run_number=run_number,
|
|
511
|
+
model_version_index=model_version_index,
|
|
512
|
+
)
|
|
513
|
+
)
|
|
514
|
+
)
|
|
425
515
|
|
|
426
516
|
for key in keys:
|
|
427
|
-
self._results[key].
|
|
517
|
+
self._results[key].extend(results[key])
|
|
428
518
|
|
|
429
519
|
def get_file_list(self, file_type="output"):
|
|
430
520
|
"""
|
|
@@ -563,6 +653,8 @@ class Simulator:
|
|
|
563
653
|
"""
|
|
564
654
|
Pack simulation output files for registering on the grid.
|
|
565
655
|
|
|
656
|
+
Creates separate tarballs for each model version's log files.
|
|
657
|
+
|
|
566
658
|
Parameters
|
|
567
659
|
----------
|
|
568
660
|
directory_for_grid_upload: str
|
|
@@ -576,7 +668,7 @@ class Simulator:
|
|
|
576
668
|
log_files = self.get_file_list(file_type="log")
|
|
577
669
|
corsika_log_files = self.get_file_list(file_type="corsika_log")
|
|
578
670
|
histogram_files = self.get_file_list(file_type="hist")
|
|
579
|
-
|
|
671
|
+
|
|
580
672
|
directory_for_grid_upload = (
|
|
581
673
|
Path(directory_for_grid_upload)
|
|
582
674
|
if directory_for_grid_upload
|
|
@@ -586,24 +678,96 @@ class Simulator:
|
|
|
586
678
|
)
|
|
587
679
|
directory_for_grid_upload.mkdir(parents=True, exist_ok=True)
|
|
588
680
|
|
|
589
|
-
|
|
681
|
+
# If there are more than one model version,
|
|
682
|
+
# duplicate the corsika log file to have one for each model version with the "right name".
|
|
683
|
+
if len(self.array_models) > 1 and corsika_log_files:
|
|
684
|
+
self._copy_corsika_log_file_for_all_versions(corsika_log_files)
|
|
590
685
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
for
|
|
598
|
-
|
|
686
|
+
# Group files by model version
|
|
687
|
+
for model in self.array_models:
|
|
688
|
+
model_version = model.model_version
|
|
689
|
+
|
|
690
|
+
# Filter files for this model version
|
|
691
|
+
model_logs = [f for f in log_files if model_version in f]
|
|
692
|
+
model_hists = [f for f in histogram_files if model_version in f]
|
|
693
|
+
model_corsika_logs = [f for f in corsika_log_files if model_version in f]
|
|
599
694
|
|
|
600
|
-
|
|
695
|
+
if model_logs:
|
|
696
|
+
tar_file_name = Path(model_logs[0]).name.replace("log.gz", "log_hist.tar.gz")
|
|
697
|
+
tar_file_path = directory_for_grid_upload.joinpath(tar_file_name)
|
|
698
|
+
|
|
699
|
+
with tarfile.open(tar_file_path, "w:gz") as tar:
|
|
700
|
+
files_to_tar = model_logs + model_hists + model_corsika_logs
|
|
701
|
+
for file_to_tar in files_to_tar:
|
|
702
|
+
tar.add(file_to_tar, arcname=Path(file_to_tar).name)
|
|
703
|
+
|
|
704
|
+
for file_to_move in output_files:
|
|
601
705
|
source_file = Path(file_to_move)
|
|
602
706
|
destination_file = directory_for_grid_upload / source_file.name
|
|
603
707
|
if destination_file.exists():
|
|
604
708
|
self._logger.warning(f"Overwriting existing file: {destination_file}")
|
|
605
|
-
# Note that this will overwrite previous files which exist in the directory
|
|
606
|
-
# It should be fine for normal production since each run is on a separate node
|
|
607
|
-
# so no files are expected there.
|
|
608
709
|
shutil.move(source_file, destination_file)
|
|
710
|
+
|
|
609
711
|
self._logger.info(f"Output files for the grid placed in {directory_for_grid_upload!s}")
|
|
712
|
+
|
|
713
|
+
def validate_metadata(self):
|
|
714
|
+
"""Validate metadata in the sim_telarray output files."""
|
|
715
|
+
if "sim_telarray" not in self.simulation_software:
|
|
716
|
+
self._logger.info("No sim_telarray files to validate.")
|
|
717
|
+
return
|
|
718
|
+
|
|
719
|
+
for model in self.array_models:
|
|
720
|
+
files = self.get_file_list(file_type="output")
|
|
721
|
+
output_file = next((f for f in files if model.model_version in f), None)
|
|
722
|
+
if output_file:
|
|
723
|
+
self._logger.info(f"Validating metadata for {output_file}")
|
|
724
|
+
assert_sim_telarray_metadata(output_file, model)
|
|
725
|
+
self._logger.info(f"Metadata for sim_telarray file {output_file} is valid.")
|
|
726
|
+
else:
|
|
727
|
+
self._logger.warning(
|
|
728
|
+
f"No sim_telarray file found for model version {model.model_version}: {files}"
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
def _copy_corsika_log_file_for_all_versions(self, corsika_log_files):
|
|
732
|
+
"""
|
|
733
|
+
Create copies of the CORSIKA log file for each model version.
|
|
734
|
+
|
|
735
|
+
Adds a header comment to each copy explaining its relationship to the original.
|
|
736
|
+
|
|
737
|
+
Parameters
|
|
738
|
+
----------
|
|
739
|
+
corsika_log_files: list
|
|
740
|
+
List containing the original CORSIKA log file path.
|
|
741
|
+
|
|
742
|
+
"""
|
|
743
|
+
original_log = Path(corsika_log_files[0])
|
|
744
|
+
# Find which model version the original log belongs to
|
|
745
|
+
original_version = next(
|
|
746
|
+
model.model_version
|
|
747
|
+
for model in self.array_models
|
|
748
|
+
if re.search(
|
|
749
|
+
rf"(?<![0-9A-Za-z]){re.escape(model.model_version)}(?![0-9A-Za-z])",
|
|
750
|
+
original_log.name,
|
|
751
|
+
)
|
|
752
|
+
)
|
|
753
|
+
|
|
754
|
+
for model in self.array_models:
|
|
755
|
+
if model.model_version == original_version:
|
|
756
|
+
continue
|
|
757
|
+
|
|
758
|
+
new_log = original_log.parent / original_log.name.replace(
|
|
759
|
+
original_version, model.model_version
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
with gzip.open(new_log, "wt") as new_file:
|
|
763
|
+
new_file.write(
|
|
764
|
+
f"###############################################################\n"
|
|
765
|
+
f"Copy of CORSIKA log file from model version {original_version}.\n"
|
|
766
|
+
f"Applicable also for {model.model_version} (same CORSIKA configuration,\n"
|
|
767
|
+
f"different sim_telarray model versions in the same run).\n"
|
|
768
|
+
f"###############################################################\n\n"
|
|
769
|
+
)
|
|
770
|
+
with gzip.open(original_log, "rt") as orig_file:
|
|
771
|
+
shutil.copyfileobj(orig_file, new_file)
|
|
772
|
+
|
|
773
|
+
corsika_log_files.append(str(new_log))
|
|
@@ -102,6 +102,11 @@ def configure(config, tmp_test_directory, request):
|
|
|
102
102
|
"""
|
|
103
103
|
tmp_output_path = create_tmp_output_path(tmp_test_directory, config)
|
|
104
104
|
model_version_requested = request.config.getoption("--model_version")
|
|
105
|
+
model_version_requested = (
|
|
106
|
+
model_version_requested.split(",") if model_version_requested else None
|
|
107
|
+
)
|
|
108
|
+
if isinstance(model_version_requested, list) and len(model_version_requested) == 1:
|
|
109
|
+
model_version_requested = model_version_requested[0]
|
|
105
110
|
|
|
106
111
|
if "CONFIGURATION" in config:
|
|
107
112
|
_skip_test_for_model_version(config, model_version_requested)
|
simtools/testing/helpers.py
CHANGED
|
@@ -33,3 +33,21 @@ def _new_testeff_version():
|
|
|
33
33
|
return False
|
|
34
34
|
except FileNotFoundError as exc:
|
|
35
35
|
raise FileNotFoundError("The testeff executable could not be found.") from exc
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def skip_multiple_version_test(config, model_version):
|
|
39
|
+
"""Skip a test which is not meant for multiple versions if multiple versions are given."""
|
|
40
|
+
message = "Skipping test not meant for multiple model versions."
|
|
41
|
+
|
|
42
|
+
if not isinstance(model_version, list):
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
config_model_version = config.get("CONFIGURATION", {}).get("MODEL_VERSION", [])
|
|
46
|
+
|
|
47
|
+
if not isinstance(config_model_version, list):
|
|
48
|
+
config_model_version = [config_model_version]
|
|
49
|
+
|
|
50
|
+
if 1 < len(model_version) != len(config_model_version):
|
|
51
|
+
return message
|
|
52
|
+
|
|
53
|
+
return None
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Test consistency of sim_telarray metadata."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from simtools.simtel.simtel_config_reader import SimtelConfigReader
|
|
8
|
+
from simtools.simtel.simtel_config_writer import sim_telarray_random_seeds
|
|
9
|
+
from simtools.simtel.simtel_io_file_info import get_corsika_run_number
|
|
10
|
+
from simtools.simtel.simtel_io_metadata import (
|
|
11
|
+
get_sim_telarray_telescope_id,
|
|
12
|
+
read_sim_telarray_metadata,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
_logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def assert_sim_telarray_metadata(file, array_model):
|
|
19
|
+
"""
|
|
20
|
+
Assert consistency of sim_telarray metadata with given array model.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
file: Path
|
|
25
|
+
Path to the sim_telarray file.
|
|
26
|
+
array_model: ArrayModel
|
|
27
|
+
Array model to compare with.
|
|
28
|
+
"""
|
|
29
|
+
global_meta, telescope_meta = read_sim_telarray_metadata(file)
|
|
30
|
+
_logger.info(f"Found metadata in sim_telarray file for {len(telescope_meta)} telescopes")
|
|
31
|
+
site_parameter_mismatch = _assert_model_parameters(global_meta, array_model.site_model)
|
|
32
|
+
sim_telarray_seed_mismatch = _assert_sim_telarray_seed(
|
|
33
|
+
global_meta, array_model.sim_telarray_seeds, file
|
|
34
|
+
)
|
|
35
|
+
if sim_telarray_seed_mismatch:
|
|
36
|
+
site_parameter_mismatch.append(sim_telarray_seed_mismatch)
|
|
37
|
+
|
|
38
|
+
if len(telescope_meta) != len(array_model.telescope_model):
|
|
39
|
+
raise ValueError(
|
|
40
|
+
f"Number of telescopes in sim_telarray file ({len(telescope_meta)}) does not match "
|
|
41
|
+
f"number of telescopes in array model ({len(array_model.telescope_model)})"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
for telescope_name in array_model.telescope_model.keys():
|
|
45
|
+
if not get_sim_telarray_telescope_id(telescope_name, file):
|
|
46
|
+
raise ValueError(f"Telescope {telescope_name} not found in sim_telarray file metadata")
|
|
47
|
+
|
|
48
|
+
telescope_parameter_mismatch = [
|
|
49
|
+
_assert_model_parameters(telescope_meta[i], model)
|
|
50
|
+
for i, model in enumerate(array_model.telescope_model.values(), start=1)
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
# ensure printout of all mismatches, not only those found first
|
|
54
|
+
telescope_parameter_mismatch.append(site_parameter_mismatch)
|
|
55
|
+
if any(len(m) > 0 for m in telescope_parameter_mismatch):
|
|
56
|
+
mismatches = [m for m in telescope_parameter_mismatch if len(m) > 0]
|
|
57
|
+
raise ValueError(
|
|
58
|
+
f"Telescope or site model parameters do not match sim_telarray metadata: {mismatches}"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _assert_model_parameters(metadata, model):
|
|
63
|
+
"""
|
|
64
|
+
Assert that model parameter values matches the values in the sim_telarray metadata.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
metadata: dict
|
|
69
|
+
Metadata dictionary.
|
|
70
|
+
model: SiteModel, TelescopeModel
|
|
71
|
+
Model to compare with.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
invalid_parameter_list: list
|
|
76
|
+
List of parameters that do not match.
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
config_reader = SimtelConfigReader()
|
|
80
|
+
|
|
81
|
+
invalid_parameter_list = []
|
|
82
|
+
|
|
83
|
+
for param in model.parameters:
|
|
84
|
+
sim_telarray_name = _sim_telarray_name_from_parameter_name(param)
|
|
85
|
+
if sim_telarray_name in metadata.keys():
|
|
86
|
+
parameter_type = model.parameters[param]["type"]
|
|
87
|
+
if parameter_type not in ("string", "dict", "boolean"):
|
|
88
|
+
value, _ = config_reader.extract_value_from_sim_telarray_column(
|
|
89
|
+
[metadata[sim_telarray_name]], parameter_type
|
|
90
|
+
)
|
|
91
|
+
else:
|
|
92
|
+
value = metadata[sim_telarray_name]
|
|
93
|
+
value = (int)(value) if value.isnumeric() else value
|
|
94
|
+
|
|
95
|
+
if not is_equal(value, model.parameters[param]["value"], parameter_type):
|
|
96
|
+
invalid_parameter_list.append(
|
|
97
|
+
f"Parameter {param} mismatch between sim_telarray file: {value}, "
|
|
98
|
+
f"and model: {model.parameters[param]['value']}"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
return invalid_parameter_list
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _assert_sim_telarray_seed(metadata, sim_telarray_seeds, file=None):
|
|
105
|
+
"""
|
|
106
|
+
Assert that sim_telarray seed matches the values in the sim_telarray metadata.
|
|
107
|
+
|
|
108
|
+
Regenerate seeds using the sim_telarray_random_seeds function and compare with the metadata.
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
metadata: dict
|
|
113
|
+
Metadata dictionary.
|
|
114
|
+
sim_telarray_seeds: dict
|
|
115
|
+
Dictionary of sim_telarray seeds.
|
|
116
|
+
file : Path
|
|
117
|
+
Path to the sim_telarray file.
|
|
118
|
+
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
invalid_parameter_list: list
|
|
122
|
+
Error message if sim_telarray seeds do not match.
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
if not sim_telarray_seeds or not metadata:
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
if "instrument_seed" in metadata.keys() and "instrument_instances" in metadata.keys():
|
|
129
|
+
if str(metadata.get("instrument_seed")) != str(sim_telarray_seeds.get("seed")):
|
|
130
|
+
return (
|
|
131
|
+
"Parameter instrument_seed mismatch between sim_telarray file: "
|
|
132
|
+
f"{metadata['instrument_seed']}, and model: {sim_telarray_seeds.get('seed')}"
|
|
133
|
+
)
|
|
134
|
+
_logger.info(
|
|
135
|
+
f"sim_telarray_seed in sim_telarray file: {metadata['instrument_seed']}, "
|
|
136
|
+
f"and model: {sim_telarray_seeds.get('seed')}"
|
|
137
|
+
)
|
|
138
|
+
if file:
|
|
139
|
+
run_number_modified = get_corsika_run_number(file) - 1
|
|
140
|
+
test_seeds = sim_telarray_random_seeds(
|
|
141
|
+
int(metadata["instrument_seed"]), int(metadata["instrument_instances"])
|
|
142
|
+
)
|
|
143
|
+
# no +1 as in sim_telarray (as we count from 0)
|
|
144
|
+
seed_used = run_number_modified % int(metadata["instrument_instances"])
|
|
145
|
+
if str(metadata.get("rng_select_seed")) != str(test_seeds[seed_used]):
|
|
146
|
+
return (
|
|
147
|
+
"Parameter rng_select_seed mismatch between sim_telarray file: "
|
|
148
|
+
f"{metadata['rng_select_seed']}, and model: {test_seeds[seed_used]}"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return None
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _sim_telarray_name_from_parameter_name(parameter_name):
|
|
155
|
+
"""Return sim_telarray parameter name. Some specific fine tuning."""
|
|
156
|
+
# parameters like "reference_point_latitude"
|
|
157
|
+
sim_telarray_name = parameter_name.replace("reference_point_", "")
|
|
158
|
+
|
|
159
|
+
if sim_telarray_name == "altitude":
|
|
160
|
+
return "corsika_observation_level"
|
|
161
|
+
if sim_telarray_name == "array_triggers":
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
return sim_telarray_name
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def is_equal(value1, value2, value_type):
|
|
168
|
+
"""
|
|
169
|
+
Check if two values are equal based on their type.
|
|
170
|
+
|
|
171
|
+
The complexity of this function reflects the complexity of the sim_telarray
|
|
172
|
+
metadata output.
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
value1: any
|
|
177
|
+
First value to compare.
|
|
178
|
+
value2: any
|
|
179
|
+
Second value to compare.
|
|
180
|
+
value_type: str
|
|
181
|
+
Type of the values ('string', 'dict', etc.).
|
|
182
|
+
|
|
183
|
+
Returns
|
|
184
|
+
-------
|
|
185
|
+
bool
|
|
186
|
+
True if the values are equal, False otherwise.
|
|
187
|
+
"""
|
|
188
|
+
value1 = value1[0] if isinstance(value1, tuple) else value1
|
|
189
|
+
value2 = value2[0] if isinstance(value2, tuple) else value2
|
|
190
|
+
if value1 is None or value2 is None:
|
|
191
|
+
if value1 in ("none", None) and value2 in ("none", None):
|
|
192
|
+
return True
|
|
193
|
+
if value_type == "string":
|
|
194
|
+
return str(value1).strip() == str(value2).strip()
|
|
195
|
+
if value_type == "dict":
|
|
196
|
+
return value1 == value2
|
|
197
|
+
if value_type == "boolean":
|
|
198
|
+
return bool(value1) == bool(value2)
|
|
199
|
+
return _is_equal_floats_or_ints(value1, value2)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _is_equal_floats_or_ints(value1, value2):
|
|
203
|
+
"""Check if floats and ints are equal."""
|
|
204
|
+
if isinstance(value1, np.ndarray | list) and isinstance(value2, np.ndarray | list):
|
|
205
|
+
return bool(np.allclose(np.array(value1), np.array(value2), rtol=1e-10))
|
|
206
|
+
if isinstance(value1, list) and isinstance(value2, float | int | np.integer | np.floating):
|
|
207
|
+
if all(x == value1[0] for x in value1):
|
|
208
|
+
return bool(np.isclose(float(value1[0]), float(value2), rtol=1e-10))
|
|
209
|
+
if isinstance(value2, list) and isinstance(value1, float | int | np.integer | np.floating):
|
|
210
|
+
if all(x == value2[0] for x in value2):
|
|
211
|
+
return bool(np.isclose(float(value1), float(value2[0]), rtol=1e-10))
|
|
212
|
+
return bool(np.isclose(float(value1), float(value2), rtol=1e-10))
|
|
@@ -64,11 +64,18 @@ def _validate_output_files(config, integration_test):
|
|
|
64
64
|
|
|
65
65
|
def _test_simtel_cfg_files(config, integration_test, from_command_line, from_config_file):
|
|
66
66
|
"""Test simtel cfg files."""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
cfg_files = integration_test.get("TEST_SIMTEL_CFG_FILES", {})
|
|
68
|
+
if isinstance(from_command_line, list):
|
|
69
|
+
sources = from_command_line
|
|
70
|
+
elif isinstance(from_config_file, list):
|
|
71
|
+
sources = from_config_file
|
|
72
|
+
else:
|
|
73
|
+
sources = [from_command_line or from_config_file]
|
|
74
|
+
for version in sources:
|
|
75
|
+
cfg = cfg_files.get(version)
|
|
76
|
+
if cfg:
|
|
77
|
+
_validate_simtel_cfg_files(config, cfg)
|
|
78
|
+
break
|
|
72
79
|
|
|
73
80
|
|
|
74
81
|
def _validate_reference_output_file(config, integration_test):
|