gammasimtools 0.9.0__py3-none-any.whl → 0.10.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.9.0.dist-info → gammasimtools-0.10.0.dist-info}/METADATA +2 -2
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.10.0.dist-info}/RECORD +94 -85
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.10.0.dist-info}/entry_points.txt +2 -1
- simtools/_version.py +2 -2
- simtools/applications/calculate_trigger_rate.py +15 -38
- simtools/applications/convert_all_model_parameters_from_simtel.py +9 -28
- simtools/applications/convert_geo_coordinates_of_array_elements.py +47 -45
- simtools/applications/convert_model_parameter_from_simtel.py +2 -2
- simtools/applications/db_add_file_to_db.py +1 -2
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +110 -0
- simtools/applications/db_add_value_from_json_to_db.py +1 -2
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +6 -6
- simtools/applications/db_get_file_from_db.py +11 -12
- simtools/applications/db_get_parameter_from_db.py +44 -32
- simtools/applications/derive_photon_electron_spectrum.py +99 -0
- simtools/applications/generate_array_config.py +17 -17
- simtools/applications/generate_regular_arrays.py +15 -15
- simtools/applications/generate_simtel_array_histograms.py +11 -48
- simtools/applications/production_generate_simulation_config.py +25 -7
- simtools/applications/production_scale_events.py +2 -2
- simtools/applications/simulate_prod.py +1 -1
- simtools/applications/simulate_prod_htcondor_generator.py +26 -26
- simtools/applications/submit_data_from_external.py +12 -4
- simtools/applications/submit_model_parameter_from_external.py +8 -6
- simtools/applications/validate_camera_efficiency.py +2 -2
- simtools/applications/validate_file_using_schema.py +23 -19
- simtools/camera/single_photon_electron_spectrum.py +168 -0
- simtools/configuration/commandline_parser.py +8 -1
- simtools/constants.py +10 -3
- simtools/corsika/corsika_config.py +8 -7
- simtools/corsika/corsika_histograms.py +1 -1
- simtools/data_model/data_reader.py +0 -3
- simtools/data_model/metadata_collector.py +3 -4
- simtools/data_model/metadata_model.py +8 -124
- simtools/data_model/model_data_writer.py +17 -63
- simtools/data_model/schema.py +213 -0
- simtools/data_model/validate_data.py +9 -44
- simtools/db/db_handler.py +323 -495
- simtools/db/db_model_upload.py +139 -0
- simtools/io_operations/hdf5_handler.py +54 -24
- simtools/layout/array_layout.py +33 -28
- simtools/model/array_model.py +13 -7
- simtools/model/model_parameter.py +22 -54
- simtools/model/site_model.py +2 -2
- simtools/production_configuration/calculate_statistical_errors_grid_point.py +119 -144
- simtools/production_configuration/event_scaler.py +7 -17
- simtools/production_configuration/generate_simulation_config.py +5 -32
- simtools/production_configuration/interpolation_handler.py +8 -11
- simtools/runners/corsika_simtel_runner.py +3 -1
- simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +39 -0
- simtools/schemas/input/single_pe_spectrum.schema.yml +38 -0
- simtools/schemas/integration_tests_config.metaschema.yml +10 -0
- simtools/schemas/model_parameter.metaschema.yml +7 -2
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +2 -0
- simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
- simtools/schemas/model_parameters/array_window.schema.yml +37 -0
- simtools/schemas/model_parameters/asum_clipping.schema.yml +0 -4
- simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_clipping.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_offset.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_pedsub.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_prescale.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_presum_max.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_shaping.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +0 -2
- simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_noise.schema.yml +3 -3
- simtools/schemas/model_parameters/fake_mirror_list.schema.yml +33 -0
- simtools/schemas/model_parameters/laser_photons.schema.yml +2 -2
- simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
- simtools/schemas/production_configuration_metrics.schema.yml +68 -0
- simtools/schemas/production_tables.schema.yml +41 -0
- simtools/simtel/simtel_config_writer.py +5 -6
- simtools/simtel/simtel_io_histogram.py +32 -67
- simtools/simtel/simtel_io_histograms.py +15 -30
- simtools/simtel/simulator_array.py +2 -1
- simtools/simtel/simulator_camera_efficiency.py +5 -0
- simtools/simtel/simulator_light_emission.py +3 -1
- simtools/simtel/simulator_ray_tracing.py +2 -1
- simtools/testing/helpers.py +6 -13
- simtools/testing/validate_output.py +131 -47
- simtools/utils/general.py +102 -12
- simtools/utils/names.py +24 -20
- simtools/applications/db_add_model_parameters_from_repository_to_db.py +0 -176
- simtools/db/db_array_elements.py +0 -130
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.10.0.dist-info}/LICENSE +0 -0
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.10.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.10.0.dist-info}/top_level.txt +0 -0
- /simtools/{camera_efficiency.py → camera/camera_efficiency.py} +0 -0
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Reads the content of multiples files from sim_telarray.
|
|
3
|
-
|
|
4
|
-
Reads the content of either multiple histogram (.hdata, or .hdata.zst) or
|
|
5
|
-
simtel_array output files (.simtel or .simtel.zst). The module is built on top of the
|
|
6
|
-
simtel_io_histogram module and uses its class (SimtelIOHistogram) to read the individual files.
|
|
7
|
-
"""
|
|
1
|
+
"""Reads the content of multiples files from sim_telarray."""
|
|
8
2
|
|
|
9
3
|
import copy
|
|
10
4
|
import logging
|
|
@@ -192,8 +186,9 @@ class SimtelIOHistograms:
|
|
|
192
186
|
energy_range=self.energy_range,
|
|
193
187
|
view_cone=self.view_cone,
|
|
194
188
|
)
|
|
195
|
-
|
|
196
|
-
|
|
189
|
+
_simulated, _triggered = simtel_hist_instance.total_number_of_events
|
|
190
|
+
stacked_num_simulated_events += _simulated
|
|
191
|
+
stacked_num_triggered_events += _triggered
|
|
197
192
|
return stacked_num_simulated_events, stacked_num_triggered_events
|
|
198
193
|
|
|
199
194
|
def _rates_for_stacked_files(self):
|
|
@@ -245,7 +240,7 @@ class SimtelIOHistograms:
|
|
|
245
240
|
logging.info(
|
|
246
241
|
f"System trigger event rate for stacked files: "
|
|
247
242
|
# pylint: disable=E1101
|
|
248
|
-
f"{triggered_event_rate.value:.4e} \
|
|
243
|
+
f"{triggered_event_rate.value:.4e} \u00b1 "
|
|
249
244
|
# pylint: disable=E1101
|
|
250
245
|
f"{triggered_event_rate_uncertainty.value:.4e} Hz"
|
|
251
246
|
)
|
|
@@ -282,24 +277,17 @@ class SimtelIOHistograms:
|
|
|
282
277
|
if print_info:
|
|
283
278
|
simtel_hist_instance.print_info()
|
|
284
279
|
|
|
280
|
+
_simulated_events, _triggered_events = simtel_hist_instance.total_number_of_events
|
|
285
281
|
logging.info(f"Histogram {i_file + 1}:")
|
|
286
|
-
logging.info(
|
|
287
|
-
|
|
288
|
-
f"{simtel_hist_instance.total_num_simulated_events} events"
|
|
289
|
-
)
|
|
290
|
-
logging.info(
|
|
291
|
-
"Total number of triggered events: "
|
|
292
|
-
f"{simtel_hist_instance.total_num_triggered_events} events"
|
|
293
|
-
)
|
|
282
|
+
logging.info(f"Total number of simulated events: {_simulated_events} events")
|
|
283
|
+
logging.info(f"Total number of triggered events: {_triggered_events} events")
|
|
294
284
|
|
|
295
|
-
obs_time = simtel_hist_instance.estimate_observation_time(
|
|
296
|
-
simtel_hist_instance.total_num_simulated_events
|
|
297
|
-
)
|
|
285
|
+
obs_time = simtel_hist_instance.estimate_observation_time(_simulated_events)
|
|
298
286
|
logging.info(
|
|
299
287
|
f"Estimated equivalent observation time corresponding to the number of "
|
|
300
288
|
f"events simulated: {obs_time.value} s"
|
|
301
289
|
)
|
|
302
|
-
sim_event_rate =
|
|
290
|
+
sim_event_rate = _simulated_events / obs_time
|
|
303
291
|
sim_event_rates.append(sim_event_rate)
|
|
304
292
|
logging.info(f"Simulated event rate: {sim_event_rate.value:.4e} Hz")
|
|
305
293
|
|
|
@@ -310,7 +298,7 @@ class SimtelIOHistograms:
|
|
|
310
298
|
logging.info(
|
|
311
299
|
f"System trigger event rate: "
|
|
312
300
|
# pylint: disable=E1101
|
|
313
|
-
f"{triggered_event_rate.value:.4e} \
|
|
301
|
+
f"{triggered_event_rate.value:.4e} \u00b1 "
|
|
314
302
|
# pylint: disable=E1101
|
|
315
303
|
f"{triggered_event_rate_uncertainty.value:.4e} Hz"
|
|
316
304
|
)
|
|
@@ -515,15 +503,16 @@ class SimtelIOHistograms:
|
|
|
515
503
|
|
|
516
504
|
def export_histograms(self, hdf5_file_name, overwrite=False):
|
|
517
505
|
"""
|
|
518
|
-
Export
|
|
506
|
+
Export sim_telarray histograms to hdf5 files.
|
|
519
507
|
|
|
520
508
|
Parameters
|
|
521
509
|
----------
|
|
522
510
|
hdf5_file_name: str
|
|
523
511
|
Name of the file to be saved with the hdf5 tables.
|
|
524
512
|
overwrite: bool
|
|
525
|
-
If True overwrites
|
|
513
|
+
If True overwrites histograms already saved in the hdf5 file.
|
|
526
514
|
"""
|
|
515
|
+
self._logger.info(f"Exporting histograms to {hdf5_file_name}.")
|
|
527
516
|
for histogram in self.combined_hists:
|
|
528
517
|
x_bin_edges_list = np.linspace(
|
|
529
518
|
histogram["lower_x"],
|
|
@@ -556,14 +545,10 @@ class SimtelIOHistograms:
|
|
|
556
545
|
f"Writing histogram with name {self._meta_dict['Title']} to {hdf5_file_name}."
|
|
557
546
|
)
|
|
558
547
|
# overwrite takes precedence over append
|
|
559
|
-
if overwrite is True:
|
|
560
|
-
append = False
|
|
561
|
-
else:
|
|
562
|
-
append = True
|
|
563
548
|
write_table(
|
|
564
549
|
table,
|
|
565
550
|
hdf5_file_name,
|
|
566
551
|
f"/{self._meta_dict['Title']}",
|
|
567
|
-
append=
|
|
552
|
+
append=not overwrite,
|
|
568
553
|
overwrite=overwrite,
|
|
569
554
|
)
|
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
|
|
5
5
|
from simtools.io_operations import io_handler
|
|
6
6
|
from simtools.runners.simtel_runner import InvalidOutputFileError, SimtelRunner
|
|
7
|
+
from simtools.utils.general import clear_default_sim_telarray_cfg_directories
|
|
7
8
|
|
|
8
9
|
__all__ = ["SimulatorArray"]
|
|
9
10
|
|
|
@@ -88,7 +89,7 @@ class SimulatorArray(SimtelRunner):
|
|
|
88
89
|
command += f" {input_file}"
|
|
89
90
|
command += f" > {self._log_file} 2>&1 || exit"
|
|
90
91
|
|
|
91
|
-
return command
|
|
92
|
+
return clear_default_sim_telarray_cfg_directories(command)
|
|
92
93
|
|
|
93
94
|
def _check_run_result(self, run_number=None):
|
|
94
95
|
"""
|
|
@@ -135,6 +135,8 @@ class SimulatorCameraEfficiency(SimtelRunner):
|
|
|
135
135
|
command += f" {pixel_shape_cmd} {pixel_diameter}"
|
|
136
136
|
if mirror_class == 0:
|
|
137
137
|
command += f" -fmir {self._telescope_model.get_parameter_value('mirror_list')}"
|
|
138
|
+
if mirror_class == 2:
|
|
139
|
+
command += f" -fmir {self._telescope_model.get_parameter_value('fake_mirror_list')}"
|
|
138
140
|
command += f" -fref {mirror_reflectivity}"
|
|
139
141
|
if mirror_class == 2:
|
|
140
142
|
command += " -m2"
|
|
@@ -155,6 +157,9 @@ class SimulatorCameraEfficiency(SimtelRunner):
|
|
|
155
157
|
command += f" {self._telescope_model.get_parameter_value('atmospheric_profile')}"
|
|
156
158
|
command += f" {self.zenith_angle}"
|
|
157
159
|
|
|
160
|
+
# Remove the default sim_telarray configuration directories
|
|
161
|
+
command = general.clear_default_sim_telarray_cfg_directories(command)
|
|
162
|
+
|
|
158
163
|
return (
|
|
159
164
|
f"cd {self._simtel_path.joinpath('sim_telarray')} && {command}",
|
|
160
165
|
self._file_simtel,
|
|
@@ -9,6 +9,7 @@ import numpy as np
|
|
|
9
9
|
|
|
10
10
|
from simtools.io_operations import io_handler
|
|
11
11
|
from simtools.runners.simtel_runner import SimtelRunner
|
|
12
|
+
from simtools.utils.general import clear_default_sim_telarray_cfg_directories
|
|
12
13
|
|
|
13
14
|
__all__ = ["SimulatorLightEmission"]
|
|
14
15
|
|
|
@@ -360,7 +361,8 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
360
361
|
f"{self.le_application[0]}_{self.le_application[1]}.ctsim.hdata\n",
|
|
361
362
|
)
|
|
362
363
|
|
|
363
|
-
|
|
364
|
+
# Remove the default sim_telarray configuration directories
|
|
365
|
+
return clear_default_sim_telarray_cfg_directories(command)
|
|
364
366
|
|
|
365
367
|
def _remove_line_from_config(self, file_path, line_prefix):
|
|
366
368
|
"""
|
|
@@ -8,6 +8,7 @@ import astropy.units as u
|
|
|
8
8
|
from simtools.io_operations import io_handler
|
|
9
9
|
from simtools.runners.simtel_runner import SimtelRunner
|
|
10
10
|
from simtools.utils import names
|
|
11
|
+
from simtools.utils.general import clear_default_sim_telarray_cfg_directories
|
|
11
12
|
|
|
12
13
|
__all__ = ["SimulatorRayTracing"]
|
|
13
14
|
|
|
@@ -192,7 +193,7 @@ class SimulatorRayTracing(SimtelRunner):
|
|
|
192
193
|
command += super().get_config_option("mirror_align_random_vertical", "0.,28.,0.,0.")
|
|
193
194
|
command += " " + str(self._corsika_file)
|
|
194
195
|
|
|
195
|
-
return command, self._log_file, self._log_file
|
|
196
|
+
return clear_default_sim_telarray_cfg_directories(command), self._log_file, self._log_file
|
|
196
197
|
|
|
197
198
|
def _check_run_result(self, run_number=None): # pylint: disable=unused-argument
|
|
198
199
|
"""
|
simtools/testing/helpers.py
CHANGED
|
@@ -6,19 +6,12 @@ from pathlib import Path
|
|
|
6
6
|
|
|
7
7
|
def skip_camera_efficiency(config):
|
|
8
8
|
"""Skip camera efficiency tests if the old version of testeff is used."""
|
|
9
|
-
if "camera-efficiency" in config["APPLICATION"]:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
)
|
|
16
|
-
full_test_name = f"{config['APPLICATION']}_{config['TEST_NAME']}"
|
|
17
|
-
if "simtools-validate-camera-efficiency_SSTS" == full_test_name:
|
|
18
|
-
return (
|
|
19
|
-
"The test simtools-validate-camera-efficiency_SSTS is skipped "
|
|
20
|
-
"since the fake SST mirrors are not yet implemented (#1155)"
|
|
21
|
-
)
|
|
9
|
+
if "camera-efficiency" in config["APPLICATION"] and not _new_testeff_version():
|
|
10
|
+
return (
|
|
11
|
+
"Any applications calling the old version of testeff are skipped "
|
|
12
|
+
"due to a limitation of the old testeff not allowing to specify "
|
|
13
|
+
"the include directory. Please update your sim_telarray tarball."
|
|
14
|
+
)
|
|
22
15
|
return None
|
|
23
16
|
|
|
24
17
|
|
|
@@ -12,39 +12,22 @@ from simtools.testing import assertions
|
|
|
12
12
|
_logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def
|
|
16
|
-
"""
|
|
17
|
-
Validate test output for all integration tests.
|
|
18
|
-
|
|
19
|
-
Parameters
|
|
20
|
-
----------
|
|
21
|
-
config: dict
|
|
22
|
-
Integration test configuration dictionary.
|
|
23
|
-
request: request
|
|
24
|
-
Request object.
|
|
25
|
-
config_file_model_version: str
|
|
26
|
-
Model version from the configuration file.
|
|
27
|
-
|
|
28
|
-
"""
|
|
29
|
-
if request.config.getoption("--model_version") is None:
|
|
30
|
-
validate_application_output(config)
|
|
31
|
-
elif config_file_model_version is not None:
|
|
32
|
-
_from_command_line = request.config.getoption("--model_version")
|
|
33
|
-
_from_config_file = config_file_model_version
|
|
34
|
-
if _from_command_line == _from_config_file:
|
|
35
|
-
validate_application_output(config)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def validate_application_output(config):
|
|
15
|
+
def validate_application_output(config, from_command_line=None, from_config_file=None):
|
|
39
16
|
"""
|
|
40
17
|
Validate application output against expected output.
|
|
41
18
|
|
|
42
19
|
Expected output is defined in configuration file.
|
|
20
|
+
Some tests run only if the model version from the command line
|
|
21
|
+
equals the model version from the configuration file.
|
|
43
22
|
|
|
44
23
|
Parameters
|
|
45
24
|
----------
|
|
46
25
|
config: dict
|
|
47
26
|
dictionary with the configuration for the application test.
|
|
27
|
+
from_command_line: str
|
|
28
|
+
Model version from the command line.
|
|
29
|
+
from_config_file: str
|
|
30
|
+
Model version from the configuration file.
|
|
48
31
|
|
|
49
32
|
"""
|
|
50
33
|
if "INTEGRATION_TESTS" not in config:
|
|
@@ -52,24 +35,37 @@ def validate_application_output(config):
|
|
|
52
35
|
|
|
53
36
|
for integration_test in config["INTEGRATION_TESTS"]:
|
|
54
37
|
_logger.info(f"Testing application output: {integration_test}")
|
|
55
|
-
if "REFERENCE_OUTPUT_FILE" in integration_test:
|
|
56
|
-
_validate_reference_output_file(config, integration_test)
|
|
57
|
-
|
|
58
|
-
if "TEST_OUTPUT_FILES" in integration_test:
|
|
59
|
-
_validate_output_path_and_file(config, integration_test["TEST_OUTPUT_FILES"])
|
|
60
|
-
if "OUTPUT_FILE" in integration_test:
|
|
61
|
-
_validate_output_path_and_file(
|
|
62
|
-
config,
|
|
63
|
-
[{"PATH_DESCRIPTOR": "OUTPUT_PATH", "FILE": integration_test["OUTPUT_FILE"]}],
|
|
64
|
-
)
|
|
65
38
|
|
|
66
|
-
if
|
|
67
|
-
|
|
68
|
-
integration_test
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)
|
|
72
|
-
|
|
39
|
+
if from_command_line == from_config_file:
|
|
40
|
+
if "REFERENCE_OUTPUT_FILE" in integration_test:
|
|
41
|
+
_validate_reference_output_file(config, integration_test)
|
|
42
|
+
|
|
43
|
+
if "TEST_OUTPUT_FILES" in integration_test:
|
|
44
|
+
_validate_output_path_and_file(config, integration_test["TEST_OUTPUT_FILES"])
|
|
45
|
+
|
|
46
|
+
if "OUTPUT_FILE" in integration_test:
|
|
47
|
+
_validate_output_path_and_file(
|
|
48
|
+
config,
|
|
49
|
+
[{"PATH_DESCRIPTOR": "OUTPUT_PATH", "FILE": integration_test["OUTPUT_FILE"]}],
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if "FILE_TYPE" in integration_test:
|
|
53
|
+
assert assertions.assert_file_type(
|
|
54
|
+
integration_test["FILE_TYPE"],
|
|
55
|
+
Path(config["CONFIGURATION"]["OUTPUT_PATH"]).joinpath(
|
|
56
|
+
config["CONFIGURATION"]["OUTPUT_FILE"]
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
_test_simtel_cfg_files(config, integration_test, from_command_line, from_config_file)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _test_simtel_cfg_files(config, integration_test, from_command_line, from_config_file):
|
|
63
|
+
"""Test simtel cfg files."""
|
|
64
|
+
test_simtel_cfg_file = integration_test.get("TEST_SIMTEL_CFG_FILES", {}).get(
|
|
65
|
+
from_command_line or from_config_file
|
|
66
|
+
)
|
|
67
|
+
if test_simtel_cfg_file:
|
|
68
|
+
_validate_simtel_cfg_files(config, test_simtel_cfg_file)
|
|
73
69
|
|
|
74
70
|
|
|
75
71
|
def _validate_reference_output_file(config, integration_test):
|
|
@@ -128,12 +124,13 @@ def compare_files(file1, file2, tolerance=1.0e-5, test_columns=None):
|
|
|
128
124
|
"""
|
|
129
125
|
_file1_suffix = Path(file1).suffix
|
|
130
126
|
_file2_suffix = Path(file2).suffix
|
|
127
|
+
_logger.info("Comparing files: %s and %s", file1, file2)
|
|
131
128
|
if _file1_suffix != _file2_suffix:
|
|
132
129
|
raise ValueError(f"File suffixes do not match: {file1} and {file2}")
|
|
133
130
|
if _file1_suffix == ".ecsv":
|
|
134
131
|
return compare_ecsv_files(file1, file2, tolerance, test_columns)
|
|
135
132
|
if _file1_suffix in (".json", ".yaml", ".yml"):
|
|
136
|
-
return compare_json_or_yaml_files(file1, file2)
|
|
133
|
+
return compare_json_or_yaml_files(file1, file2, tolerance)
|
|
137
134
|
|
|
138
135
|
_logger.warning(f"Unknown file type for files: {file1} and {file2}")
|
|
139
136
|
return False
|
|
@@ -168,11 +165,35 @@ def compare_json_or_yaml_files(file1, file2, tolerance=1.0e-2):
|
|
|
168
165
|
if data1 == data2:
|
|
169
166
|
return True
|
|
170
167
|
|
|
171
|
-
if
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
168
|
+
if data1.keys() != data2.keys():
|
|
169
|
+
_logger.error(f"Keys do not match: {data1.keys()} and {data2.keys()}")
|
|
170
|
+
return False
|
|
171
|
+
_comparison = all(
|
|
172
|
+
(
|
|
173
|
+
_compare_value_from_parameter_dict(data1[k], data2[k], tolerance)
|
|
174
|
+
if k == "value"
|
|
175
|
+
else data1[k] == data2[k]
|
|
176
|
+
)
|
|
177
|
+
for k in data1
|
|
178
|
+
)
|
|
179
|
+
if not _comparison:
|
|
180
|
+
_logger.error(f"Values do not match: {data1} and {data2} (tolerance: {tolerance})")
|
|
181
|
+
return _comparison
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _compare_value_from_parameter_dict(data1, data2, tolerance):
|
|
185
|
+
"""Compare value fields given in different formats."""
|
|
186
|
+
|
|
187
|
+
def _as_list(value):
|
|
188
|
+
if isinstance(value, str):
|
|
189
|
+
return gen.convert_string_to_list(value)
|
|
190
|
+
if isinstance(value, list | np.ndarray):
|
|
191
|
+
return value
|
|
192
|
+
return [value]
|
|
193
|
+
|
|
194
|
+
_logger.info(f"Comparing values: {data1} and {data2} (tolerance: {tolerance})")
|
|
195
|
+
|
|
196
|
+
return np.allclose(_as_list(data1), _as_list(data2), rtol=tolerance)
|
|
176
197
|
|
|
177
198
|
|
|
178
199
|
def compare_ecsv_files(file1, file2, tolerance=1.0e-5, test_columns=None):
|
|
@@ -238,3 +259,66 @@ def compare_ecsv_files(file1, file2, tolerance=1.0e-5, test_columns=None):
|
|
|
238
259
|
return False
|
|
239
260
|
|
|
240
261
|
return True
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _validate_simtel_cfg_files(config, simtel_cfg_file):
|
|
265
|
+
"""
|
|
266
|
+
Check sim_telarray configuration files and compare with reference file.
|
|
267
|
+
|
|
268
|
+
Note the finetuned naming of configuration files by simtools.
|
|
269
|
+
|
|
270
|
+
"""
|
|
271
|
+
reference_file = Path(simtel_cfg_file)
|
|
272
|
+
test_file = Path(config["CONFIGURATION"]["OUTPUT_PATH"]) / reference_file.name.replace(
|
|
273
|
+
"_test", f"_{config['CONFIGURATION']['LABEL']}"
|
|
274
|
+
)
|
|
275
|
+
_logger.info(
|
|
276
|
+
f"Comparing simtel cfg files: {reference_file} and {test_file} "
|
|
277
|
+
f"for model version {config['CONFIGURATION']['MODEL_VERSION']}"
|
|
278
|
+
)
|
|
279
|
+
return _compare_simtel_cfg_files(reference_file, test_file)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _compare_simtel_cfg_files(reference_file, test_file):
|
|
283
|
+
"""
|
|
284
|
+
Compare two sim_telarray configuration files.
|
|
285
|
+
|
|
286
|
+
Line-by-line string comparison. Requires similar sequence of
|
|
287
|
+
parameters in the files. Ignore lines containing 'config_release'
|
|
288
|
+
(as it contains the simtools package version).
|
|
289
|
+
|
|
290
|
+
Parameters
|
|
291
|
+
----------
|
|
292
|
+
reference_file: Path
|
|
293
|
+
Reference sim_telarray configuration file.
|
|
294
|
+
test_file: Path
|
|
295
|
+
Test sim_telarray configuration file.
|
|
296
|
+
|
|
297
|
+
Returns
|
|
298
|
+
-------
|
|
299
|
+
bool
|
|
300
|
+
True if the files are equal.
|
|
301
|
+
|
|
302
|
+
"""
|
|
303
|
+
with open(reference_file, encoding="utf-8") as f1, open(test_file, encoding="utf-8") as f2:
|
|
304
|
+
reference_cfg = [line.rstrip() for line in f1 if line.strip()]
|
|
305
|
+
test_cfg = [line.rstrip() for line in f2 if line.strip()]
|
|
306
|
+
|
|
307
|
+
if len(reference_cfg) != len(test_cfg):
|
|
308
|
+
_logger.error(
|
|
309
|
+
f"Line counts differ: {reference_file} ({len(reference_cfg)} lines), "
|
|
310
|
+
f"{test_file} ({len(test_cfg)} lines)."
|
|
311
|
+
)
|
|
312
|
+
return False
|
|
313
|
+
|
|
314
|
+
for ref_line, test_line in zip(reference_cfg, test_cfg):
|
|
315
|
+
if any(ignore in ref_line for ignore in ("config_release", "Label")):
|
|
316
|
+
continue
|
|
317
|
+
if ref_line != test_line:
|
|
318
|
+
_logger.error(
|
|
319
|
+
f"Configuration files {reference_file} and {test_file} do not match: "
|
|
320
|
+
f"'{ref_line}' and '{test_line}'"
|
|
321
|
+
)
|
|
322
|
+
return False
|
|
323
|
+
|
|
324
|
+
return True
|
simtools/utils/general.py
CHANGED
|
@@ -17,6 +17,7 @@ import yaml
|
|
|
17
17
|
__all__ = [
|
|
18
18
|
"InvalidConfigDataError",
|
|
19
19
|
"change_dict_keys_case",
|
|
20
|
+
"clear_default_sim_telarray_cfg_directories",
|
|
20
21
|
"collect_data_from_file",
|
|
21
22
|
"collect_final_lines",
|
|
22
23
|
"collect_kwargs",
|
|
@@ -81,6 +82,28 @@ def is_url(url):
|
|
|
81
82
|
return False
|
|
82
83
|
|
|
83
84
|
|
|
85
|
+
def url_exists(url):
|
|
86
|
+
"""
|
|
87
|
+
Check if a URL exists.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
url: str
|
|
92
|
+
URL to be checked.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
bool
|
|
97
|
+
True if URL exists.
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
with urllib.request.urlopen(url, timeout=5) as response:
|
|
101
|
+
return response.status == 200
|
|
102
|
+
except (urllib.error.URLError, AttributeError) as e:
|
|
103
|
+
_logger.error(f"URL {url} does not exist: {e}")
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
|
|
84
107
|
def collect_data_from_http(url):
|
|
85
108
|
"""
|
|
86
109
|
Download yaml or json file from url and return it contents as dict.
|
|
@@ -135,7 +158,7 @@ def collect_data_from_http(url):
|
|
|
135
158
|
return data
|
|
136
159
|
|
|
137
160
|
|
|
138
|
-
def collect_data_from_file(file_name):
|
|
161
|
+
def collect_data_from_file(file_name, yaml_document=None):
|
|
139
162
|
"""
|
|
140
163
|
Collect data from file based on its extension.
|
|
141
164
|
|
|
@@ -143,6 +166,8 @@ def collect_data_from_file(file_name):
|
|
|
143
166
|
----------
|
|
144
167
|
file_name: str
|
|
145
168
|
Name of the yaml/json/ascii file.
|
|
169
|
+
yaml_document: None, int
|
|
170
|
+
Return list of yaml documents or a single document (for yaml files with several documents).
|
|
146
171
|
|
|
147
172
|
Returns
|
|
148
173
|
-------
|
|
@@ -152,21 +177,34 @@ def collect_data_from_file(file_name):
|
|
|
152
177
|
if is_url(file_name):
|
|
153
178
|
return collect_data_from_http(file_name)
|
|
154
179
|
|
|
180
|
+
suffix = Path(file_name).suffix.lower()
|
|
155
181
|
with open(file_name, encoding="utf-8") as file:
|
|
156
|
-
if
|
|
182
|
+
if suffix == ".json":
|
|
157
183
|
return json.load(file)
|
|
184
|
+
if suffix == ".list":
|
|
185
|
+
return [line.strip() for line in file.readlines()]
|
|
186
|
+
if suffix in [".yml", ".yaml"]:
|
|
187
|
+
return _collect_data_from_yaml_file(file, file_name, yaml_document)
|
|
188
|
+
return None
|
|
158
189
|
|
|
159
|
-
if Path(file_name).suffix.lower() == ".list":
|
|
160
|
-
lines = file.readlines()
|
|
161
|
-
return [line.strip() for line in lines]
|
|
162
190
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
191
|
+
def _collect_data_from_yaml_file(file, file_name, yaml_document):
|
|
192
|
+
"""Collect data from a yaml file."""
|
|
193
|
+
try:
|
|
194
|
+
return yaml.safe_load(file)
|
|
195
|
+
except yaml.constructor.ConstructorError:
|
|
196
|
+
return _load_yaml_using_astropy(file)
|
|
197
|
+
except yaml.composer.ComposerError:
|
|
198
|
+
pass
|
|
199
|
+
file.seek(0)
|
|
200
|
+
if yaml_document is None:
|
|
201
|
+
return list(yaml.safe_load_all(file))
|
|
202
|
+
try:
|
|
203
|
+
return list(yaml.safe_load_all(file))[yaml_document]
|
|
204
|
+
except IndexError as exc:
|
|
205
|
+
raise InvalidConfigDataError(
|
|
206
|
+
f"YAML file {file_name} does not contain {yaml_document} documents."
|
|
207
|
+
) from exc
|
|
170
208
|
|
|
171
209
|
|
|
172
210
|
def collect_kwargs(label, in_kwargs):
|
|
@@ -832,3 +870,55 @@ def convert_keys_in_dict_to_lowercase(data):
|
|
|
832
870
|
if isinstance(data, list):
|
|
833
871
|
return [convert_keys_in_dict_to_lowercase(i) for i in data]
|
|
834
872
|
return data
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
def clear_default_sim_telarray_cfg_directories(command):
|
|
876
|
+
"""Prefix the command to clear default sim_telarray configuration directories.
|
|
877
|
+
|
|
878
|
+
Parameters
|
|
879
|
+
----------
|
|
880
|
+
command: str
|
|
881
|
+
Command to be prefixed.
|
|
882
|
+
|
|
883
|
+
Returns
|
|
884
|
+
-------
|
|
885
|
+
str
|
|
886
|
+
Prefixed command.
|
|
887
|
+
|
|
888
|
+
"""
|
|
889
|
+
return f"SIM_TELARRAY_CONFIG_PATH='' {command}"
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
def get_list_of_files_from_command_line(file_names, suffix_list):
|
|
893
|
+
"""
|
|
894
|
+
Get a list of files from the command line.
|
|
895
|
+
|
|
896
|
+
Files can be given as a list of file names or as a text file containing the list of files.
|
|
897
|
+
The list of suffixes restrict the files types to be returned. Note that a file list must
|
|
898
|
+
have a different suffix than those in the suffix list.
|
|
899
|
+
|
|
900
|
+
Parameters
|
|
901
|
+
----------
|
|
902
|
+
file_names: list
|
|
903
|
+
List of file names to be checked.
|
|
904
|
+
suffix_list: list
|
|
905
|
+
List of suffixes to be checked.
|
|
906
|
+
|
|
907
|
+
Returns
|
|
908
|
+
-------
|
|
909
|
+
list
|
|
910
|
+
List of files with the given suffixes.
|
|
911
|
+
"""
|
|
912
|
+
_files = []
|
|
913
|
+
for one_file in file_names:
|
|
914
|
+
path = Path(one_file)
|
|
915
|
+
try:
|
|
916
|
+
if path.suffix in suffix_list:
|
|
917
|
+
_files.append(one_file)
|
|
918
|
+
elif len(file_names) == 1:
|
|
919
|
+
with open(one_file, encoding="utf-8") as file:
|
|
920
|
+
_files.extend(line.strip() for line in file)
|
|
921
|
+
except FileNotFoundError as exc:
|
|
922
|
+
_logger.error(f"{one_file} is not a file.")
|
|
923
|
+
raise FileNotFoundError from exc
|
|
924
|
+
return _files
|