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
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
import logging
|
|
5
|
-
import os
|
|
6
5
|
import sys
|
|
7
6
|
import uuid
|
|
8
7
|
|
|
9
8
|
import astropy.units as u
|
|
10
|
-
from dotenv import load_dotenv
|
|
11
9
|
|
|
12
10
|
import simtools.configuration.commandline_parser as argparser
|
|
13
11
|
from simtools.db.mongo_db import jsonschema_db_dict
|
|
@@ -305,19 +303,16 @@ class Configurator:
|
|
|
305
303
|
Only parameters which are not already configured are changed (i.e., parameter is None).
|
|
306
304
|
|
|
307
305
|
"""
|
|
306
|
+
_all_env_dict = gen.load_environment_variables(
|
|
307
|
+
env_file=self.config.get("env_file", None), env_list=self.config.keys()
|
|
308
|
+
)
|
|
309
|
+
|
|
308
310
|
_env_dict = {}
|
|
309
|
-
try:
|
|
310
|
-
load_dotenv(self.config["env_file"])
|
|
311
|
-
except KeyError:
|
|
312
|
-
pass
|
|
313
311
|
for key, value in self.config.items():
|
|
314
|
-
# environmental variables for simtools should always start with SIMTOOLS_
|
|
315
|
-
env_variable_to_read = f"SIMTOOLS_{key.upper()}"
|
|
316
312
|
if value is None:
|
|
317
|
-
env_value =
|
|
313
|
+
env_value = _all_env_dict.get(key)
|
|
318
314
|
if env_value is not None:
|
|
319
|
-
|
|
320
|
-
_env_dict[key] = env_value
|
|
315
|
+
_env_dict[key] = env_value
|
|
321
316
|
|
|
322
317
|
self._fill_from_config_dict(_env_dict)
|
|
323
318
|
|
simtools/constants.py
CHANGED
|
@@ -23,3 +23,8 @@ MODEL_PARAMETER_SCHEMA_URL = (
|
|
|
23
23
|
)
|
|
24
24
|
# Path to resource files
|
|
25
25
|
RESOURCE_PATH = files("simtools") / "resources"
|
|
26
|
+
|
|
27
|
+
# Maximum value allowed for random seeds in sim_telarray
|
|
28
|
+
SIMTEL_MAX_SEED = 2147483647
|
|
29
|
+
# Maximum value allowed for random seeds in CORSIKA
|
|
30
|
+
CORSIKA_MAX_SEED = 900000000
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
"""CORSIKA configuration."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
from collections.abc import Mapping
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
import numpy as np
|
|
7
8
|
from astropy import units as u
|
|
8
9
|
|
|
10
|
+
from simtools import settings
|
|
11
|
+
from simtools.constants import CORSIKA_MAX_SEED
|
|
9
12
|
from simtools.corsika.primary_particle import PrimaryParticle
|
|
10
|
-
from simtools.io import
|
|
13
|
+
from simtools.io import io_handler
|
|
11
14
|
from simtools.model.model_parameter import ModelParameter
|
|
15
|
+
from simtools.sim_events import file_info
|
|
12
16
|
from simtools.utils import general as gen
|
|
17
|
+
from simtools.utils.random import seeds
|
|
13
18
|
|
|
14
19
|
|
|
15
20
|
class CorsikaConfig:
|
|
@@ -25,37 +30,31 @@ class CorsikaConfig:
|
|
|
25
30
|
----------
|
|
26
31
|
array_model : ArrayModel
|
|
27
32
|
Array model.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
db_config : dict
|
|
31
|
-
MongoDB configuration.
|
|
33
|
+
run_number : int
|
|
34
|
+
Run number.
|
|
32
35
|
label : str
|
|
33
36
|
Instance label.
|
|
34
|
-
dummy_simulations : bool
|
|
35
|
-
If True, the configuration is generated for dummy simulations
|
|
36
|
-
(e.g., sim_telarray requires for some run modes a valid CORSIKA input file).
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
|
-
def __init__(self, array_model,
|
|
39
|
+
def __init__(self, array_model, run_number, label=None):
|
|
40
40
|
"""Initialize CorsikaConfig."""
|
|
41
41
|
self._logger = logging.getLogger(__name__)
|
|
42
|
-
self._logger.debug("Init CorsikaConfig")
|
|
43
42
|
|
|
44
43
|
self.label = label
|
|
45
44
|
self.shower_events = self.mc_events = None
|
|
46
45
|
self.zenith_angle = self.azimuth_angle = None
|
|
47
46
|
self.curved_atmosphere_min_zenith_angle = None
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
50
|
-
self.
|
|
51
|
-
self.
|
|
52
|
-
self.dummy_simulations = dummy_simulations
|
|
47
|
+
self.run_number = run_number
|
|
48
|
+
self.primary_particle = settings.config.args # see setter for primary_particle
|
|
49
|
+
self.use_curved_atmosphere = settings.config.args # see setter for use_curved_atmosphere
|
|
50
|
+
self.run_mode = settings.config.args.get("run_mode")
|
|
53
51
|
|
|
54
52
|
self.io_handler = io_handler.IOHandler()
|
|
55
53
|
self.array_model = array_model
|
|
56
|
-
self.
|
|
57
|
-
self.
|
|
58
|
-
self.
|
|
54
|
+
self.corsika_exec = settings.config.corsika_exe
|
|
55
|
+
self.interaction_table_path = settings.config.corsika_interaction_table_path
|
|
56
|
+
self.config = self._fill_corsika_configuration(settings.config.args)
|
|
57
|
+
self._initialize_from_config(settings.config.args)
|
|
59
58
|
|
|
60
59
|
@property
|
|
61
60
|
def primary_particle(self):
|
|
@@ -76,7 +75,7 @@ class CorsikaConfig:
|
|
|
76
75
|
Configuration dictionary
|
|
77
76
|
"""
|
|
78
77
|
if (
|
|
79
|
-
isinstance(args, dict)
|
|
78
|
+
isinstance(args, Mapping) # dict-like (includes mappingproxy)
|
|
80
79
|
and args.get("primary_id_type") is not None
|
|
81
80
|
and args.get("primary") is not None
|
|
82
81
|
):
|
|
@@ -101,7 +100,7 @@ class CorsikaConfig:
|
|
|
101
100
|
self._use_curved_atmosphere = False
|
|
102
101
|
if isinstance(args, bool):
|
|
103
102
|
self._use_curved_atmosphere = args
|
|
104
|
-
elif isinstance(args, dict)
|
|
103
|
+
elif isinstance(args, Mapping): # dict-like (includes mappingproxy)
|
|
105
104
|
try:
|
|
106
105
|
self._use_curved_atmosphere = (
|
|
107
106
|
args.get("zenith_angle", 0.0 * u.deg).to("deg").value
|
|
@@ -110,7 +109,7 @@ class CorsikaConfig:
|
|
|
110
109
|
except KeyError:
|
|
111
110
|
self._use_curved_atmosphere = False
|
|
112
111
|
|
|
113
|
-
def _fill_corsika_configuration(self,
|
|
112
|
+
def _fill_corsika_configuration(self, args):
|
|
114
113
|
"""
|
|
115
114
|
Fill CORSIKA configuration.
|
|
116
115
|
|
|
@@ -119,48 +118,48 @@ class CorsikaConfig:
|
|
|
119
118
|
|
|
120
119
|
Parameters
|
|
121
120
|
----------
|
|
122
|
-
|
|
121
|
+
args: dict
|
|
123
122
|
Configuration dictionary.
|
|
124
|
-
db_config: dict
|
|
125
|
-
Database configuration.
|
|
126
123
|
|
|
127
124
|
Returns
|
|
128
125
|
-------
|
|
129
126
|
dict
|
|
130
127
|
Dictionary with CORSIKA parameters.
|
|
131
128
|
"""
|
|
132
|
-
if
|
|
129
|
+
if args is None:
|
|
133
130
|
return {}
|
|
134
131
|
|
|
135
132
|
config = {}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
config["RUNNR"] = [self.run_number]
|
|
134
|
+
config["USER"] = [settings.config.user]
|
|
135
|
+
config["HOST"] = [settings.config.hostname]
|
|
136
|
+
if self.is_calibration_run():
|
|
137
|
+
config["USER_INPUT"] = self._corsika_configuration_for_dummy_simulations(args)
|
|
138
|
+
elif args.get("corsika_file", None) is not None:
|
|
139
139
|
config["USER_INPUT"] = self._corsika_configuration_from_corsika_file(
|
|
140
|
-
|
|
140
|
+
args["corsika_file"]
|
|
141
141
|
)
|
|
142
142
|
else:
|
|
143
|
-
config["USER_INPUT"] = self._corsika_configuration_from_user_input(
|
|
143
|
+
config["USER_INPUT"] = self._corsika_configuration_from_user_input(args)
|
|
144
144
|
|
|
145
145
|
config.update(
|
|
146
|
-
self._fill_corsika_configuration_from_db(
|
|
147
|
-
gen.ensure_iterable(args_dict.get("model_version")), db_config
|
|
148
|
-
)
|
|
146
|
+
self._fill_corsika_configuration_from_db(gen.ensure_iterable(args.get("model_version")))
|
|
149
147
|
)
|
|
150
148
|
return config
|
|
151
149
|
|
|
152
|
-
def _fill_corsika_configuration_from_db(self, model_versions
|
|
150
|
+
def _fill_corsika_configuration_from_db(self, model_versions):
|
|
153
151
|
"""Fill CORSIKA configuration from database."""
|
|
154
152
|
config = {}
|
|
155
|
-
|
|
153
|
+
# all following parameters require DB
|
|
154
|
+
if settings.config.db_config is None or not model_versions:
|
|
156
155
|
return config
|
|
157
156
|
|
|
158
157
|
# For multiple model versions, check that CORSIKA parameters are identical
|
|
159
|
-
self.assert_corsika_configurations_match(model_versions
|
|
158
|
+
self.assert_corsika_configurations_match(model_versions)
|
|
160
159
|
model_version = model_versions[0]
|
|
161
160
|
|
|
162
161
|
self._logger.debug(f"Using model version {model_version} for CORSIKA parameters from DB")
|
|
163
|
-
db_model_parameters = ModelParameter(
|
|
162
|
+
db_model_parameters = ModelParameter(model_version=model_version)
|
|
164
163
|
parameters_from_db = db_model_parameters.get_simulation_software_parameters("corsika")
|
|
165
164
|
|
|
166
165
|
config["INTERACTION_FLAGS"] = self._corsika_configuration_interaction_flags(
|
|
@@ -173,13 +172,17 @@ class CorsikaConfig:
|
|
|
173
172
|
config["IACT_PARAMETERS"] = self._corsika_configuration_iact_parameters(parameters_from_db)
|
|
174
173
|
return config
|
|
175
174
|
|
|
176
|
-
def _initialize_from_config(self,
|
|
175
|
+
def _initialize_from_config(self, args):
|
|
177
176
|
"""
|
|
178
177
|
Initialize additional parameters either from command line args or from derived config.
|
|
179
178
|
|
|
180
179
|
Takes into account that in the case of a given CORSIKA input file, some parameters are read
|
|
181
180
|
from the file instead of the command line args.
|
|
182
181
|
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
args: dict
|
|
185
|
+
Command line arguments.
|
|
183
186
|
"""
|
|
184
187
|
self.primary_particle = int(self.config.get("USER_INPUT", {}).get("PRMPAR", [1])[0])
|
|
185
188
|
self.shower_events = int(self.config.get("USER_INPUT", {}).get("NSHOW", [0])[0])
|
|
@@ -187,7 +190,7 @@ class CorsikaConfig:
|
|
|
187
190
|
self.shower_events * self.config.get("USER_INPUT", {}).get("CSCAT", [1])[0]
|
|
188
191
|
)
|
|
189
192
|
|
|
190
|
-
if
|
|
193
|
+
if args.get("corsika_file", None) is not None:
|
|
191
194
|
azimuth = self._rotate_azimuth_by_180deg(
|
|
192
195
|
0.5 * (self.config["USER_INPUT"]["PHIP"][0] + self.config["USER_INPUT"]["PHIP"][1]),
|
|
193
196
|
invert_operation=True,
|
|
@@ -196,17 +199,17 @@ class CorsikaConfig:
|
|
|
196
199
|
self.config["USER_INPUT"]["THETAP"][0] + self.config["USER_INPUT"]["THETAP"][1]
|
|
197
200
|
)
|
|
198
201
|
else:
|
|
199
|
-
azimuth =
|
|
200
|
-
zenith =
|
|
202
|
+
azimuth = args.get("azimuth_angle", 0.0 * u.deg).to("deg").value
|
|
203
|
+
zenith = args.get("zenith_angle", 20.0 * u.deg).to("deg").value
|
|
201
204
|
|
|
202
205
|
self.azimuth_angle = round(azimuth)
|
|
203
206
|
self.zenith_angle = round(zenith)
|
|
204
207
|
|
|
205
208
|
self.curved_atmosphere_min_zenith_angle = (
|
|
206
|
-
|
|
209
|
+
args.get("curved_atmosphere_min_zenith_angle", 90.0 * u.deg).to("deg").value
|
|
207
210
|
)
|
|
208
211
|
|
|
209
|
-
def assert_corsika_configurations_match(self, model_versions
|
|
212
|
+
def assert_corsika_configurations_match(self, model_versions):
|
|
210
213
|
"""
|
|
211
214
|
Assert that CORSIKA configurations match across all model versions.
|
|
212
215
|
|
|
@@ -214,8 +217,6 @@ class CorsikaConfig:
|
|
|
214
217
|
----------
|
|
215
218
|
model_versions : list
|
|
216
219
|
List of model versions to check.
|
|
217
|
-
db_config : dict, optional
|
|
218
|
-
Database configuration.
|
|
219
220
|
|
|
220
221
|
Raises
|
|
221
222
|
------
|
|
@@ -229,7 +230,7 @@ class CorsikaConfig:
|
|
|
229
230
|
|
|
230
231
|
# Get parameters for all model versions
|
|
231
232
|
for model_version in model_versions:
|
|
232
|
-
db_model_parameters = ModelParameter(
|
|
233
|
+
db_model_parameters = ModelParameter(model_version=model_version)
|
|
233
234
|
parameters_from_db_list.append(
|
|
234
235
|
db_model_parameters.get_simulation_software_parameters("corsika")
|
|
235
236
|
)
|
|
@@ -264,6 +265,7 @@ class CorsikaConfig:
|
|
|
264
265
|
|
|
265
266
|
Settings are such that that the simulations are fast
|
|
266
267
|
and none (or not many) Cherenkov photons are generated.
|
|
268
|
+
This is e.g. used for some calibration run modes in sim_telarray.
|
|
267
269
|
|
|
268
270
|
Returns
|
|
269
271
|
-------
|
|
@@ -271,6 +273,7 @@ class CorsikaConfig:
|
|
|
271
273
|
Dictionary with CORSIKA parameters for dummy simulations.
|
|
272
274
|
"""
|
|
273
275
|
theta, phi = self._get_corsika_theta_phi(args_dict)
|
|
276
|
+
self._logger.info("Using CORSIKA configuration for dummy simulations.")
|
|
274
277
|
return {
|
|
275
278
|
"EVTNR": [1],
|
|
276
279
|
"NSHOW": [1],
|
|
@@ -301,9 +304,7 @@ class CorsikaConfig:
|
|
|
301
304
|
dict
|
|
302
305
|
Dictionary with CORSIKA parameters from input file.
|
|
303
306
|
"""
|
|
304
|
-
run_header, event_header =
|
|
305
|
-
corsika_input_file
|
|
306
|
-
)
|
|
307
|
+
run_header, event_header = file_info.get_corsika_run_and_event_headers(corsika_input_file)
|
|
307
308
|
self._logger.debug(f"CORSIKA run header from {corsika_input_file}")
|
|
308
309
|
|
|
309
310
|
def to_float32(value):
|
|
@@ -432,9 +433,25 @@ class CorsikaConfig:
|
|
|
432
433
|
parameters["MAXPRT"] = ["10"]
|
|
433
434
|
parameters["ECTMAP"] = ["1.e6"]
|
|
434
435
|
|
|
436
|
+
if "epos" in str(self.corsika_exec).lower():
|
|
437
|
+
parameters.update(self._epos_flags())
|
|
438
|
+
|
|
435
439
|
self._logger.debug(f"Interaction parameters: {parameters}")
|
|
436
440
|
return parameters
|
|
437
441
|
|
|
442
|
+
def _epos_flags(self):
|
|
443
|
+
"""EPOS interaction model flags."""
|
|
444
|
+
epos_par = {}
|
|
445
|
+
epos_path = Path(self.interaction_table_path)
|
|
446
|
+
epos_par["EPOPAR fname pathnx"] = [f"{epos_path}/"]
|
|
447
|
+
for epos_file in ["inics", "iniev", "inirj", "initl"]:
|
|
448
|
+
epos_par[f"EPOPAR fname {epos_file}"] = [str(epos_path / f"epos.{epos_file}")]
|
|
449
|
+
epos_par["EPOPAR fname hpf"] = [str(epos_path / "urqmd34/tables.dat")]
|
|
450
|
+
for dummy_output in ["check", "histo", "data", "copy"]:
|
|
451
|
+
epos_par[f"EPOPAR fname {dummy_output}"] = ["none"]
|
|
452
|
+
|
|
453
|
+
return epos_par
|
|
454
|
+
|
|
438
455
|
def _input_config_first_interaction_height(self, entry):
|
|
439
456
|
"""Return FIXHEI parameter CORSIKA format."""
|
|
440
457
|
return [f"{entry['value'] * u.Unit(entry['unit']).to('cm'):.2f}", "0"]
|
|
@@ -553,7 +570,7 @@ class CorsikaConfig:
|
|
|
553
570
|
"""Return CORSIKA debugging output parameters."""
|
|
554
571
|
return {
|
|
555
572
|
"DEBUG": ["F", 6, "F", 1000000],
|
|
556
|
-
"DATBAS": ["
|
|
573
|
+
"DATBAS": ["F"],
|
|
557
574
|
"DIRECT": ["./"],
|
|
558
575
|
"PAROUT": ["F", "F"],
|
|
559
576
|
}
|
|
@@ -596,11 +613,6 @@ class CorsikaConfig:
|
|
|
596
613
|
return (az - 180 - b_field_declination) % 360
|
|
597
614
|
return (az + 180 + b_field_declination) % 360
|
|
598
615
|
|
|
599
|
-
@property
|
|
600
|
-
def primary(self):
|
|
601
|
-
"""Primary particle name."""
|
|
602
|
-
return self.primary_particle.name
|
|
603
|
-
|
|
604
616
|
def get_config_parameter(self, par_name):
|
|
605
617
|
"""
|
|
606
618
|
Get value of CORSIKA configuration parameter.
|
|
@@ -621,7 +633,7 @@ class CorsikaConfig:
|
|
|
621
633
|
Value(s) of the parameter.
|
|
622
634
|
"""
|
|
623
635
|
par_value = []
|
|
624
|
-
for
|
|
636
|
+
for values in self.config.values():
|
|
625
637
|
if par_name in values:
|
|
626
638
|
par_value = values[par_name]
|
|
627
639
|
if len(par_value) == 0:
|
|
@@ -652,7 +664,7 @@ class CorsikaConfig:
|
|
|
652
664
|
text += line
|
|
653
665
|
return text
|
|
654
666
|
|
|
655
|
-
def generate_corsika_input_file(self, use_multipipe
|
|
667
|
+
def generate_corsika_input_file(self, use_multipipe, input_file, output_file):
|
|
656
668
|
"""
|
|
657
669
|
Generate a CORSIKA input file.
|
|
658
670
|
|
|
@@ -661,16 +673,14 @@ class CorsikaConfig:
|
|
|
661
673
|
use_multipipe: bool
|
|
662
674
|
Whether to set the CORSIKA Inputs file to pipe
|
|
663
675
|
the output directly to sim_telarray.
|
|
664
|
-
|
|
676
|
+
input_file: Path
|
|
677
|
+
Path to the input file to be generated.
|
|
678
|
+
output_file: Path
|
|
679
|
+
Path to the output file to be generated.
|
|
665
680
|
"""
|
|
666
|
-
|
|
667
|
-
self._logger.debug(f"CORSIKA input file already updated: {self.config_file_path}")
|
|
668
|
-
return self.config_file_path
|
|
669
|
-
self._logger.info(f"Exporting CORSIKA input file to {self.config_file_path}")
|
|
670
|
-
_output_generic_file_name = self.set_output_file_and_directory(use_multipipe=use_multipipe)
|
|
671
|
-
self._logger.info(f"Output generic file name: {_output_generic_file_name}")
|
|
681
|
+
self._logger.info(f"Exporting CORSIKA input file to {input_file}")
|
|
672
682
|
|
|
673
|
-
with open(
|
|
683
|
+
with open(input_file, "w", encoding="utf-8") as file:
|
|
674
684
|
file.write("\n* [ RUN PARAMETERS ]\n")
|
|
675
685
|
text_parameters = self._get_text_single_line(self.config["USER_INPUT"])
|
|
676
686
|
file.write(text_parameters)
|
|
@@ -689,7 +699,7 @@ class CorsikaConfig:
|
|
|
689
699
|
file.write(f"IACT setenv AZM {self.azimuth_angle}\n")
|
|
690
700
|
|
|
691
701
|
file.write("\n* [ SEEDS ]\n")
|
|
692
|
-
self._write_seeds(file
|
|
702
|
+
self._write_seeds(file)
|
|
693
703
|
|
|
694
704
|
file.write("\n* [ TELESCOPES ]\n")
|
|
695
705
|
telescope_list_text = self.get_corsika_telescope_list()
|
|
@@ -698,6 +708,7 @@ class CorsikaConfig:
|
|
|
698
708
|
file.write("\n* [ INTERACTION FLAGS ]\n")
|
|
699
709
|
text_interaction_flags = self._get_text_single_line(self.config["INTERACTION_FLAGS"])
|
|
700
710
|
file.write(text_interaction_flags)
|
|
711
|
+
file.write(f"DATDIR {self.interaction_table_path}\n")
|
|
701
712
|
|
|
702
713
|
file.write("\n* [ CHERENKOV EMISSION PARAMETERS ]\n")
|
|
703
714
|
text_cherenkov = self._get_text_single_line(
|
|
@@ -711,10 +722,9 @@ class CorsikaConfig:
|
|
|
711
722
|
|
|
712
723
|
file.write("\n* [ OUTPUT FILE ]\n")
|
|
713
724
|
if use_multipipe:
|
|
714
|
-
|
|
715
|
-
file.write(f"TELFIL |{run_cta_script!s}\n")
|
|
725
|
+
file.write(f"TELFIL |{output_file!s}\n")
|
|
716
726
|
else:
|
|
717
|
-
file.write(f"TELFIL {
|
|
727
|
+
file.write(f"TELFIL {output_file.name}\n")
|
|
718
728
|
|
|
719
729
|
file.write("\n* [ IACT TUNING PARAMETERS ]\n")
|
|
720
730
|
text_iact = self._get_text_single_line(
|
|
@@ -731,111 +741,22 @@ class CorsikaConfig:
|
|
|
731
741
|
model_directory=self.array_model.get_config_directory()
|
|
732
742
|
)
|
|
733
743
|
|
|
734
|
-
|
|
735
|
-
return self.config_file_path
|
|
736
|
-
|
|
737
|
-
def get_corsika_config_file_name(self, file_type, run_number=None):
|
|
738
|
-
"""
|
|
739
|
-
Get a CORSIKA config style file name for various configuration file types.
|
|
740
|
-
|
|
741
|
-
Parameters
|
|
742
|
-
----------
|
|
743
|
-
file_type: str
|
|
744
|
-
The type of file (determines the file suffix).
|
|
745
|
-
Choices are config_tmp, config or output_generic.
|
|
746
|
-
run_number: int
|
|
747
|
-
Run number.
|
|
748
|
-
|
|
749
|
-
Returns
|
|
750
|
-
-------
|
|
751
|
-
str
|
|
752
|
-
for file_type="config_tmp":
|
|
753
|
-
Return CORSIKA input file name for one specific run.
|
|
754
|
-
This is the input file after being pre-processed by sim_telarray (pfp).
|
|
755
|
-
for file_type="config":
|
|
756
|
-
Return generic CORSIKA config input file name.
|
|
757
|
-
for file_type="output_generic"
|
|
758
|
-
Return generic file name for the TELFIL option in the CORSIKA inputs file.
|
|
759
|
-
for file_type="multipipe"
|
|
760
|
-
Return multipipe "file name" for the TELFIL option in the CORSIKA inputs file.
|
|
761
|
-
|
|
762
|
-
Raises
|
|
763
|
-
------
|
|
764
|
-
ValueError
|
|
765
|
-
If file_type is unknown or if the run number is not given for file_type==config_tmp.
|
|
766
|
-
"""
|
|
767
|
-
if file_type == "config_tmp" and run_number is None:
|
|
768
|
-
raise ValueError("Must provide a run number for a temporary CORSIKA config file")
|
|
769
|
-
|
|
770
|
-
file_label = f"_{self.label}" if self.label is not None else ""
|
|
771
|
-
|
|
772
|
-
_vc_low = self.get_config_parameter("VIEWCONE")[0]
|
|
773
|
-
_vc_high = self.get_config_parameter("VIEWCONE")[1]
|
|
774
|
-
view_cone = (
|
|
775
|
-
f"_cone{int(_vc_low):d}-{int(_vc_high):d}" if _vc_low != 0 or _vc_high != 0 else ""
|
|
776
|
-
)
|
|
777
|
-
|
|
778
|
-
run_number_in_file_name = ""
|
|
779
|
-
if file_type == "output_generic":
|
|
780
|
-
# The XXXXXX will be replaced by the run number after the pfp step with sed
|
|
781
|
-
run_number_in_file_name = "runXXXXXX_"
|
|
782
|
-
if file_type == "config_tmp":
|
|
783
|
-
run_number_in_file_name = f"run{run_number:06}_"
|
|
784
|
-
|
|
785
|
-
base_name = (
|
|
786
|
-
f"{self.primary_particle.name}_{run_number_in_file_name}"
|
|
787
|
-
f"za{int(self.get_config_parameter('THETAP')[0]):02}deg_"
|
|
788
|
-
f"azm{self.azimuth_angle:03}deg{view_cone}_"
|
|
789
|
-
f"{self.array_model.site}_{self.array_model.layout_name}_"
|
|
790
|
-
f"{self.array_model.model_version}{file_label}"
|
|
791
|
-
)
|
|
792
|
-
|
|
793
|
-
if file_type == "config_tmp":
|
|
794
|
-
return f"corsika_config_{base_name}.txt"
|
|
795
|
-
if file_type == "config":
|
|
796
|
-
return f"corsika_config_{base_name}.input"
|
|
797
|
-
if file_type == "output_generic":
|
|
798
|
-
return f"{base_name}.corsika.zst"
|
|
799
|
-
if file_type == "multipipe":
|
|
800
|
-
return f"multi_cta-{self.array_model.site}-{self.array_model.layout_name}.cfg"
|
|
801
|
-
|
|
802
|
-
raise ValueError(f"The requested file type ({file_type}) is unknown")
|
|
803
|
-
|
|
804
|
-
def set_output_file_and_directory(self, use_multipipe=False):
|
|
805
|
-
"""
|
|
806
|
-
Set output file names and directories.
|
|
807
|
-
|
|
808
|
-
Parameters
|
|
809
|
-
----------
|
|
810
|
-
use_multipipe: bool
|
|
811
|
-
Whether to set the CORSIKA Inputs file to pipe
|
|
812
|
-
the output directly to sim_telarray. Defines directory names.
|
|
813
|
-
|
|
814
|
-
Returns
|
|
815
|
-
-------
|
|
816
|
-
str
|
|
817
|
-
Output file name.
|
|
818
|
-
"""
|
|
819
|
-
self.config_file_path = self.io_handler.get_output_file(
|
|
820
|
-
file_name=self.get_corsika_config_file_name(file_type="config"),
|
|
821
|
-
sub_dir="corsika_sim_telarray" if use_multipipe else "corsika",
|
|
822
|
-
)
|
|
823
|
-
return self.get_corsika_config_file_name(file_type="output_generic")
|
|
824
|
-
|
|
825
|
-
def _write_seeds(self, file, use_test_seeds=False):
|
|
744
|
+
def _write_seeds(self, file):
|
|
826
745
|
"""
|
|
827
746
|
Generate and write seeds in the CORSIKA input file.
|
|
828
747
|
|
|
748
|
+
CORSIKA seeds consist of 4 integers.
|
|
749
|
+
|
|
829
750
|
Parameters
|
|
830
751
|
----------
|
|
831
752
|
file: stream
|
|
832
753
|
File where the telescope positions will be written.
|
|
833
754
|
"""
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
if
|
|
838
|
-
|
|
755
|
+
corsika_seeds = settings.config.args.get("corsika_seeds", False)
|
|
756
|
+
if not corsika_seeds:
|
|
757
|
+
corsika_seeds = seeds(n_seeds=4, max_seed=CORSIKA_MAX_SEED)
|
|
758
|
+
if len(corsika_seeds) != 4:
|
|
759
|
+
raise ValueError("Exactly 4 CORSIKA seeds must be provided.")
|
|
839
760
|
for s in corsika_seeds:
|
|
840
761
|
file.write(f"SEED {s} 0 0\n")
|
|
841
762
|
|
|
@@ -862,46 +783,23 @@ class CorsikaConfig:
|
|
|
862
783
|
|
|
863
784
|
return corsika_input_list
|
|
864
785
|
|
|
865
|
-
|
|
866
|
-
def run_number(self):
|
|
867
|
-
"""Set run number."""
|
|
868
|
-
return self._run_number
|
|
869
|
-
|
|
870
|
-
@run_number.setter
|
|
871
|
-
def run_number(self, run_number):
|
|
872
|
-
"""
|
|
873
|
-
Set run number and validate it.
|
|
874
|
-
|
|
875
|
-
Parameters
|
|
876
|
-
----------
|
|
877
|
-
run_number: int
|
|
878
|
-
Run number.
|
|
879
|
-
"""
|
|
880
|
-
self._run_number = self.validate_run_number(run_number)
|
|
881
|
-
|
|
882
|
-
def validate_run_number(self, run_number):
|
|
786
|
+
def is_calibration_run(self):
|
|
883
787
|
"""
|
|
884
|
-
|
|
788
|
+
Check if this simulation is a calibration run.
|
|
885
789
|
|
|
886
790
|
Parameters
|
|
887
791
|
----------
|
|
888
|
-
|
|
889
|
-
Run
|
|
792
|
+
run_mode: str
|
|
793
|
+
Run mode of the simulation.
|
|
890
794
|
|
|
891
795
|
Returns
|
|
892
796
|
-------
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
return self.run_number
|
|
903
|
-
if not float(run_number).is_integer() or run_number < 1 or run_number > 999999:
|
|
904
|
-
raise ValueError(
|
|
905
|
-
f"Invalid type of run number ({run_number}) - it must be an uint < 1000000."
|
|
906
|
-
)
|
|
907
|
-
return run_number
|
|
797
|
+
bool
|
|
798
|
+
True if it is a calibration run, False otherwise.
|
|
799
|
+
"""
|
|
800
|
+
return self.run_mode in [
|
|
801
|
+
"pedestals",
|
|
802
|
+
"pedestals_dark",
|
|
803
|
+
"pedestals_nsb_only",
|
|
804
|
+
"direct_injection",
|
|
805
|
+
]
|