gammasimtools 0.25.0__py3-none-any.whl → 0.27.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.25.0.dist-info → gammasimtools-0.27.0.dist-info}/METADATA +6 -1
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/RECORD +135 -130
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/entry_points.txt +3 -2
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/licenses/LICENSE +1 -1
- simtools/_version.py +2 -2
- simtools/application_control.py +35 -7
- simtools/applications/convert_geo_coordinates_of_array_elements.py +3 -3
- simtools/applications/db_add_file_to_db.py +1 -1
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +1 -1
- simtools/applications/db_add_value_from_json_to_db.py +1 -1
- simtools/applications/db_generate_compound_indexes.py +1 -1
- simtools/applications/db_get_array_layouts_from_db.py +3 -7
- simtools/applications/db_get_file_from_db.py +1 -1
- simtools/applications/db_get_parameter_from_db.py +1 -1
- simtools/applications/db_inspect_databases.py +1 -1
- simtools/applications/db_upload_model_repository.py +1 -1
- simtools/applications/derive_ctao_array_layouts.py +1 -2
- simtools/applications/{calculate_incident_angles.py → derive_incident_angle.py} +16 -18
- simtools/applications/derive_mirror_rnda.py +112 -180
- simtools/applications/derive_psf_parameters.py +0 -1
- simtools/applications/derive_pulse_shape_parameters.py +0 -1
- simtools/applications/derive_trigger_rates.py +1 -1
- simtools/applications/docs_produce_array_element_report.py +2 -8
- simtools/applications/docs_produce_calibration_reports.py +1 -3
- simtools/applications/docs_produce_model_parameter_reports.py +0 -2
- simtools/applications/docs_produce_simulation_configuration_report.py +1 -3
- simtools/applications/generate_array_config.py +0 -1
- simtools/applications/generate_corsika_histograms.py +79 -229
- simtools/applications/generate_regular_arrays.py +76 -69
- simtools/applications/generate_simtel_event_data.py +2 -2
- simtools/applications/maintain_simulation_model_add_production.py +2 -2
- simtools/applications/maintain_simulation_model_write_array_element_positions.py +87 -0
- simtools/applications/plot_array_layout.py +5 -111
- simtools/applications/plot_simulated_event_distributions.py +57 -0
- simtools/applications/plot_tabular_data.py +0 -1
- simtools/applications/plot_tabular_data_for_model_parameter.py +1 -6
- simtools/applications/production_derive_corsika_limits.py +1 -1
- simtools/applications/production_generate_grid.py +0 -1
- simtools/applications/run_application.py +1 -1
- simtools/applications/simulate_flasher.py +3 -15
- simtools/applications/simulate_illuminator.py +2 -11
- simtools/applications/simulate_pedestals.py +1 -5
- simtools/applications/simulate_prod.py +8 -11
- simtools/applications/simulate_prod_htcondor_generator.py +1 -1
- simtools/applications/submit_array_layouts.py +2 -4
- simtools/applications/submit_data_from_external.py +2 -1
- simtools/applications/submit_model_parameter_from_external.py +1 -3
- simtools/applications/validate_camera_efficiency.py +28 -28
- simtools/applications/validate_camera_fov.py +0 -1
- simtools/applications/validate_cumulative_psf.py +1 -5
- simtools/applications/validate_optics.py +2 -14
- simtools/atmosphere.py +83 -0
- simtools/camera/camera_efficiency.py +171 -53
- simtools/camera/single_photon_electron_spectrum.py +8 -7
- simtools/configuration/commandline_parser.py +82 -11
- simtools/configuration/configurator.py +6 -11
- simtools/constants.py +5 -0
- simtools/corsika/corsika_config.py +100 -202
- simtools/corsika/corsika_histograms.py +561 -1708
- simtools/corsika/primary_particle.py +1 -1
- simtools/data_model/metadata_collector.py +5 -2
- simtools/data_model/metadata_model.py +0 -4
- simtools/data_model/model_data_writer.py +59 -64
- simtools/data_model/schema.py +2 -0
- simtools/data_model/validate_data.py +1 -3
- simtools/db/db_handler.py +23 -10
- simtools/db/mongo_db.py +2 -2
- simtools/dependencies.py +81 -38
- simtools/io/ascii_handler.py +55 -5
- simtools/io/io_handler.py +23 -12
- simtools/io/table_handler.py +1 -1
- simtools/job_execution/job_manager.py +154 -79
- simtools/job_execution/process_pool.py +137 -0
- simtools/layout/array_layout.py +4 -13
- simtools/layout/array_layout_utils.py +348 -57
- simtools/model/array_model.py +23 -63
- simtools/model/calibration_model.py +4 -8
- simtools/model/legacy_model_parameter.py +134 -0
- simtools/model/model_parameter.py +147 -86
- simtools/model/model_utils.py +40 -6
- simtools/model/site_model.py +4 -8
- simtools/model/telescope_model.py +10 -16
- simtools/production_configuration/derive_corsika_limits.py +6 -11
- simtools/production_configuration/interpolation_handler.py +16 -16
- simtools/ray_tracing/incident_angles.py +92 -17
- simtools/ray_tracing/mirror_panel_psf.py +338 -222
- simtools/ray_tracing/psf_analysis.py +62 -48
- simtools/ray_tracing/psf_parameter_optimisation.py +3 -3
- simtools/ray_tracing/ray_tracing.py +43 -25
- simtools/reporting/docs_auto_report_generator.py +8 -13
- simtools/reporting/docs_read_parameters.py +2 -8
- simtools/runners/corsika_runner.py +52 -195
- simtools/runners/corsika_simtel_runner.py +77 -108
- simtools/runners/runner_services.py +214 -213
- simtools/runners/simtel_runner.py +27 -160
- simtools/runners/simtools_runner.py +11 -73
- simtools/schemas/application_workflow.metaschema.yml +8 -0
- simtools/settings.py +173 -0
- simtools/{io/eventio_handler.py → sim_events/file_info.py} +3 -3
- simtools/{simtel/simtel_io_event_histograms.py → sim_events/histograms.py} +25 -15
- simtools/{simtel/simtel_io_event_reader.py → sim_events/reader.py} +20 -17
- simtools/{simtel/simtel_io_event_writer.py → sim_events/writer.py} +84 -25
- simtools/simtel/pulse_shapes.py +7 -2
- simtools/simtel/simtel_config_writer.py +79 -91
- simtools/simtel/simtel_seeds.py +184 -0
- simtools/simtel/simtel_table_reader.py +6 -4
- simtools/simtel/simulator_array.py +114 -109
- simtools/simtel/simulator_camera_efficiency.py +68 -46
- simtools/simtel/simulator_light_emission.py +164 -132
- simtools/simtel/simulator_ray_tracing.py +80 -71
- simtools/simulator.py +137 -355
- simtools/telescope_trigger_rates.py +3 -4
- simtools/testing/assertions.py +84 -33
- simtools/testing/configuration.py +1 -2
- simtools/testing/helpers.py +2 -3
- simtools/testing/log_inspector.py +1 -0
- simtools/testing/sim_telarray_metadata.py +14 -12
- simtools/testing/validate_output.py +121 -42
- simtools/utils/general.py +43 -17
- simtools/utils/geometry.py +0 -77
- simtools/utils/names.py +5 -5
- simtools/utils/random.py +36 -0
- simtools/visualization/legend_handlers.py +7 -6
- simtools/visualization/plot_array_layout.py +91 -16
- simtools/visualization/plot_corsika_histograms.py +145 -605
- simtools/visualization/plot_incident_angles.py +48 -1
- simtools/visualization/plot_mirrors.py +1 -4
- simtools/visualization/plot_pixels.py +2 -4
- simtools/visualization/plot_psf.py +160 -19
- simtools/visualization/plot_simtel_event_histograms.py +4 -4
- simtools/visualization/plot_simtel_events.py +6 -11
- simtools/visualization/plot_tables.py +8 -19
- simtools/visualization/visualize.py +22 -2
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +0 -160
- simtools/applications/print_version.py +0 -53
- simtools/io/hdf5_handler.py +0 -139
- {gammasimtools-0.25.0.dist-info → gammasimtools-0.27.0.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
"""Base class for running sim_telarray simulations."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import subprocess
|
|
5
|
-
from pathlib import Path
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
from simtools.job_execution import job_manager
|
|
8
6
|
from simtools.runners.runner_services import RunnerServices
|
|
9
7
|
|
|
8
|
+
SIM_TELARRAY_ENV = {
|
|
9
|
+
"SIM_TELARRAY_CONFIG_PATH": "",
|
|
10
|
+
}
|
|
10
11
|
|
|
11
|
-
class SimtelExecutionError(Exception):
|
|
12
|
-
"""Exception for sim_telarray execution error."""
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"""
|
|
13
|
+
def sim_telarray_env_as_string():
|
|
14
|
+
"""Return the sim_telarray environment variables as a string."""
|
|
15
|
+
return " ".join(f'{key}="{value}" ' for key, value in SIM_TELARRAY_ENV.items())
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
class SimtelRunner:
|
|
@@ -25,40 +24,26 @@ class SimtelRunner:
|
|
|
25
24
|
|
|
26
25
|
Parameters
|
|
27
26
|
----------
|
|
28
|
-
simtel_path: str or Path
|
|
29
|
-
Location of sim_telarray installation.
|
|
30
27
|
label: str
|
|
31
28
|
Instance label. Important for output file naming.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
calibration_run_mode: str
|
|
37
|
-
Calibration run mode.
|
|
29
|
+
config: CorsikaConfig or dict
|
|
30
|
+
Configuration parameters.
|
|
31
|
+
is_calibration_run: bool
|
|
32
|
+
Flag to indicate if this is a calibration run.
|
|
38
33
|
"""
|
|
39
34
|
|
|
40
|
-
def __init__(
|
|
41
|
-
self,
|
|
42
|
-
simtel_path,
|
|
43
|
-
label=None,
|
|
44
|
-
corsika_config=None,
|
|
45
|
-
use_multipipe=False,
|
|
46
|
-
calibration_run_mode=None,
|
|
47
|
-
):
|
|
35
|
+
def __init__(self, label=None, config=None, is_calibration_run=False):
|
|
48
36
|
"""Initialize SimtelRunner."""
|
|
49
37
|
self._logger = logging.getLogger(__name__)
|
|
50
38
|
|
|
51
|
-
self._simtel_path = Path(simtel_path)
|
|
52
39
|
self.label = label
|
|
53
40
|
self._base_directory = None
|
|
54
|
-
self.
|
|
41
|
+
self.is_calibration_run = is_calibration_run
|
|
55
42
|
|
|
56
43
|
self.runs_per_set = 1
|
|
57
44
|
|
|
58
|
-
self.runner_service = RunnerServices(
|
|
59
|
-
self.
|
|
60
|
-
"corsika_sim_telarray" if use_multipipe else "sim_telarray"
|
|
61
|
-
)
|
|
45
|
+
self.runner_service = RunnerServices(config, run_type="sim_telarray", label=label)
|
|
46
|
+
self.file_list = None
|
|
62
47
|
|
|
63
48
|
def run(self, test=False, input_file=None, run_number=None):
|
|
64
49
|
"""
|
|
@@ -75,142 +60,24 @@ class SimtelRunner:
|
|
|
75
60
|
"""
|
|
76
61
|
self._logger.debug("Running sim_telarray")
|
|
77
62
|
|
|
78
|
-
command, stdout_file, stderr_file = self.
|
|
63
|
+
command, stdout_file, stderr_file = self.make_run_command(
|
|
79
64
|
run_number=run_number, input_file=input_file
|
|
80
65
|
)
|
|
81
|
-
|
|
82
|
-
if test
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
self._logger.debug(f"Running ({self.runs_per_set}x) with command: {command}")
|
|
87
|
-
for _ in range(self.runs_per_set):
|
|
88
|
-
self._run_simtel_and_check_output(command, stdout_file, stderr_file)
|
|
89
|
-
|
|
90
|
-
self._check_run_result(run_number=run_number)
|
|
91
|
-
|
|
92
|
-
def _check_run_result(self, run_number=None): # pylint: disable=all
|
|
93
|
-
"""Check if simtel output file exists."""
|
|
94
|
-
pass
|
|
95
|
-
|
|
96
|
-
def _raise_simtel_error(self):
|
|
97
|
-
"""
|
|
98
|
-
Raise sim_telarray execution error.
|
|
99
|
-
|
|
100
|
-
Final 30 lines from the log file are collected and printed.
|
|
101
|
-
|
|
102
|
-
Raises
|
|
103
|
-
------
|
|
104
|
-
SimtelExecutionError
|
|
105
|
-
"""
|
|
106
|
-
if hasattr(self, "_log_file"):
|
|
107
|
-
msg = gen.get_log_excerpt(self._log_file)
|
|
108
|
-
else:
|
|
109
|
-
msg = "Simtel log file does not exist."
|
|
110
|
-
raise SimtelExecutionError(msg)
|
|
111
|
-
|
|
112
|
-
def _run_simtel_and_check_output(self, command, stdout_file, stderr_file):
|
|
113
|
-
"""
|
|
114
|
-
Run the sim_telarray command and check the exit code.
|
|
115
|
-
|
|
116
|
-
Raises
|
|
117
|
-
------
|
|
118
|
-
SimtelExecutionError
|
|
119
|
-
if run was not successful.
|
|
120
|
-
"""
|
|
121
|
-
stdout_file = stdout_file if stdout_file else "/dev/null"
|
|
122
|
-
stderr_file = stderr_file if stderr_file else "/dev/null"
|
|
123
|
-
with (
|
|
124
|
-
open(f"{stdout_file}", "w", encoding="utf-8") as stdout,
|
|
125
|
-
open(f"{stderr_file}", "w", encoding="utf-8") as stderr,
|
|
126
|
-
):
|
|
127
|
-
result = subprocess.run(
|
|
66
|
+
runs = 1 if test else self.runs_per_set
|
|
67
|
+
label = "test" if test else f"{self.runs_per_set}x"
|
|
68
|
+
self._logger.info(f"Running ({label}) with command: {command}")
|
|
69
|
+
for _ in range(runs):
|
|
70
|
+
job_manager.submit(
|
|
128
71
|
command,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
stderr=stderr,
|
|
72
|
+
out_file=stdout_file,
|
|
73
|
+
err_file=stderr_file,
|
|
74
|
+
env=SIM_TELARRAY_ENV,
|
|
133
75
|
)
|
|
134
76
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return result.returncode
|
|
139
|
-
|
|
140
|
-
def _make_run_command(self, run_number=None, input_file=None):
|
|
141
|
-
self._logger.debug(
|
|
142
|
-
"make_run_command is being called from the base class - "
|
|
143
|
-
"it should be implemented in the sub class"
|
|
144
|
-
)
|
|
145
|
-
input_file = input_file if input_file else "nofile"
|
|
146
|
-
run_number = run_number if run_number else 1
|
|
147
|
-
return f"{input_file}-{run_number}", None, None
|
|
148
|
-
|
|
149
|
-
@staticmethod
|
|
150
|
-
def get_config_option(par, value=None, weak_option=False):
|
|
151
|
-
"""
|
|
152
|
-
Build sim_telarray command.
|
|
153
|
-
|
|
154
|
-
Parameters
|
|
155
|
-
----------
|
|
156
|
-
par: str
|
|
157
|
-
Parameter name.
|
|
158
|
-
value: str
|
|
159
|
-
Parameter value.
|
|
160
|
-
weak_option: bool
|
|
161
|
-
If True, use -W option instead of -C.
|
|
162
|
-
|
|
163
|
-
Returns
|
|
164
|
-
-------
|
|
165
|
-
str
|
|
166
|
-
Command for sim_telarray.
|
|
167
|
-
"""
|
|
168
|
-
option_syntax = "-W" if weak_option else "-C"
|
|
169
|
-
c = f" {option_syntax} {par}"
|
|
170
|
-
c += f"={value}" if value is not None else ""
|
|
171
|
-
return c
|
|
77
|
+
def make_run_command(self, run_number=None, input_file=None):
|
|
78
|
+
"""Make the sim_telarray run command (to implemented in subclasses)."""
|
|
79
|
+
raise NotImplementedError("Must be implemented in concrete subclass")
|
|
172
80
|
|
|
173
81
|
def get_resources(self, run_number=None):
|
|
174
82
|
"""Return computing resources used."""
|
|
175
83
|
return self.runner_service.get_resources(run_number)
|
|
176
|
-
|
|
177
|
-
def get_file_name(
|
|
178
|
-
self,
|
|
179
|
-
simulation_software="sim_telarray",
|
|
180
|
-
file_type=None,
|
|
181
|
-
run_number=None,
|
|
182
|
-
mode="",
|
|
183
|
-
model_version_index=0,
|
|
184
|
-
):
|
|
185
|
-
"""
|
|
186
|
-
Get the full path of a file for a given run number.
|
|
187
|
-
|
|
188
|
-
Parameters
|
|
189
|
-
----------
|
|
190
|
-
simulation_software: str
|
|
191
|
-
Simulation software.
|
|
192
|
-
file_type: str
|
|
193
|
-
File type.
|
|
194
|
-
run_number: int
|
|
195
|
-
Run number.
|
|
196
|
-
model_version_index: int
|
|
197
|
-
Index of the model version.
|
|
198
|
-
This is used to select the correct simulator_array instance in case
|
|
199
|
-
multiple array models are simulated.
|
|
200
|
-
|
|
201
|
-
Returns
|
|
202
|
-
-------
|
|
203
|
-
str
|
|
204
|
-
File name with full path.
|
|
205
|
-
"""
|
|
206
|
-
if simulation_software.lower() != "sim_telarray":
|
|
207
|
-
raise ValueError(
|
|
208
|
-
f"simulation_software ({simulation_software}) is not supported in SimulatorArray"
|
|
209
|
-
)
|
|
210
|
-
return self.runner_service.get_file_name(
|
|
211
|
-
file_type=file_type,
|
|
212
|
-
run_number=run_number,
|
|
213
|
-
mode=mode,
|
|
214
|
-
_model_version_index=model_version_index,
|
|
215
|
-
calibration_run_mode=self.calibration_run_mode,
|
|
216
|
-
)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"""Tools for running applications in the simtools framework."""
|
|
2
2
|
|
|
3
3
|
import shutil
|
|
4
|
-
import subprocess
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
|
|
7
6
|
import simtools.utils.general as gen
|
|
8
7
|
from simtools import dependencies
|
|
9
8
|
from simtools.io import ascii_handler
|
|
9
|
+
from simtools.job_execution import job_manager
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def run_applications(args_dict,
|
|
12
|
+
def run_applications(args_dict, logger):
|
|
13
13
|
"""
|
|
14
14
|
Run simtools applications step-by-step as defined in a configuration file.
|
|
15
15
|
|
|
@@ -17,8 +17,6 @@ def run_applications(args_dict, db_config, logger):
|
|
|
17
17
|
----------
|
|
18
18
|
args_dict : dict
|
|
19
19
|
Dictionary containing command line arguments.
|
|
20
|
-
db_config : dict
|
|
21
|
-
Database configuration
|
|
22
20
|
logger : logging.Logger
|
|
23
21
|
Logger for logging application output.
|
|
24
22
|
"""
|
|
@@ -33,7 +31,7 @@ def run_applications(args_dict, db_config, logger):
|
|
|
33
31
|
|
|
34
32
|
with log_file.open("w", encoding="utf-8") as file:
|
|
35
33
|
file.write("Running simtools applications\n")
|
|
36
|
-
file.write(dependencies.get_version_string(
|
|
34
|
+
file.write(dependencies.get_version_string(run_time))
|
|
37
35
|
|
|
38
36
|
for config in configurations:
|
|
39
37
|
app = config.get("application")
|
|
@@ -41,75 +39,15 @@ def run_applications(args_dict, db_config, logger):
|
|
|
41
39
|
logger.info(f"Skipping application: {app}")
|
|
42
40
|
continue
|
|
43
41
|
logger.info(f"Running application: {app}")
|
|
44
|
-
|
|
42
|
+
result = job_manager.submit(
|
|
43
|
+
app,
|
|
44
|
+
out_file=None,
|
|
45
|
+
err_file=None,
|
|
46
|
+
configuration=config.get("configuration"),
|
|
47
|
+
runtime_environment=run_time,
|
|
48
|
+
)
|
|
45
49
|
file.write("=" * 80 + "\n")
|
|
46
|
-
file.write(f"Application: {app}\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n")
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def run_application(runtime_environment, application, configuration, logger):
|
|
50
|
-
"""
|
|
51
|
-
Run a simtools application and return stdout and stderr.
|
|
52
|
-
|
|
53
|
-
Allow to specify a runtime environment (e.g., Docker) and a working directory.
|
|
54
|
-
|
|
55
|
-
Parameters
|
|
56
|
-
----------
|
|
57
|
-
runtime_environment : list
|
|
58
|
-
Command to run the application in the specified runtime environment.
|
|
59
|
-
application : str
|
|
60
|
-
Name of the application to run.
|
|
61
|
-
configuration : dict
|
|
62
|
-
Configuration for the application.
|
|
63
|
-
logger : logging.Logger
|
|
64
|
-
Logger for logging application output.
|
|
65
|
-
|
|
66
|
-
Returns
|
|
67
|
-
-------
|
|
68
|
-
tuple
|
|
69
|
-
stdout and stderr from the application run.
|
|
70
|
-
|
|
71
|
-
"""
|
|
72
|
-
command = [application, *_convert_dict_to_args(configuration)]
|
|
73
|
-
if runtime_environment:
|
|
74
|
-
command = runtime_environment + command
|
|
75
|
-
try:
|
|
76
|
-
result = subprocess.run(
|
|
77
|
-
command,
|
|
78
|
-
check=True,
|
|
79
|
-
capture_output=True,
|
|
80
|
-
text=True,
|
|
81
|
-
)
|
|
82
|
-
except subprocess.CalledProcessError as exc:
|
|
83
|
-
logger.error(f"Error running application {application}: {exc.stderr}")
|
|
84
|
-
raise exc
|
|
85
|
-
|
|
86
|
-
return result.stdout, result.stderr
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def _convert_dict_to_args(parameters):
|
|
90
|
-
"""
|
|
91
|
-
Convert a dictionary of parameters to a list of command line arguments.
|
|
92
|
-
|
|
93
|
-
Parameters
|
|
94
|
-
----------
|
|
95
|
-
parameters : dict
|
|
96
|
-
Dictionary containing parameters to convert.
|
|
97
|
-
|
|
98
|
-
Returns
|
|
99
|
-
-------
|
|
100
|
-
list
|
|
101
|
-
List of command line arguments.
|
|
102
|
-
"""
|
|
103
|
-
args = []
|
|
104
|
-
for key, value in parameters.items():
|
|
105
|
-
if isinstance(value, bool):
|
|
106
|
-
if value:
|
|
107
|
-
args.append(f"--{key}")
|
|
108
|
-
elif isinstance(value, list):
|
|
109
|
-
args.extend([f"--{key}", *(str(item) for item in value)])
|
|
110
|
-
else:
|
|
111
|
-
args.extend([f"--{key}", str(value)])
|
|
112
|
-
return args
|
|
50
|
+
file.write(f"Application: {app}\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}\n")
|
|
113
51
|
|
|
114
52
|
|
|
115
53
|
def _read_application_configuration(configuration_file, steps, logger):
|
|
@@ -142,6 +142,10 @@ definitions:
|
|
|
142
142
|
description: |
|
|
143
143
|
"Allowed tolerance for floating point comparison."
|
|
144
144
|
type: number
|
|
145
|
+
scaling:
|
|
146
|
+
description: |
|
|
147
|
+
"Scaling factor to apply to the model parameter value before comparison."
|
|
148
|
+
type: number
|
|
145
149
|
test_simtel_cfg_files:
|
|
146
150
|
description: |
|
|
147
151
|
"Reference file used for comparison of sim_telarray configuration files."
|
|
@@ -152,6 +156,10 @@ definitions:
|
|
|
152
156
|
type: string
|
|
153
157
|
description: Path to the configuration file for the given version.
|
|
154
158
|
minProperties: 1
|
|
159
|
+
test_output_file:
|
|
160
|
+
description: |
|
|
161
|
+
"Output file generated by the integration test for comparison with the reference file."
|
|
162
|
+
type: string
|
|
155
163
|
tolerance:
|
|
156
164
|
description: "Allowed tolerance for floating point comparison."
|
|
157
165
|
type: number
|
simtools/settings.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Centralized settings object with command line and environment variables."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import socket
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from types import MappingProxyType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class _Config:
|
|
10
|
+
"""Centralized settings object with command line and environment variables."""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
"""Initialize empty config."""
|
|
14
|
+
self._args = {}
|
|
15
|
+
self._db_config = {}
|
|
16
|
+
self._sim_telarray_path = None
|
|
17
|
+
self._sim_telarray_exe = None
|
|
18
|
+
self._corsika_path = None
|
|
19
|
+
self._corsika_interaction_table_path = None
|
|
20
|
+
self._corsika_exe = None
|
|
21
|
+
self.user = os.getenv("USER", "unknown")
|
|
22
|
+
self.hostname = socket.gethostname()
|
|
23
|
+
|
|
24
|
+
def load(self, args=None, db_config=None):
|
|
25
|
+
"""
|
|
26
|
+
Load configuration from command line arguments and environment variables.
|
|
27
|
+
|
|
28
|
+
For paths, first check for environment variables, then command line arguments.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
args : dict, optional
|
|
33
|
+
Command line arguments.
|
|
34
|
+
db_config : dict, optional
|
|
35
|
+
Database configuration.
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
self._args = MappingProxyType(args) if args is not None else {}
|
|
39
|
+
self._db_config = MappingProxyType(db_config) if db_config is not None else {}
|
|
40
|
+
self._sim_telarray_path = (
|
|
41
|
+
args.get("sim_telarray_path")
|
|
42
|
+
if args is not None and "sim_telarray_path" in args
|
|
43
|
+
else os.getenv("SIMTOOLS_SIM_TELARRAY_PATH")
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
self._sim_telarray_exe = (
|
|
47
|
+
args.get("sim_telarray_executable")
|
|
48
|
+
if args is not None and "sim_telarray_executable" in args
|
|
49
|
+
else os.getenv("SIMTOOLS_SIM_TELARRAY_EXECUTABLE", "sim_telarray")
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
self._corsika_path = (
|
|
53
|
+
args.get("corsika_path")
|
|
54
|
+
if args is not None and "corsika_path" in args
|
|
55
|
+
else os.getenv("SIMTOOLS_CORSIKA_PATH")
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
self._corsika_interaction_table_path = (
|
|
59
|
+
args.get("corsika_interaction_table_path")
|
|
60
|
+
if args is not None and "corsika_interaction_table_path" in args
|
|
61
|
+
else os.getenv("SIMTOOLS_CORSIKA_INTERACTION_TABLE_PATH")
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
self._corsika_exe = self._get_corsika_exec() if self._corsika_path is not None else None
|
|
65
|
+
|
|
66
|
+
def _get_corsika_exec(self):
|
|
67
|
+
"""
|
|
68
|
+
Get the CORSIKA executable from environment variable or command line argument.
|
|
69
|
+
|
|
70
|
+
Build the executable name based on configured interaction models. Fall back to
|
|
71
|
+
legacy naming (simply "corsika") if models are not specified.
|
|
72
|
+
"""
|
|
73
|
+
he_model = (
|
|
74
|
+
self._args.get("corsika_he_interaction")
|
|
75
|
+
if self._args is not None and "corsika_he_interaction" in self._args
|
|
76
|
+
else os.getenv("SIMTOOLS_CORSIKA_HE_INTERACTION")
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
le_model = (
|
|
80
|
+
self._args.get("corsika_le_interaction")
|
|
81
|
+
if self._args is not None and "corsika_le_interaction" in self._args
|
|
82
|
+
else os.getenv("SIMTOOLS_CORSIKA_LE_INTERACTION")
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if he_model and le_model:
|
|
86
|
+
corsika_exe = self.corsika_path / f"corsika_{he_model}_{le_model}_flat"
|
|
87
|
+
if corsika_exe.exists():
|
|
88
|
+
return corsika_exe
|
|
89
|
+
|
|
90
|
+
# legacy naming
|
|
91
|
+
return self.corsika_path / "corsika"
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def args(self):
|
|
95
|
+
"""Command line arguments."""
|
|
96
|
+
return self._args
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def db_config(self):
|
|
100
|
+
"""Database configuration."""
|
|
101
|
+
return self._db_config
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def sim_telarray_path(self):
|
|
105
|
+
"""Path to the sim_telarray installation directory."""
|
|
106
|
+
return Path(self._sim_telarray_path) if self._sim_telarray_path is not None else None
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def sim_telarray_exe(self):
|
|
110
|
+
"""Path to the sim_telarray executable."""
|
|
111
|
+
return (
|
|
112
|
+
Path(self._sim_telarray_path) / "bin" / self._sim_telarray_exe
|
|
113
|
+
if self._sim_telarray_path is not None
|
|
114
|
+
else None
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def sim_telarray_exe_debug_trace(self):
|
|
119
|
+
"""Path to the debug trace version of the sim_telarray executable."""
|
|
120
|
+
return (
|
|
121
|
+
Path(self._sim_telarray_path) / "bin" / (self._sim_telarray_exe + "_debug_trace")
|
|
122
|
+
if self._sim_telarray_path is not None
|
|
123
|
+
else None
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def corsika_path(self):
|
|
128
|
+
"""Path to the CORSIKA installation directory."""
|
|
129
|
+
return Path(self._corsika_path) if self._corsika_path is not None else None
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def corsika_interaction_table_path(self):
|
|
133
|
+
"""Path to the CORSIKA interaction table directory."""
|
|
134
|
+
return (
|
|
135
|
+
Path(self._corsika_interaction_table_path)
|
|
136
|
+
if self._corsika_interaction_table_path is not None
|
|
137
|
+
else self.corsika_path
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def corsika_exe(self):
|
|
142
|
+
"""Path to the CORSIKA executable."""
|
|
143
|
+
return (
|
|
144
|
+
Path(self._corsika_path) / self._corsika_exe if self._corsika_path is not None else None
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def corsika_exe_curved(self):
|
|
149
|
+
"""Path to the curved version of the CORSIKA executable."""
|
|
150
|
+
if self._corsika_exe is None:
|
|
151
|
+
return None
|
|
152
|
+
corsika_curved = (
|
|
153
|
+
self._corsika_exe.name.replace("_flat", "_curved")
|
|
154
|
+
if "_flat" in self._corsika_exe.name
|
|
155
|
+
else self._corsika_exe.name + "-curved" # legacy naming convention
|
|
156
|
+
)
|
|
157
|
+
return Path(self._corsika_path) / corsika_curved if self._corsika_path is not None else None
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def corsika_dummy_file(self):
|
|
161
|
+
"""
|
|
162
|
+
Path to a dummy CORSIKA file required by sim_telarray for ray-tracing simulations.
|
|
163
|
+
|
|
164
|
+
This file does not need to exist; sim_telarray only requires a file path.
|
|
165
|
+
"""
|
|
166
|
+
return (
|
|
167
|
+
self.sim_telarray_path / "run9991.corsika.gz"
|
|
168
|
+
if self._sim_telarray_path is not None
|
|
169
|
+
else None
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
config = _Config()
|
|
@@ -24,7 +24,7 @@ def get_corsika_run_number(file):
|
|
|
24
24
|
int, None
|
|
25
25
|
CORSIKA run number. Returns None if not found.
|
|
26
26
|
"""
|
|
27
|
-
run_header =
|
|
27
|
+
run_header = get_combined_eventio_run_header(file)
|
|
28
28
|
if run_header and "run" in run_header:
|
|
29
29
|
return run_header["run"]
|
|
30
30
|
run_header, _ = get_corsika_run_and_event_headers(file)
|
|
@@ -34,9 +34,9 @@ def get_corsika_run_number(file):
|
|
|
34
34
|
return None
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def
|
|
37
|
+
def get_combined_eventio_run_header(sim_telarray_file):
|
|
38
38
|
"""
|
|
39
|
-
Return the CORSIKA run header information from an sim_telarray file.
|
|
39
|
+
Return the CORSIKA run header information from an eventio (sim_telarray) file.
|
|
40
40
|
|
|
41
41
|
Reads both RunHeader and MCRunHeader object from file and returns a merged dictionary.
|
|
42
42
|
Adds primary id from the first event.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Histograms for shower and triggered events."""
|
|
1
|
+
"""Histograms for shower and (if available) triggered events."""
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
4
|
import logging
|
|
@@ -6,12 +6,12 @@ import logging
|
|
|
6
6
|
import astropy.units as u
|
|
7
7
|
import numpy as np
|
|
8
8
|
|
|
9
|
-
from simtools.
|
|
9
|
+
from simtools.sim_events.reader import EventDataReader
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class
|
|
12
|
+
class EventDataHistograms:
|
|
13
13
|
"""
|
|
14
|
-
Generate and fill histograms for shower and triggered events.
|
|
14
|
+
Generate and fill histograms for shower and (if available) triggered events.
|
|
15
15
|
|
|
16
16
|
Event data is read from the reduced MC event data file.
|
|
17
17
|
Calculate cumulative and relative (efficiency) distributions.
|
|
@@ -35,7 +35,7 @@ class SimtelIOEventHistograms:
|
|
|
35
35
|
self.histograms = {}
|
|
36
36
|
self.file_info = {}
|
|
37
37
|
|
|
38
|
-
self.reader =
|
|
38
|
+
self.reader = EventDataReader(event_data_file, telescope_list=telescope_list)
|
|
39
39
|
|
|
40
40
|
def fill(self):
|
|
41
41
|
"""
|
|
@@ -63,12 +63,10 @@ class SimtelIOEventHistograms:
|
|
|
63
63
|
|
|
64
64
|
self.histograms = self._define_histograms(event_data, triggered_data, shower_data)
|
|
65
65
|
|
|
66
|
-
for
|
|
67
|
-
self._logger.debug(f"Filling histogram {name}")
|
|
66
|
+
for data in self.histograms.values():
|
|
68
67
|
self._fill_histogram_and_bin_edges(data)
|
|
69
68
|
|
|
70
69
|
self.print_summary()
|
|
71
|
-
|
|
72
70
|
self.calculate_efficiency_data()
|
|
73
71
|
self.calculate_cumulative_data()
|
|
74
72
|
|
|
@@ -202,11 +200,14 @@ class SimtelIOEventHistograms:
|
|
|
202
200
|
Adds to existing histogram if present, otherwise initializes it.
|
|
203
201
|
"""
|
|
204
202
|
if data["1d"]:
|
|
203
|
+
if data["event_data"] is None:
|
|
204
|
+
return
|
|
205
205
|
hist, _ = np.histogram(
|
|
206
|
-
getattr(data["event_data"], data["event_data_column"]),
|
|
207
|
-
bins=data["bin_edges"],
|
|
206
|
+
getattr(data["event_data"], data["event_data_column"]), bins=data["bin_edges"]
|
|
208
207
|
)
|
|
209
208
|
else:
|
|
209
|
+
if data["event_data"][0] is None or data["event_data"][1] is None:
|
|
210
|
+
return
|
|
210
211
|
hist, _, _ = np.histogram2d(
|
|
211
212
|
getattr(data["event_data"][0], data["event_data_column"][0]),
|
|
212
213
|
getattr(data["event_data"][1], data["event_data_column"][1]),
|
|
@@ -227,6 +228,8 @@ class SimtelIOEventHistograms:
|
|
|
227
228
|
dict
|
|
228
229
|
Dictionary containing the efficiency histograms.
|
|
229
230
|
"""
|
|
231
|
+
if not any(isinstance(ds, dict) and "TRIGGERS" in ds for ds in self.reader.data_sets):
|
|
232
|
+
return None
|
|
230
233
|
|
|
231
234
|
def calculate_efficiency(trig_hist, mc_hist):
|
|
232
235
|
with np.errstate(divide="ignore", invalid="ignore"):
|
|
@@ -295,11 +298,15 @@ class SimtelIOEventHistograms:
|
|
|
295
298
|
"""Return bins for the viewcone histogram."""
|
|
296
299
|
if "viewcone_bin_edges" in self.histograms:
|
|
297
300
|
return self.histograms["viewcone_bin_edges"]
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
|
|
302
|
+
viewcone_min = self.file_info.get("viewcone_min", 0.0 * u.deg).to("deg").value
|
|
303
|
+
viewcone_max = self.file_info.get("viewcone_max", 20.0 * u.deg).to("deg").value
|
|
304
|
+
|
|
305
|
+
# avoid zero-width bins
|
|
306
|
+
if viewcone_min == viewcone_max:
|
|
307
|
+
viewcone_max = viewcone_min + 0.5
|
|
308
|
+
|
|
309
|
+
return np.linspace(viewcone_min, viewcone_max, 100)
|
|
303
310
|
|
|
304
311
|
def calculate_cumulative_data(self):
|
|
305
312
|
"""
|
|
@@ -310,6 +317,9 @@ class SimtelIOEventHistograms:
|
|
|
310
317
|
dict
|
|
311
318
|
Dictionary containing the cumulative histograms.
|
|
312
319
|
"""
|
|
320
|
+
if not any(isinstance(ds, dict) and "TRIGGERS" in ds for ds in self.reader.data_sets):
|
|
321
|
+
return None
|
|
322
|
+
|
|
313
323
|
cumulative_data = {}
|
|
314
324
|
suffix = "_cumulative"
|
|
315
325
|
|