gammasimtools 0.15.0__py3-none-any.whl → 0.17.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.17.0.dist-info}/METADATA +5 -33
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/RECORD +243 -229
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/entry_points.txt +8 -3
- 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_ctao_array_layouts.py +5 -5
- 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/generate_simtel_event_data.py +36 -46
- simtools/applications/merge_tables.py +104 -0
- simtools/applications/plot_array_layout.py +145 -258
- simtools/applications/production_derive_corsika_limits.py +35 -167
- simtools/applications/production_derive_statistics.py +159 -0
- simtools/applications/production_generate_grid.py +197 -0
- simtools/applications/simulate_light_emission.py +6 -13
- simtools/applications/simulate_prod.py +45 -21
- simtools/applications/simulate_prod_htcondor_generator.py +0 -1
- simtools/applications/submit_array_layouts.py +93 -0
- 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/applications/verify_simulation_model_production_tables.py +52 -0
- simtools/camera/camera_efficiency.py +17 -42
- simtools/configuration/commandline_parser.py +32 -37
- simtools/configuration/configurator.py +10 -4
- simtools/corsika/corsika_config.py +120 -17
- simtools/corsika/primary_particle.py +46 -13
- simtools/data_model/format_checkers.py +9 -0
- simtools/data_model/metadata_collector.py +7 -3
- 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 +21 -15
- simtools/db/db_model_upload.py +2 -2
- simtools/io_operations/io_handler.py +2 -2
- simtools/io_operations/io_table_handler.py +345 -0
- simtools/job_execution/htcondor_script_generator.py +2 -2
- simtools/job_execution/job_manager.py +7 -121
- simtools/layout/array_layout.py +1 -0
- simtools/layout/array_layout_utils.py +385 -0
- simtools/model/array_model.py +68 -29
- simtools/model/model_parameter.py +76 -51
- simtools/model/model_repository.py +134 -0
- 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 → calculate_statistical_uncertainties_grid_point.py} +101 -116
- simtools/production_configuration/derive_corsika_limits.py +239 -111
- simtools/production_configuration/derive_corsika_limits_grid.py +189 -0
- simtools/production_configuration/derive_production_statistics.py +155 -0
- simtools/production_configuration/derive_production_statistics_handler.py +152 -0
- simtools/production_configuration/generate_production_grid.py +364 -0
- simtools/production_configuration/interpolation_handler.py +303 -96
- simtools/ray_tracing/mirror_panel_psf.py +16 -20
- simtools/ray_tracing/psf_analysis.py +2 -2
- simtools/ray_tracing/ray_tracing.py +12 -7
- simtools/reporting/docs_read_parameters.py +426 -81
- simtools/runners/corsika_runner.py +11 -1
- simtools/runners/corsika_simtel_runner.py +84 -90
- simtools/runners/runner_services.py +22 -8
- 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 +44 -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/schemas/production_configuration_metrics.schema.yml +2 -2
- simtools/simtel/simtel_config_reader.py +21 -17
- simtools/simtel/simtel_config_writer.py +258 -66
- simtools/simtel/simtel_io_event_reader.py +301 -194
- simtools/simtel/simtel_io_event_writer.py +207 -227
- simtools/simtel/simtel_io_file_info.py +62 -0
- simtools/simtel/simtel_io_histogram.py +10 -14
- simtools/simtel/simtel_io_histograms.py +2 -2
- simtools/simtel/simtel_io_metadata.py +106 -0
- simtools/simtel/simulator_array.py +28 -14
- simtools/simtel/simulator_camera_efficiency.py +12 -6
- simtools/simtel/simulator_light_emission.py +85 -45
- simtools/simtel/simulator_ray_tracing.py +16 -6
- simtools/simulator.py +286 -89
- 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 +16 -6
- simtools/utils/general.py +18 -27
- simtools/utils/names.py +32 -10
- simtools/visualization/plot_array_layout.py +242 -0
- simtools/visualization/plot_pixels.py +681 -0
- simtools/visualization/visualize.py +5 -221
- simtools/applications/production_generate_simulation_config.py +0 -162
- simtools/applications/production_scale_events.py +0 -185
- simtools/layout/ctao_array_layouts.py +0 -172
- simtools/production_configuration/event_scaler.py +0 -120
- simtools/production_configuration/generate_simulation_config.py +0 -158
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.15.0.dist-info → gammasimtools-0.17.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
|
|
@@ -11,12 +12,14 @@ import numpy as np
|
|
|
11
12
|
|
|
12
13
|
import simtools.utils.general as gen
|
|
13
14
|
from simtools.corsika.corsika_config import CorsikaConfig
|
|
14
|
-
from simtools.io_operations import io_handler
|
|
15
|
+
from simtools.io_operations import io_handler, io_table_handler
|
|
15
16
|
from simtools.job_execution.job_manager import JobManager
|
|
16
17
|
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
|
|
20
|
+
from simtools.simtel.simtel_io_event_writer import SimtelIOEventDataWriter
|
|
19
21
|
from simtools.simtel.simulator_array import SimulatorArray
|
|
22
|
+
from simtools.testing.sim_telarray_metadata import assert_sim_telarray_metadata
|
|
20
23
|
|
|
21
24
|
__all__ = [
|
|
22
25
|
"InvalidRunsToSimulateError",
|
|
@@ -70,11 +73,16 @@ class Simulator:
|
|
|
70
73
|
self.runs = self._initialize_run_list()
|
|
71
74
|
self._results = defaultdict(list)
|
|
72
75
|
self._test = self.args_dict.get("test", False)
|
|
73
|
-
self.submit_engine = self.args_dict.get("submit_engine", "local")
|
|
74
|
-
self._submit_options = self.args_dict.get("submit_options", None)
|
|
75
76
|
self._extra_commands = extra_commands
|
|
76
77
|
|
|
77
|
-
self.
|
|
78
|
+
self.sim_telarray_seeds = {
|
|
79
|
+
"seed": self.args_dict.get("sim_telarray_instrument_seeds"),
|
|
80
|
+
"random_instrument_instances": self.args_dict.get(
|
|
81
|
+
"sim_telarray_random_instrument_instances"
|
|
82
|
+
),
|
|
83
|
+
"seed_file_name": "sim_telarray_instrument_seeds.txt", # name only; no directory
|
|
84
|
+
}
|
|
85
|
+
self.array_models = self._initialize_array_models(mongo_db_config)
|
|
78
86
|
self._simulation_runner = self._initialize_simulation_runner(mongo_db_config)
|
|
79
87
|
|
|
80
88
|
@property
|
|
@@ -89,8 +97,8 @@ class Simulator:
|
|
|
89
97
|
|
|
90
98
|
Parameters
|
|
91
99
|
----------
|
|
92
|
-
simulation_software: choices: [
|
|
93
|
-
implemented are sim_telarray and CORSIKA or
|
|
100
|
+
simulation_software: choices: [sim_telarray, corsika, corsika_sim_telarray]
|
|
101
|
+
implemented are sim_telarray and CORSIKA or corsika_sim_telarray
|
|
94
102
|
(running CORSIKA and piping it directly to sim_telarray)
|
|
95
103
|
|
|
96
104
|
Raises
|
|
@@ -98,14 +106,14 @@ class Simulator:
|
|
|
98
106
|
gen.InvalidConfigDataError
|
|
99
107
|
|
|
100
108
|
"""
|
|
101
|
-
if simulation_software not in ["
|
|
109
|
+
if simulation_software not in ["sim_telarray", "corsika", "corsika_sim_telarray"]:
|
|
102
110
|
self._logger.error(f"Invalid simulation software: {simulation_software}")
|
|
103
111
|
raise gen.InvalidConfigDataError
|
|
104
112
|
self._simulation_software = simulation_software.lower()
|
|
105
113
|
|
|
106
|
-
def
|
|
114
|
+
def _initialize_array_models(self, mongo_db_config):
|
|
107
115
|
"""
|
|
108
|
-
Initialize array simulation
|
|
116
|
+
Initialize array simulation models.
|
|
109
117
|
|
|
110
118
|
Parameters
|
|
111
119
|
----------
|
|
@@ -114,20 +122,67 @@ class Simulator:
|
|
|
114
122
|
|
|
115
123
|
Returns
|
|
116
124
|
-------
|
|
117
|
-
|
|
118
|
-
ArrayModel
|
|
119
|
-
"""
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
list
|
|
126
|
+
List of ArrayModel objects.
|
|
127
|
+
"""
|
|
128
|
+
model_version = self.args_dict.get("model_version", [])
|
|
129
|
+
versions = [model_version] if not isinstance(model_version, list) else model_version
|
|
130
|
+
|
|
131
|
+
return [
|
|
132
|
+
ArrayModel(
|
|
133
|
+
label=self.label,
|
|
134
|
+
site=self.args_dict.get("site"),
|
|
135
|
+
layout_name=self.args_dict.get("array_layout_name"),
|
|
136
|
+
mongo_db_config=mongo_db_config,
|
|
137
|
+
model_version=version,
|
|
138
|
+
sim_telarray_seeds={
|
|
139
|
+
"seed": self._get_seed_for_random_instrument_instances(
|
|
140
|
+
self.sim_telarray_seeds["seed"], version
|
|
141
|
+
),
|
|
142
|
+
"random_instrument_instances": self.sim_telarray_seeds[
|
|
143
|
+
"random_instrument_instances"
|
|
144
|
+
],
|
|
145
|
+
"seed_file_name": self.sim_telarray_seeds["seed_file_name"],
|
|
146
|
+
},
|
|
147
|
+
simtel_path=self.args_dict.get("simtel_path", None),
|
|
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
|
"""
|
|
130
|
-
Initialize run list using the configuration values
|
|
182
|
+
Initialize run list using the configuration values.
|
|
183
|
+
|
|
184
|
+
Uses 'run_number', 'run_number_offset' and 'number_of_runs' arguments
|
|
185
|
+
to create a list of run numbers.
|
|
131
186
|
|
|
132
187
|
Returns
|
|
133
188
|
-------
|
|
@@ -137,19 +192,27 @@ class Simulator:
|
|
|
137
192
|
Raises
|
|
138
193
|
------
|
|
139
194
|
KeyError
|
|
140
|
-
If '
|
|
195
|
+
If 'run_number', 'run_number_offset' and 'number_of_runs' are
|
|
196
|
+
not found in the configuration.
|
|
141
197
|
"""
|
|
142
198
|
try:
|
|
199
|
+
offset_run_number = self.args_dict["run_number_offset"] + self.args_dict["run_number"]
|
|
200
|
+
if self.args_dict["number_of_runs"] <= 1:
|
|
201
|
+
return self._validate_run_list_and_range(
|
|
202
|
+
run_list=offset_run_number,
|
|
203
|
+
run_range=None,
|
|
204
|
+
)
|
|
143
205
|
return self._validate_run_list_and_range(
|
|
144
206
|
run_list=None,
|
|
145
207
|
run_range=[
|
|
146
|
-
|
|
147
|
-
|
|
208
|
+
offset_run_number,
|
|
209
|
+
offset_run_number + self.args_dict["number_of_runs"],
|
|
148
210
|
],
|
|
149
211
|
)
|
|
150
212
|
except KeyError as exc:
|
|
151
213
|
self._logger.error(
|
|
152
|
-
"Error in initializing run list
|
|
214
|
+
"Error in initializing run list "
|
|
215
|
+
"(missing 'run_number', 'run_number_offset' or 'number_of_runs')."
|
|
153
216
|
)
|
|
154
217
|
raise exc
|
|
155
218
|
|
|
@@ -214,22 +277,33 @@ class Simulator:
|
|
|
214
277
|
CorsikaRunner or SimulatorArray or CorsikaSimtelRunner
|
|
215
278
|
Simulation runner object.
|
|
216
279
|
"""
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
280
|
+
corsika_configurations = []
|
|
281
|
+
for array_model in self.array_models:
|
|
282
|
+
corsika_configurations.append(
|
|
283
|
+
CorsikaConfig(
|
|
284
|
+
array_model=array_model,
|
|
285
|
+
label=self.label,
|
|
286
|
+
args_dict=self.args_dict,
|
|
287
|
+
db_config=db_config,
|
|
288
|
+
)
|
|
289
|
+
)
|
|
223
290
|
|
|
224
291
|
runner_class = {
|
|
225
292
|
"corsika": CorsikaRunner,
|
|
226
|
-
"
|
|
227
|
-
"
|
|
293
|
+
"sim_telarray": SimulatorArray,
|
|
294
|
+
"corsika_sim_telarray": CorsikaSimtelRunner,
|
|
228
295
|
}.get(self.simulation_software)
|
|
229
296
|
|
|
297
|
+
# In case of CorsikaSimtelRunner we should pass all corsika_configurations
|
|
298
|
+
# to the runner, since we define multiple configurations to run in a single job
|
|
299
|
+
# using multipipe. In other cases we pass only the first one (there's only one anyway).
|
|
230
300
|
runner_args = {
|
|
231
301
|
"label": self.label,
|
|
232
|
-
"corsika_config":
|
|
302
|
+
"corsika_config": (
|
|
303
|
+
corsika_configurations
|
|
304
|
+
if runner_class is CorsikaSimtelRunner
|
|
305
|
+
else corsika_configurations[0]
|
|
306
|
+
),
|
|
233
307
|
"simtel_path": self.args_dict.get("simtel_path"),
|
|
234
308
|
"use_multipipe": runner_class is CorsikaSimtelRunner,
|
|
235
309
|
}
|
|
@@ -237,7 +311,9 @@ class Simulator:
|
|
|
237
311
|
if runner_class is not SimulatorArray:
|
|
238
312
|
runner_args["keep_seeds"] = self.args_dict.get("corsika_test_seeds", False)
|
|
239
313
|
if runner_class is not CorsikaRunner:
|
|
240
|
-
runner_args["sim_telarray_seeds"] = self.
|
|
314
|
+
runner_args["sim_telarray_seeds"] = self.sim_telarray_seeds
|
|
315
|
+
if runner_class is CorsikaSimtelRunner:
|
|
316
|
+
runner_args["sequential"] = self.args_dict.get("sequential", False)
|
|
241
317
|
|
|
242
318
|
return runner_class(**runner_args)
|
|
243
319
|
|
|
@@ -267,8 +343,6 @@ class Simulator:
|
|
|
267
343
|
input_file_list: str or list of str
|
|
268
344
|
Single file or list of files of shower simulations.
|
|
269
345
|
"""
|
|
270
|
-
self._logger.info(f"Submission command: {self.submit_engine}")
|
|
271
|
-
|
|
272
346
|
runs_and_files_to_submit = self._get_runs_and_files_to_submit(
|
|
273
347
|
input_file_list=input_file_list
|
|
274
348
|
)
|
|
@@ -282,11 +356,7 @@ class Simulator:
|
|
|
282
356
|
run_number=run_number, input_file=input_file, extra_commands=self._extra_commands
|
|
283
357
|
)
|
|
284
358
|
|
|
285
|
-
job_manager = JobManager(
|
|
286
|
-
submit_engine=self.submit_engine,
|
|
287
|
-
submit_options=self._submit_options,
|
|
288
|
-
test=self._test,
|
|
289
|
-
)
|
|
359
|
+
job_manager = JobManager(test=self._test)
|
|
290
360
|
job_manager.submit(
|
|
291
361
|
run_script=run_script,
|
|
292
362
|
run_out_file=self._simulation_runner.get_file_name(
|
|
@@ -325,10 +395,10 @@ class Simulator:
|
|
|
325
395
|
_runs_and_files = {}
|
|
326
396
|
self._logger.debug(f"Getting runs and files to submit ({input_file_list})")
|
|
327
397
|
|
|
328
|
-
if self.simulation_software == "
|
|
398
|
+
if self.simulation_software == "sim_telarray":
|
|
329
399
|
input_file_list = self._enforce_list_type(input_file_list)
|
|
330
400
|
_runs_and_files = {self._guess_run_from_file(file): file for file in input_file_list}
|
|
331
|
-
elif self.simulation_software in ["corsika", "
|
|
401
|
+
elif self.simulation_software in ["corsika", "corsika_sim_telarray"]:
|
|
332
402
|
_runs_and_files = dict.fromkeys(self._get_runs_to_simulate())
|
|
333
403
|
if len(_runs_and_files) == 0:
|
|
334
404
|
raise ValueError("No runs to submit.")
|
|
@@ -391,46 +461,66 @@ class Simulator:
|
|
|
391
461
|
run number
|
|
392
462
|
|
|
393
463
|
"""
|
|
394
|
-
keys = ["
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
self._simulation_runner.get_file_name(file_type=
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
464
|
+
keys = ["simtel_output", "sub_out", "log", "input", "hist", "corsika_log", "event_data"]
|
|
465
|
+
results = {key: [] for key in keys}
|
|
466
|
+
|
|
467
|
+
def get_file_name(name, **kwargs):
|
|
468
|
+
return str(self._simulation_runner.get_file_name(file_type=name, **kwargs))
|
|
469
|
+
|
|
470
|
+
if "sim_telarray" in self.simulation_software:
|
|
471
|
+
results["input"].append(str(file))
|
|
472
|
+
|
|
473
|
+
results["sub_out"].append(get_file_name("sub_log", mode="out", run_number=run_number))
|
|
474
|
+
|
|
475
|
+
for i in range(len(self.array_models)):
|
|
476
|
+
results["simtel_output"].append(
|
|
477
|
+
get_file_name("simtel_output", run_number=run_number, model_version_index=i)
|
|
403
478
|
)
|
|
404
|
-
)
|
|
405
479
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
480
|
+
if "sim_telarray" in self.simulation_software:
|
|
481
|
+
results["log"].append(
|
|
482
|
+
get_file_name(
|
|
483
|
+
"log",
|
|
484
|
+
simulation_software="sim_telarray",
|
|
485
|
+
run_number=run_number,
|
|
486
|
+
model_version_index=i,
|
|
487
|
+
)
|
|
410
488
|
)
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
489
|
+
results["hist"].append(
|
|
490
|
+
get_file_name(
|
|
491
|
+
"histogram",
|
|
492
|
+
simulation_software="sim_telarray",
|
|
493
|
+
run_number=run_number,
|
|
494
|
+
model_version_index=i,
|
|
495
|
+
)
|
|
496
|
+
)
|
|
497
|
+
results["event_data"].append(
|
|
498
|
+
get_file_name(
|
|
499
|
+
"event_data",
|
|
500
|
+
simulation_software="sim_telarray",
|
|
501
|
+
run_number=run_number,
|
|
502
|
+
model_version_index=i,
|
|
503
|
+
)
|
|
416
504
|
)
|
|
417
|
-
)
|
|
418
505
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
506
|
+
if "corsika" in self.simulation_software:
|
|
507
|
+
results["corsika_log"].append(
|
|
508
|
+
get_file_name(
|
|
509
|
+
"corsika_log",
|
|
510
|
+
simulation_software="corsika",
|
|
511
|
+
run_number=run_number,
|
|
512
|
+
model_version_index=i,
|
|
513
|
+
)
|
|
423
514
|
)
|
|
424
|
-
)
|
|
425
515
|
|
|
426
516
|
for key in keys:
|
|
427
|
-
self._results[key].
|
|
517
|
+
self._results[key].extend(results[key])
|
|
428
518
|
|
|
429
|
-
def get_file_list(self, file_type="
|
|
519
|
+
def get_file_list(self, file_type="simtel_output"):
|
|
430
520
|
"""
|
|
431
521
|
Get list of files generated by simulations.
|
|
432
522
|
|
|
433
|
-
Options are "input", "
|
|
523
|
+
Options are "input", "simtel_output", "hist", "log", "corsika_log".
|
|
434
524
|
Not all file types are available for all simulation types.
|
|
435
525
|
Returns an empty list for an unknown file type.
|
|
436
526
|
|
|
@@ -448,11 +538,11 @@ class Simulator:
|
|
|
448
538
|
self._logger.info(f"Getting list of {file_type} files")
|
|
449
539
|
return self._results[file_type]
|
|
450
540
|
|
|
451
|
-
def print_list_of_files(self, file_type="
|
|
541
|
+
def print_list_of_files(self, file_type="simtel_output"):
|
|
452
542
|
"""
|
|
453
543
|
Print list of output files generated by simulations.
|
|
454
544
|
|
|
455
|
-
Options are "input", "
|
|
545
|
+
Options are "input", "simtel_output", "hist", "log".
|
|
456
546
|
|
|
457
547
|
Parameters
|
|
458
548
|
----------
|
|
@@ -546,7 +636,7 @@ class Simulator:
|
|
|
546
636
|
|
|
547
637
|
def save_file_lists(self):
|
|
548
638
|
"""Save files lists for output and log files."""
|
|
549
|
-
for file_type in ["
|
|
639
|
+
for file_type in ["simtel_output", "log", "corsika_log", "hist"]:
|
|
550
640
|
file_name = self.io_handler.get_output_directory(label=self.label).joinpath(
|
|
551
641
|
f"{file_type}_files.txt"
|
|
552
642
|
)
|
|
@@ -559,10 +649,35 @@ class Simulator:
|
|
|
559
649
|
else:
|
|
560
650
|
self._logger.debug(f"No files to save for {file_type} files.")
|
|
561
651
|
|
|
652
|
+
def save_reduced_event_lists(self):
|
|
653
|
+
"""
|
|
654
|
+
Save reduced event lists with event data on simulated and triggered events.
|
|
655
|
+
|
|
656
|
+
The files are saved with the same name as the sim_telarray output file
|
|
657
|
+
but with a 'hdf5' extension.
|
|
658
|
+
"""
|
|
659
|
+
if "sim_telarray" not in self.simulation_software:
|
|
660
|
+
self._logger.warning(
|
|
661
|
+
"Reduced event lists can only be saved for sim_telarray simulations."
|
|
662
|
+
)
|
|
663
|
+
return
|
|
664
|
+
|
|
665
|
+
input_files = self.get_file_list(file_type="simtel_output")
|
|
666
|
+
output_files = self.get_file_list(file_type="event_data")
|
|
667
|
+
for input_file, output_file in zip(input_files, output_files):
|
|
668
|
+
generator = SimtelIOEventDataWriter([input_file])
|
|
669
|
+
io_table_handler.write_tables(
|
|
670
|
+
tables=generator.process_files(),
|
|
671
|
+
output_file=Path(output_file),
|
|
672
|
+
overwrite_existing=True,
|
|
673
|
+
)
|
|
674
|
+
|
|
562
675
|
def pack_for_register(self, directory_for_grid_upload=None):
|
|
563
676
|
"""
|
|
564
677
|
Pack simulation output files for registering on the grid.
|
|
565
678
|
|
|
679
|
+
Creates separate tarballs for each model version's log files.
|
|
680
|
+
|
|
566
681
|
Parameters
|
|
567
682
|
----------
|
|
568
683
|
directory_for_grid_upload: str
|
|
@@ -572,11 +687,16 @@ class Simulator:
|
|
|
572
687
|
self._logger.info(
|
|
573
688
|
f"Packing the output files for registering on the grid ({directory_for_grid_upload})"
|
|
574
689
|
)
|
|
575
|
-
output_files = self.get_file_list(file_type="
|
|
690
|
+
output_files = self.get_file_list(file_type="simtel_output")
|
|
576
691
|
log_files = self.get_file_list(file_type="log")
|
|
577
692
|
corsika_log_files = self.get_file_list(file_type="corsika_log")
|
|
578
693
|
histogram_files = self.get_file_list(file_type="hist")
|
|
579
|
-
|
|
694
|
+
reduced_event_files = (
|
|
695
|
+
self.get_file_list(file_type="event_data")
|
|
696
|
+
if self.args_dict.get("save_reduced_event_lists")
|
|
697
|
+
else []
|
|
698
|
+
)
|
|
699
|
+
|
|
580
700
|
directory_for_grid_upload = (
|
|
581
701
|
Path(directory_for_grid_upload)
|
|
582
702
|
if directory_for_grid_upload
|
|
@@ -586,24 +706,101 @@ class Simulator:
|
|
|
586
706
|
)
|
|
587
707
|
directory_for_grid_upload.mkdir(parents=True, exist_ok=True)
|
|
588
708
|
|
|
589
|
-
|
|
709
|
+
# If there are more than one model version,
|
|
710
|
+
# duplicate the corsika log file to have one for each model version with the "right name".
|
|
711
|
+
if len(self.array_models) > 1 and corsika_log_files:
|
|
712
|
+
self._copy_corsika_log_file_for_all_versions(corsika_log_files)
|
|
590
713
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
for
|
|
598
|
-
|
|
714
|
+
# Group files by model version
|
|
715
|
+
for model in self.array_models:
|
|
716
|
+
model_version = model.model_version
|
|
717
|
+
|
|
718
|
+
# Filter files for this model version
|
|
719
|
+
model_logs = [f for f in log_files if model_version in f]
|
|
720
|
+
model_hists = [f for f in histogram_files if model_version in f]
|
|
721
|
+
model_corsika_logs = [f for f in corsika_log_files if model_version in f]
|
|
722
|
+
|
|
723
|
+
if model_logs:
|
|
724
|
+
tar_file_name = Path(model_logs[0]).name.replace("log.gz", "log_hist.tar.gz")
|
|
725
|
+
tar_file_path = directory_for_grid_upload.joinpath(tar_file_name)
|
|
599
726
|
|
|
600
|
-
|
|
727
|
+
with tarfile.open(tar_file_path, "w:gz") as tar:
|
|
728
|
+
# Add all relevant log, histogram, and CORSIKA log files to the tarball
|
|
729
|
+
files_to_tar = model_logs + model_hists + model_corsika_logs
|
|
730
|
+
for file_to_tar in files_to_tar:
|
|
731
|
+
tar.add(file_to_tar, arcname=Path(file_to_tar).name)
|
|
732
|
+
|
|
733
|
+
for file_to_move in output_files + reduced_event_files:
|
|
601
734
|
source_file = Path(file_to_move)
|
|
602
735
|
destination_file = directory_for_grid_upload / source_file.name
|
|
603
736
|
if destination_file.exists():
|
|
604
737
|
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
738
|
shutil.move(source_file, destination_file)
|
|
739
|
+
|
|
609
740
|
self._logger.info(f"Output files for the grid placed in {directory_for_grid_upload!s}")
|
|
741
|
+
|
|
742
|
+
def validate_metadata(self):
|
|
743
|
+
"""Validate metadata in the sim_telarray output files."""
|
|
744
|
+
if "sim_telarray" not in self.simulation_software:
|
|
745
|
+
self._logger.info("No sim_telarray files to validate.")
|
|
746
|
+
return
|
|
747
|
+
|
|
748
|
+
for model in self.array_models:
|
|
749
|
+
files = self.get_file_list(file_type="simtel_output")
|
|
750
|
+
output_file = next((f for f in files if model.model_version in f), None)
|
|
751
|
+
if output_file:
|
|
752
|
+
self._logger.info(f"Validating metadata for {output_file}")
|
|
753
|
+
assert_sim_telarray_metadata(output_file, model)
|
|
754
|
+
self._logger.info(f"Metadata for sim_telarray file {output_file} is valid.")
|
|
755
|
+
else:
|
|
756
|
+
self._logger.warning(
|
|
757
|
+
f"No sim_telarray file found for model version {model.model_version}: {files}"
|
|
758
|
+
)
|
|
759
|
+
|
|
760
|
+
def _copy_corsika_log_file_for_all_versions(self, corsika_log_files):
|
|
761
|
+
"""
|
|
762
|
+
Create copies of the CORSIKA log file for each model version.
|
|
763
|
+
|
|
764
|
+
Adds a header comment to each copy explaining its relationship to the original.
|
|
765
|
+
|
|
766
|
+
Parameters
|
|
767
|
+
----------
|
|
768
|
+
corsika_log_files: list
|
|
769
|
+
List containing the original CORSIKA log file path.
|
|
770
|
+
"""
|
|
771
|
+
original_log = Path(corsika_log_files[0])
|
|
772
|
+
# Find which model version the original log belongs to
|
|
773
|
+
original_version = next(
|
|
774
|
+
model.model_version
|
|
775
|
+
for model in self.array_models
|
|
776
|
+
if re.search(
|
|
777
|
+
rf"(?<![0-9A-Za-z]){re.escape(model.model_version)}(?![0-9A-Za-z])",
|
|
778
|
+
original_log.name,
|
|
779
|
+
)
|
|
780
|
+
)
|
|
781
|
+
|
|
782
|
+
for model in self.array_models:
|
|
783
|
+
if model.model_version == original_version:
|
|
784
|
+
continue
|
|
785
|
+
|
|
786
|
+
new_log = original_log.parent / original_log.name.replace(
|
|
787
|
+
original_version, model.model_version
|
|
788
|
+
)
|
|
789
|
+
|
|
790
|
+
with gzip.open(new_log, "wt", encoding="utf-8") as new_file:
|
|
791
|
+
# Write the header to the new file
|
|
792
|
+
header = (
|
|
793
|
+
f"###############################################################\n"
|
|
794
|
+
f"Copy of CORSIKA log file from model version {original_version}.\n"
|
|
795
|
+
f"Applicable also for {model.model_version} (same CORSIKA configuration,\n"
|
|
796
|
+
f"different sim_telarray model versions in the same run).\n"
|
|
797
|
+
f"###############################################################\n\n"
|
|
798
|
+
)
|
|
799
|
+
new_file.write(header)
|
|
800
|
+
|
|
801
|
+
# Copy the content of the original log file, ignoring invalid characters
|
|
802
|
+
with gzip.open(original_log, "rt", encoding="utf-8", errors="ignore") as orig_file:
|
|
803
|
+
for line in orig_file:
|
|
804
|
+
new_file.write(line)
|
|
805
|
+
|
|
806
|
+
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
|