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
simtools/simulator.py
CHANGED
|
@@ -1,81 +1,65 @@
|
|
|
1
1
|
"""Simulator class for managing simulations of showers and array of telescopes."""
|
|
2
2
|
|
|
3
|
-
import gzip
|
|
4
3
|
import logging
|
|
5
|
-
import re
|
|
6
4
|
import shutil
|
|
7
|
-
from collections import defaultdict
|
|
8
5
|
from pathlib import Path
|
|
9
6
|
|
|
10
7
|
import numpy as np
|
|
11
8
|
from astropy import units as u
|
|
12
9
|
|
|
10
|
+
from simtools import settings
|
|
13
11
|
from simtools.corsika.corsika_config import CorsikaConfig
|
|
14
|
-
from simtools.io import
|
|
15
|
-
from simtools.job_execution
|
|
12
|
+
from simtools.io import io_handler, table_handler
|
|
13
|
+
from simtools.job_execution import job_manager
|
|
16
14
|
from simtools.model.array_model import ArrayModel
|
|
17
|
-
from simtools.runners
|
|
18
|
-
from simtools.
|
|
19
|
-
from simtools.simtel.simtel_io_event_writer import SimtelIOEventDataWriter
|
|
15
|
+
from simtools.runners import corsika_runner, corsika_simtel_runner, runner_services, simtel_runner
|
|
16
|
+
from simtools.sim_events import file_info, writer
|
|
20
17
|
from simtools.simtel.simulator_array import SimulatorArray
|
|
21
18
|
from simtools.testing.sim_telarray_metadata import assert_sim_telarray_metadata
|
|
22
|
-
from simtools.utils import general
|
|
23
|
-
from simtools.version import semver_to_int
|
|
19
|
+
from simtools.utils import general
|
|
24
20
|
|
|
25
21
|
|
|
26
22
|
class Simulator:
|
|
27
23
|
"""
|
|
28
|
-
|
|
24
|
+
Simulation of showers and of the array of telescopes.
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
Interface with the simulation software packages (e.g., CORSIKA or sim_telarray).
|
|
31
27
|
A single run is simulated per instance, possibly for multiple model versions.
|
|
32
28
|
|
|
33
|
-
The configuration is set as a dict corresponding to the command line configuration groups
|
|
34
|
-
(especially simulation_software, simulation_model, simulation_parameters).
|
|
35
|
-
|
|
36
29
|
Parameters
|
|
37
30
|
----------
|
|
38
|
-
args_dict : dict
|
|
39
|
-
Configuration dictionary
|
|
40
|
-
(includes simulation_software, simulation_model, simulation_parameters groups).
|
|
41
31
|
label: str
|
|
42
32
|
Instance label.
|
|
43
33
|
extra_commands: str or list of str
|
|
44
34
|
Extra commands to be added to the run script before the run command.
|
|
45
|
-
db_config: dict
|
|
46
|
-
Database configuration.
|
|
47
35
|
"""
|
|
48
36
|
|
|
49
|
-
def __init__(
|
|
50
|
-
self,
|
|
51
|
-
args_dict,
|
|
52
|
-
label=None,
|
|
53
|
-
extra_commands=None,
|
|
54
|
-
db_config=None,
|
|
55
|
-
):
|
|
37
|
+
def __init__(self, label=None, extra_commands=None):
|
|
56
38
|
"""Initialize Simulator class."""
|
|
57
39
|
self.logger = logging.getLogger(__name__)
|
|
58
40
|
self.label = label
|
|
59
41
|
|
|
60
|
-
self.
|
|
61
|
-
self.
|
|
62
|
-
self.site = self.args_dict.get("site", None)
|
|
63
|
-
self.model_version = self.args_dict.get("model_version", None)
|
|
42
|
+
self.site = settings.config.args.get("site", None)
|
|
43
|
+
self.model_version = settings.config.args.get("model_version", None)
|
|
64
44
|
|
|
65
|
-
self.simulation_software =
|
|
66
|
-
|
|
67
|
-
|
|
45
|
+
self.simulation_software = settings.config.args.get(
|
|
46
|
+
"simulation_software", "corsika_sim_telarray"
|
|
47
|
+
)
|
|
48
|
+
self.run_mode = settings.config.args.get("run_mode", None)
|
|
68
49
|
|
|
69
50
|
self.io_handler = io_handler.IOHandler()
|
|
70
51
|
|
|
71
|
-
self.run_number = None
|
|
72
|
-
self._results = defaultdict(list)
|
|
73
|
-
self._test = None
|
|
74
52
|
self._extra_commands = extra_commands
|
|
75
|
-
self.
|
|
76
|
-
|
|
53
|
+
self.run_number = self._initialize_from_tool_configuration()
|
|
54
|
+
|
|
77
55
|
self.array_models, self.corsika_configurations = self._initialize_array_models()
|
|
78
56
|
self._simulation_runner = self._initialize_simulation_runner()
|
|
57
|
+
self.runner_service = runner_services.RunnerServices(
|
|
58
|
+
self._get_first_corsika_config(),
|
|
59
|
+
"sub",
|
|
60
|
+
label,
|
|
61
|
+
)
|
|
62
|
+
self.file_list = self.runner_service.load_files(self.run_number)
|
|
79
63
|
|
|
80
64
|
@property
|
|
81
65
|
def simulation_software(self):
|
|
@@ -104,21 +88,13 @@ class Simulator:
|
|
|
104
88
|
|
|
105
89
|
def _initialize_from_tool_configuration(self):
|
|
106
90
|
"""Initialize simulator from tool configuration."""
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"seed": self.args_dict.get("sim_telarray_instrument_seeds"),
|
|
110
|
-
"random_instrument_instances": self.args_dict.get(
|
|
111
|
-
"sim_telarray_random_instrument_instances"
|
|
112
|
-
),
|
|
113
|
-
"seed_file_name": "sim_telarray_instrument_seeds.txt", # name only; no directory
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if self.args_dict.get("corsika_file"):
|
|
117
|
-
self.run_number = eventio_handler.get_corsika_run_number(self.args_dict["corsika_file"])
|
|
91
|
+
if settings.config.args.get("corsika_file"):
|
|
92
|
+
run_number = file_info.get_corsika_run_number(settings.config.args["corsika_file"])
|
|
118
93
|
else:
|
|
119
|
-
|
|
120
|
-
"
|
|
121
|
-
)
|
|
94
|
+
run_number = settings.config.args.get(
|
|
95
|
+
"run_number_offset", 0
|
|
96
|
+
) + settings.config.args.get("run_number", 1)
|
|
97
|
+
return runner_services.validate_corsika_run_number(run_number)
|
|
122
98
|
|
|
123
99
|
def _initialize_array_models(self):
|
|
124
100
|
"""
|
|
@@ -126,8 +102,8 @@ class Simulator:
|
|
|
126
102
|
|
|
127
103
|
Returns
|
|
128
104
|
-------
|
|
129
|
-
list
|
|
130
|
-
List of ArrayModel objects.
|
|
105
|
+
list, list
|
|
106
|
+
List of ArrayModel and CorsikaConfig objects.
|
|
131
107
|
"""
|
|
132
108
|
versions = general.ensure_iterable(self.model_version)
|
|
133
109
|
|
|
@@ -135,39 +111,19 @@ class Simulator:
|
|
|
135
111
|
corsika_configurations = []
|
|
136
112
|
|
|
137
113
|
for version in versions:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
calibration_device_types=self._get_calibration_device_types(self.run_mode),
|
|
146
|
-
overwrite_model_parameters=self.args_dict.get("overwrite_model_parameters"),
|
|
147
|
-
simtel_path=self.args_dict.get("simtel_path"),
|
|
148
|
-
)
|
|
114
|
+
model = ArrayModel(
|
|
115
|
+
label=self.label,
|
|
116
|
+
site=self.site,
|
|
117
|
+
layout_name=settings.config.args.get("array_layout_name"),
|
|
118
|
+
model_version=version,
|
|
119
|
+
calibration_device_types=self._get_calibration_device_types(self.run_mode),
|
|
120
|
+
overwrite_model_parameters=settings.config.args.get("overwrite_model_parameters"),
|
|
149
121
|
)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
db_config=self.db_config,
|
|
156
|
-
dummy_simulations=self._is_calibration_run(self.run_mode),
|
|
157
|
-
)
|
|
158
|
-
)
|
|
159
|
-
array_model[-1].sim_telarray_seeds = {
|
|
160
|
-
"seed": self._get_seed_for_random_instrument_instances(
|
|
161
|
-
self.sim_telarray_seeds["seed"],
|
|
162
|
-
version,
|
|
163
|
-
corsika_configurations[-1].zenith_angle,
|
|
164
|
-
corsika_configurations[-1].azimuth_angle,
|
|
165
|
-
),
|
|
166
|
-
"random_instrument_instances": self.sim_telarray_seeds[
|
|
167
|
-
"random_instrument_instances"
|
|
168
|
-
],
|
|
169
|
-
"seed_file_name": self.sim_telarray_seeds["seed_file_name"],
|
|
170
|
-
}
|
|
122
|
+
cfg = CorsikaConfig(array_model=model, label=self.label, run_number=self.run_number)
|
|
123
|
+
model.initialize_seeds(cfg.zenith_angle, cfg.azimuth_angle)
|
|
124
|
+
|
|
125
|
+
array_model.append(model)
|
|
126
|
+
corsika_configurations.append(cfg)
|
|
171
127
|
|
|
172
128
|
# 'corsika_sim_telarray' allows for multiple model versions (multipipe option)
|
|
173
129
|
corsika_configurations = (
|
|
@@ -178,42 +134,6 @@ class Simulator:
|
|
|
178
134
|
|
|
179
135
|
return array_model, corsika_configurations
|
|
180
136
|
|
|
181
|
-
def _get_seed_for_random_instrument_instances(
|
|
182
|
-
self, seed, model_version, zenith_angle, azimuth_angle
|
|
183
|
-
):
|
|
184
|
-
"""
|
|
185
|
-
Generate seed for random instances of the instrument.
|
|
186
|
-
|
|
187
|
-
Parameters
|
|
188
|
-
----------
|
|
189
|
-
seed : str
|
|
190
|
-
Seed string given through configuration.
|
|
191
|
-
model_version: str
|
|
192
|
-
Model version.
|
|
193
|
-
zenith_angle: float
|
|
194
|
-
Zenith angle of the observation (in degrees).
|
|
195
|
-
azimuth_angle: float
|
|
196
|
-
Azimuth angle of the observation (in degrees).
|
|
197
|
-
|
|
198
|
-
Returns
|
|
199
|
-
-------
|
|
200
|
-
int
|
|
201
|
-
Seed for random instances of the instrument.
|
|
202
|
-
"""
|
|
203
|
-
if seed:
|
|
204
|
-
return int(seed.split(",")[0].strip())
|
|
205
|
-
|
|
206
|
-
def key_index(key):
|
|
207
|
-
try:
|
|
208
|
-
return list(names.site_names()).index(key) + 1
|
|
209
|
-
except ValueError:
|
|
210
|
-
return 1
|
|
211
|
-
|
|
212
|
-
seed = semver_to_int(model_version) * 10000000
|
|
213
|
-
seed = seed + key_index(self.site) * 1000000
|
|
214
|
-
seed = seed + (int)(zenith_angle) * 1000
|
|
215
|
-
return seed + (int)(azimuth_angle)
|
|
216
|
-
|
|
217
137
|
def _initialize_simulation_runner(self):
|
|
218
138
|
"""
|
|
219
139
|
Initialize corsika configuration and simulation runners.
|
|
@@ -224,30 +144,22 @@ class Simulator:
|
|
|
224
144
|
Simulation runner object.
|
|
225
145
|
"""
|
|
226
146
|
runner_class = {
|
|
227
|
-
"corsika": CorsikaRunner,
|
|
147
|
+
"corsika": corsika_runner.CorsikaRunner,
|
|
228
148
|
"sim_telarray": SimulatorArray,
|
|
229
|
-
"corsika_sim_telarray": CorsikaSimtelRunner,
|
|
149
|
+
"corsika_sim_telarray": corsika_simtel_runner.CorsikaSimtelRunner,
|
|
230
150
|
}.get(self.simulation_software)
|
|
231
151
|
|
|
232
152
|
runner_args = {
|
|
233
153
|
"label": self.label,
|
|
234
154
|
"corsika_config": self.corsika_configurations,
|
|
235
|
-
"simtel_path": self.args_dict.get("simtel_path"),
|
|
236
|
-
"use_multipipe": runner_class is CorsikaSimtelRunner,
|
|
237
155
|
}
|
|
238
156
|
|
|
239
157
|
if runner_class is not SimulatorArray:
|
|
240
|
-
runner_args["
|
|
241
|
-
runner_args["curved_atmosphere_min_zenith_angle"] = self.args_dict.get(
|
|
158
|
+
runner_args["curved_atmosphere_min_zenith_angle"] = settings.config.args.get(
|
|
242
159
|
"curved_atmosphere_min_zenith_angle", 65 * u.deg
|
|
243
160
|
)
|
|
244
|
-
if runner_class is
|
|
245
|
-
runner_args["
|
|
246
|
-
if runner_class is CorsikaSimtelRunner:
|
|
247
|
-
runner_args["sequential"] = self.args_dict.get("sequential", False)
|
|
248
|
-
runner_args["calibration_config"] = (
|
|
249
|
-
self.args_dict if self._is_calibration_run(self.run_mode) else None
|
|
250
|
-
)
|
|
161
|
+
if runner_class is corsika_simtel_runner.CorsikaSimtelRunner:
|
|
162
|
+
runner_args["sequential"] = settings.config.args.get("sequential", False)
|
|
251
163
|
|
|
252
164
|
return runner_class(**runner_args)
|
|
253
165
|
|
|
@@ -258,25 +170,21 @@ class Simulator:
|
|
|
258
170
|
Writes submission scripts using the simulation runners and submits the
|
|
259
171
|
run script to the job manager. Collects generated files.
|
|
260
172
|
"""
|
|
261
|
-
|
|
173
|
+
self._simulation_runner.prepare_run(
|
|
262
174
|
run_number=self.run_number,
|
|
263
|
-
|
|
175
|
+
corsika_file=self._get_corsika_file(),
|
|
176
|
+
sub_script=self.runner_service.get_file_name("sub_script", self.run_number),
|
|
264
177
|
extra_commands=self._extra_commands,
|
|
265
178
|
)
|
|
179
|
+
self.update_file_lists()
|
|
266
180
|
|
|
267
|
-
job_manager = JobManager(test=self._test)
|
|
268
181
|
job_manager.submit(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
log_file=self._simulation_runner.get_file_name(
|
|
274
|
-
file_type=("log"), run_number=self.run_number
|
|
275
|
-
),
|
|
182
|
+
command=self.runner_service.get_file_name("sub_script", self.run_number),
|
|
183
|
+
out_file=self.runner_service.get_file_name("sub_out", self.run_number),
|
|
184
|
+
err_file=self.runner_service.get_file_name("sub_err", self.run_number),
|
|
185
|
+
env=simtel_runner.SIM_TELARRAY_ENV,
|
|
276
186
|
)
|
|
277
187
|
|
|
278
|
-
self._fill_list_of_generated_files()
|
|
279
|
-
|
|
280
188
|
def _get_corsika_file(self):
|
|
281
189
|
"""
|
|
282
190
|
Get the CORSIKA input file if applicable (for sim_telarray simulations).
|
|
@@ -287,61 +195,12 @@ class Simulator:
|
|
|
287
195
|
Path to the CORSIKA input file.
|
|
288
196
|
"""
|
|
289
197
|
if self.simulation_software == "sim_telarray":
|
|
290
|
-
return
|
|
198
|
+
return settings.config.args.get("corsika_file", None)
|
|
291
199
|
return None
|
|
292
200
|
|
|
293
|
-
def
|
|
294
|
-
"""
|
|
295
|
-
|
|
296
|
-
"simtel_output",
|
|
297
|
-
"sub_out",
|
|
298
|
-
"log",
|
|
299
|
-
"input",
|
|
300
|
-
"histogram",
|
|
301
|
-
"corsika_log",
|
|
302
|
-
"corsika_output",
|
|
303
|
-
"event_data",
|
|
304
|
-
]
|
|
305
|
-
results = {key: [] for key in keys}
|
|
306
|
-
|
|
307
|
-
def get_file_name(name, **kwargs):
|
|
308
|
-
return str(self._simulation_runner.get_file_name(file_type=name, **kwargs))
|
|
309
|
-
|
|
310
|
-
results["sub_out"].append(get_file_name("sub_log", mode="out", run_number=self.run_number))
|
|
311
|
-
|
|
312
|
-
for i in range(len(self.array_models)):
|
|
313
|
-
results["simtel_output"].append(
|
|
314
|
-
get_file_name("simtel_output", run_number=self.run_number, model_version_index=i)
|
|
315
|
-
)
|
|
316
|
-
|
|
317
|
-
if "sim_telarray" in self.simulation_software:
|
|
318
|
-
for file_type in ("log", "histogram", "event_data"):
|
|
319
|
-
results[file_type].append(
|
|
320
|
-
get_file_name(
|
|
321
|
-
file_type,
|
|
322
|
-
simulation_software="sim_telarray",
|
|
323
|
-
run_number=self.run_number,
|
|
324
|
-
model_version_index=i,
|
|
325
|
-
)
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
if "corsika" in self.simulation_software:
|
|
329
|
-
for file_type in ("corsika_output", "corsika_log"):
|
|
330
|
-
results[file_type].append(
|
|
331
|
-
get_file_name(
|
|
332
|
-
file_type,
|
|
333
|
-
simulation_software="corsika",
|
|
334
|
-
run_number=self.run_number,
|
|
335
|
-
model_version_index=i,
|
|
336
|
-
)
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
-
for key in keys:
|
|
340
|
-
self._results[key].extend(results[key])
|
|
341
|
-
|
|
342
|
-
def get_file_list(self, file_type="simtel_output"):
|
|
343
|
-
"""
|
|
344
|
-
Get list of files generated by simulations.
|
|
201
|
+
def get_files(self, file_type):
|
|
202
|
+
"""
|
|
203
|
+
Get file(s) generated by simulations.
|
|
345
204
|
|
|
346
205
|
Not all file types are available for all simulation types.
|
|
347
206
|
Returns an empty list for an unknown file type.
|
|
@@ -353,34 +212,24 @@ class Simulator:
|
|
|
353
212
|
|
|
354
213
|
Returns
|
|
355
214
|
-------
|
|
356
|
-
list
|
|
357
|
-
|
|
215
|
+
Path or list[Path]:
|
|
216
|
+
File or list with the full path of output files of a certain file type.
|
|
358
217
|
|
|
359
218
|
"""
|
|
360
|
-
return self.
|
|
219
|
+
return self.file_list[file_type]
|
|
361
220
|
|
|
362
|
-
def _make_resources_report(self
|
|
221
|
+
def _make_resources_report(self):
|
|
363
222
|
"""
|
|
364
223
|
Prepare a simple report on computing wall clock time used in the simulations.
|
|
365
224
|
|
|
366
|
-
Parameters
|
|
367
|
-
----------
|
|
368
|
-
input_file_list: str or list of str
|
|
369
|
-
Single file or list of files of shower simulations.
|
|
370
|
-
|
|
371
225
|
Returns
|
|
372
226
|
-------
|
|
373
227
|
str
|
|
374
228
|
string reporting on computing resources
|
|
375
229
|
|
|
376
230
|
"""
|
|
377
|
-
if len(self._results["sub_out"]) == 0 and input_file_list is None:
|
|
378
|
-
return "Mean wall time/run [sec]: np.nan"
|
|
379
|
-
|
|
380
231
|
runtime = []
|
|
381
|
-
|
|
382
|
-
_resources = {}
|
|
383
|
-
_resources = self._simulation_runner.get_resources(run_number=self.run_number)
|
|
232
|
+
_resources = self._simulation_runner.get_resources(self.get_files(file_type="sub_out"))
|
|
384
233
|
if _resources.get("runtime"):
|
|
385
234
|
runtime.append(_resources["runtime"])
|
|
386
235
|
|
|
@@ -392,17 +241,11 @@ class Simulator:
|
|
|
392
241
|
|
|
393
242
|
return resource_summary
|
|
394
243
|
|
|
395
|
-
def report(self
|
|
244
|
+
def report(self):
|
|
396
245
|
"""
|
|
397
246
|
Report on simulations and computing resources used.
|
|
398
247
|
|
|
399
248
|
Includes run time per run only at this point.
|
|
400
|
-
|
|
401
|
-
Parameters
|
|
402
|
-
----------
|
|
403
|
-
input_file_list: str or list of str
|
|
404
|
-
Single file or list of files of shower simulations.
|
|
405
|
-
|
|
406
249
|
"""
|
|
407
250
|
_corsika_config = self._get_first_corsika_config()
|
|
408
251
|
self.logger.info(
|
|
@@ -412,22 +255,23 @@ class Simulator:
|
|
|
412
255
|
f"at {self.site} site, using {self.model_version} model."
|
|
413
256
|
)
|
|
414
257
|
self.logger.info(
|
|
415
|
-
f"Computing for {self.simulation_software} Simulations: "
|
|
416
|
-
f"{self._make_resources_report(input_file_list)}"
|
|
258
|
+
f"Computing for {self.simulation_software} Simulations: {self._make_resources_report()}"
|
|
417
259
|
)
|
|
418
260
|
|
|
419
261
|
def save_file_lists(self):
|
|
420
|
-
"""Save
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if
|
|
425
|
-
self.logger.info(f"Saving list of {file_type} files to {file_name}")
|
|
426
|
-
with open(file_name, "w", encoding="utf-8") as f:
|
|
427
|
-
for line in self.get_file_list(file_type=file_type):
|
|
428
|
-
f.write(f"{line}\n")
|
|
429
|
-
else:
|
|
262
|
+
"""Save file lists for output and log files."""
|
|
263
|
+
outdir = self.io_handler.get_output_directory()
|
|
264
|
+
|
|
265
|
+
for file_type, files in self.file_list.items():
|
|
266
|
+
if not files or any(f is None for f in files):
|
|
430
267
|
self.logger.debug(f"No files to save for {file_type} files.")
|
|
268
|
+
continue
|
|
269
|
+
|
|
270
|
+
path = outdir / f"{file_type}_files.txt"
|
|
271
|
+
self.logger.info(f"Saving list of {file_type} files to {path}")
|
|
272
|
+
|
|
273
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
274
|
+
f.write("\n".join(map(str, files)) + "\n")
|
|
431
275
|
|
|
432
276
|
def save_reduced_event_lists(self):
|
|
433
277
|
"""
|
|
@@ -442,10 +286,10 @@ class Simulator:
|
|
|
442
286
|
)
|
|
443
287
|
return
|
|
444
288
|
|
|
445
|
-
input_files = self.
|
|
446
|
-
output_files = self.
|
|
289
|
+
input_files = self.get_files(file_type="sim_telarray_output")
|
|
290
|
+
output_files = self.get_files(file_type="sim_telarray_event_data")
|
|
447
291
|
for input_file, output_file in zip(input_files, output_files):
|
|
448
|
-
generator =
|
|
292
|
+
generator = writer.EventDataWriter([input_file])
|
|
449
293
|
table_handler.write_tables(
|
|
450
294
|
tables=generator.process_files(),
|
|
451
295
|
output_file=Path(output_file),
|
|
@@ -465,15 +309,14 @@ class Simulator:
|
|
|
465
309
|
|
|
466
310
|
"""
|
|
467
311
|
self.logger.info(
|
|
468
|
-
f"Packing
|
|
312
|
+
f"Packing output files for registering on the grid ({directory_for_grid_upload})"
|
|
469
313
|
)
|
|
470
|
-
output_files = self.
|
|
471
|
-
log_files = self.
|
|
472
|
-
|
|
473
|
-
histogram_files = self.get_file_list(file_type="histogram")
|
|
314
|
+
output_files = self.get_files(file_type="sim_telarray_output")
|
|
315
|
+
log_files = self.get_files(file_type="sim_telarray_log")
|
|
316
|
+
histogram_files = self.get_files(file_type="sim_telarray_histogram")
|
|
474
317
|
reduced_event_files = (
|
|
475
|
-
self.
|
|
476
|
-
if
|
|
318
|
+
self.get_files(file_type="sim_telarray_event_data")
|
|
319
|
+
if settings.config.args.get("save_reduced_event_lists")
|
|
477
320
|
else []
|
|
478
321
|
)
|
|
479
322
|
|
|
@@ -484,36 +327,32 @@ class Simulator:
|
|
|
484
327
|
)
|
|
485
328
|
directory_for_grid_upload.mkdir(parents=True, exist_ok=True)
|
|
486
329
|
|
|
487
|
-
# If there are more than one model version,
|
|
488
|
-
# duplicate the corsika log file to have one for each model version with the "right name".
|
|
489
|
-
if len(self.array_models) > 1 and corsika_log_files:
|
|
490
|
-
self._copy_corsika_log_file_for_all_versions(corsika_log_files)
|
|
491
|
-
|
|
492
330
|
# Group files by model version
|
|
493
331
|
for model in self.array_models:
|
|
494
332
|
model_version = model.model_version
|
|
495
|
-
|
|
333
|
+
model_logs = [f for f in log_files if model_version in str(f)]
|
|
496
334
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
model_hists = [f for f in histogram_files if model_version in f]
|
|
500
|
-
model_corsika_logs = [f for f in corsika_log_files if model_version in f]
|
|
335
|
+
if not model_logs:
|
|
336
|
+
continue
|
|
501
337
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
338
|
+
tar_name = Path(model_logs[0]).name.replace("simtel.log.gz", "log_hist.tar.gz")
|
|
339
|
+
tar_path = directory_for_grid_upload / tar_name
|
|
340
|
+
|
|
341
|
+
files_to_tar = (
|
|
342
|
+
model_logs
|
|
343
|
+
+ [f for f in histogram_files if model_version in str(f)]
|
|
344
|
+
+ [str(self.get_files(file_type="corsika_log"))]
|
|
345
|
+
+ list(general.ensure_iterable(model.pack_model_files()))
|
|
346
|
+
)
|
|
347
|
+
general.pack_tar_file(tar_path, files_to_tar)
|
|
508
348
|
|
|
509
349
|
for file_to_move in output_files + reduced_event_files:
|
|
510
|
-
|
|
511
|
-
destination_file = directory_for_grid_upload / source_file.name
|
|
350
|
+
destination_file = directory_for_grid_upload / Path(file_to_move).name
|
|
512
351
|
if destination_file.exists():
|
|
513
352
|
self.logger.warning(f"Overwriting existing file: {destination_file}")
|
|
514
|
-
shutil.move(
|
|
353
|
+
shutil.move(file_to_move, destination_file)
|
|
515
354
|
|
|
516
|
-
self.logger.info(f"
|
|
355
|
+
self.logger.info(f"Grid output files grid placed in {directory_for_grid_upload!s}")
|
|
517
356
|
|
|
518
357
|
def validate_metadata(self):
|
|
519
358
|
"""Validate metadata in the sim_telarray output files."""
|
|
@@ -522,8 +361,9 @@ class Simulator:
|
|
|
522
361
|
return
|
|
523
362
|
|
|
524
363
|
for model in self.array_models:
|
|
525
|
-
files = self.
|
|
526
|
-
|
|
364
|
+
files = general.ensure_iterable(self.get_files(file_type="sim_telarray_output"))
|
|
365
|
+
|
|
366
|
+
output_file = next((f for f in files if model.model_version in str(f)), None)
|
|
527
367
|
if output_file:
|
|
528
368
|
self.logger.info(f"Validating metadata for {output_file}")
|
|
529
369
|
assert_sim_telarray_metadata(output_file, model)
|
|
@@ -533,76 +373,6 @@ class Simulator:
|
|
|
533
373
|
f"No sim_telarray file found for model version {model.model_version}: {files}"
|
|
534
374
|
)
|
|
535
375
|
|
|
536
|
-
def _copy_corsika_log_file_for_all_versions(self, corsika_log_files):
|
|
537
|
-
"""
|
|
538
|
-
Create copies of the CORSIKA log file for each model version.
|
|
539
|
-
|
|
540
|
-
Adds a header comment to each copy explaining its relationship to the original.
|
|
541
|
-
|
|
542
|
-
Parameters
|
|
543
|
-
----------
|
|
544
|
-
corsika_log_files: list
|
|
545
|
-
List containing the original CORSIKA log file path.
|
|
546
|
-
"""
|
|
547
|
-
original_log = Path(corsika_log_files[0])
|
|
548
|
-
# Find which model version the original log belongs to
|
|
549
|
-
original_version = next(
|
|
550
|
-
model.model_version
|
|
551
|
-
for model in self.array_models
|
|
552
|
-
if re.search(
|
|
553
|
-
rf"(?<![0-9A-Za-z]){re.escape(model.model_version)}(?![0-9A-Za-z])",
|
|
554
|
-
original_log.name,
|
|
555
|
-
)
|
|
556
|
-
)
|
|
557
|
-
|
|
558
|
-
for model in self.array_models:
|
|
559
|
-
if model.model_version == original_version:
|
|
560
|
-
continue
|
|
561
|
-
|
|
562
|
-
new_log = original_log.parent / original_log.name.replace(
|
|
563
|
-
original_version, model.model_version
|
|
564
|
-
)
|
|
565
|
-
|
|
566
|
-
with gzip.open(new_log, "wt", encoding="utf-8") as new_file:
|
|
567
|
-
# Write the header to the new file
|
|
568
|
-
header = (
|
|
569
|
-
f"###############################################################\n"
|
|
570
|
-
f"Copy of CORSIKA log file from model version {original_version}.\n"
|
|
571
|
-
f"Applicable also for {model.model_version} (same CORSIKA configuration,\n"
|
|
572
|
-
f"different sim_telarray model versions in the same run).\n"
|
|
573
|
-
f"###############################################################\n\n"
|
|
574
|
-
)
|
|
575
|
-
new_file.write(header)
|
|
576
|
-
|
|
577
|
-
# Copy the content of the original log file, ignoring invalid characters
|
|
578
|
-
with gzip.open(original_log, "rt", encoding="utf-8", errors="ignore") as orig_file:
|
|
579
|
-
for line in orig_file:
|
|
580
|
-
new_file.write(line)
|
|
581
|
-
|
|
582
|
-
corsika_log_files.append(str(new_log))
|
|
583
|
-
|
|
584
|
-
@staticmethod
|
|
585
|
-
def _is_calibration_run(run_mode):
|
|
586
|
-
"""
|
|
587
|
-
Check if this simulation is a calibration run.
|
|
588
|
-
|
|
589
|
-
Parameters
|
|
590
|
-
----------
|
|
591
|
-
run_mode: str
|
|
592
|
-
Run mode of the simulation.
|
|
593
|
-
|
|
594
|
-
Returns
|
|
595
|
-
-------
|
|
596
|
-
bool
|
|
597
|
-
True if it is a calibration run, False otherwise.
|
|
598
|
-
"""
|
|
599
|
-
return run_mode in [
|
|
600
|
-
"pedestals",
|
|
601
|
-
"pedestals_dark",
|
|
602
|
-
"pedestals_nsb_only",
|
|
603
|
-
"direct_injection",
|
|
604
|
-
]
|
|
605
|
-
|
|
606
376
|
@staticmethod
|
|
607
377
|
def _get_calibration_device_types(run_mode):
|
|
608
378
|
"""
|
|
@@ -666,7 +436,7 @@ class Simulator:
|
|
|
666
436
|
)
|
|
667
437
|
if self.simulation_software == "corsika":
|
|
668
438
|
self._verify_simulated_events_corsika(expected_mc_events)
|
|
669
|
-
if
|
|
439
|
+
if settings.config.args.get("save_reduced_event_lists"):
|
|
670
440
|
self._verify_simulated_events_in_reduced_event_lists(expected_mc_events)
|
|
671
441
|
|
|
672
442
|
def _verify_simulated_events_corsika(self, expected_mc_events, tolerance=1.0e-3):
|
|
@@ -690,24 +460,25 @@ class Simulator:
|
|
|
690
460
|
return abs(a - b) / max(a, b) <= tol
|
|
691
461
|
|
|
692
462
|
event_errors = []
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
)
|
|
702
|
-
|
|
463
|
+
|
|
464
|
+
file = self.get_files(file_type="corsika_output")
|
|
465
|
+
shower_events, _ = file_info.get_simulated_events(file)
|
|
466
|
+
|
|
467
|
+
if shower_events != expected_mc_events:
|
|
468
|
+
if consistent(shower_events, expected_mc_events, tol=tolerance):
|
|
469
|
+
self.logger.warning(
|
|
470
|
+
f"Small mismatch in number of events in: {file}: "
|
|
471
|
+
f"shower events: {shower_events} (expected: {expected_mc_events})"
|
|
472
|
+
)
|
|
473
|
+
else:
|
|
703
474
|
event_errors.append(
|
|
704
475
|
f"Number of simulated MC events ({shower_events}) does not match "
|
|
705
476
|
f"the expected number ({expected_mc_events}) in CORSIKA {file}."
|
|
706
477
|
)
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
478
|
+
else:
|
|
479
|
+
self.logger.info(
|
|
480
|
+
f"Consistent number of events in: {file}: shower events: {shower_events}"
|
|
481
|
+
)
|
|
711
482
|
|
|
712
483
|
if event_errors:
|
|
713
484
|
self.logger.error("Inconsistent event counts found in CORSIKA output:")
|
|
@@ -735,8 +506,8 @@ class Simulator:
|
|
|
735
506
|
If the number of simulated events does not match the expected number.
|
|
736
507
|
"""
|
|
737
508
|
event_errors = []
|
|
738
|
-
for file in self.
|
|
739
|
-
shower_events, mc_events =
|
|
509
|
+
for file in general.ensure_iterable(self.get_files(file_type="sim_telarray_output")):
|
|
510
|
+
shower_events, mc_events = file_info.get_simulated_events(file)
|
|
740
511
|
|
|
741
512
|
if (shower_events, mc_events) != (expected_shower_events, expected_mc_events):
|
|
742
513
|
event_errors.append(
|
|
@@ -774,7 +545,7 @@ class Simulator:
|
|
|
774
545
|
If the number of simulated events does not match the expected number.
|
|
775
546
|
"""
|
|
776
547
|
event_errors = []
|
|
777
|
-
for file in self.
|
|
548
|
+
for file in self.get_files(file_type="sim_telarray_event_data"):
|
|
778
549
|
tables = table_handler.read_tables(file, ["SHOWERS"])
|
|
779
550
|
try:
|
|
780
551
|
mc_events = len(tables["SHOWERS"])
|
|
@@ -800,3 +571,14 @@ class Simulator:
|
|
|
800
571
|
f" - {error}" for error in event_errors
|
|
801
572
|
)
|
|
802
573
|
raise ValueError(error_message)
|
|
574
|
+
|
|
575
|
+
def update_file_lists(self):
|
|
576
|
+
"""
|
|
577
|
+
Update file lists with all data, log, histogram and submission files.
|
|
578
|
+
|
|
579
|
+
Some of these files are generated by the simulation runners.
|
|
580
|
+
"""
|
|
581
|
+
if self.file_list is None:
|
|
582
|
+
self.file_list = self._simulation_runner.file_list
|
|
583
|
+
else:
|
|
584
|
+
self.file_list.update(self._simulation_runner.file_list)
|