gammasimtools 0.22.0__py3-none-any.whl → 0.24.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.22.0.dist-info → gammasimtools-0.24.0.dist-info}/METADATA +2 -1
- {gammasimtools-0.22.0.dist-info → gammasimtools-0.24.0.dist-info}/RECORD +128 -125
- simtools/_version.py +2 -2
- simtools/application_control.py +118 -0
- simtools/applications/calculate_incident_angles.py +17 -22
- simtools/applications/convert_all_model_parameters_from_simtel.py +28 -43
- simtools/applications/convert_geo_coordinates_of_array_elements.py +26 -45
- simtools/applications/convert_model_parameter_from_simtel.py +21 -41
- simtools/applications/db_add_file_to_db.py +13 -14
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +20 -33
- simtools/applications/db_add_value_from_json_to_db.py +29 -24
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +20 -35
- simtools/applications/db_generate_compound_indexes.py +11 -13
- simtools/applications/db_get_array_layouts_from_db.py +20 -40
- simtools/applications/db_get_file_from_db.py +15 -17
- simtools/applications/db_get_parameter_from_db.py +33 -35
- simtools/applications/db_inspect_databases.py +13 -12
- simtools/applications/db_upload_model_repository.py +13 -31
- simtools/applications/derive_ctao_array_layouts.py +16 -21
- simtools/applications/derive_mirror_rnda.py +9 -14
- simtools/applications/derive_photon_electron_spectrum.py +7 -10
- simtools/applications/derive_psf_parameters.py +13 -20
- simtools/applications/derive_trigger_rates.py +6 -9
- simtools/applications/docs_produce_array_element_report.py +22 -23
- simtools/applications/docs_produce_calibration_reports.py +26 -24
- simtools/applications/docs_produce_model_parameter_reports.py +15 -22
- simtools/applications/docs_produce_simulation_configuration_report.py +21 -22
- simtools/applications/generate_array_config.py +14 -33
- simtools/applications/generate_corsika_histograms.py +22 -43
- simtools/applications/generate_default_metadata.py +15 -36
- simtools/applications/generate_regular_arrays.py +11 -15
- simtools/applications/generate_simtel_event_data.py +23 -33
- simtools/applications/maintain_simulation_model_add_production.py +20 -37
- simtools/applications/maintain_simulation_model_compare_productions.py +10 -12
- simtools/applications/maintain_simulation_model_verify_production_tables.py +8 -11
- simtools/applications/merge_tables.py +14 -23
- simtools/applications/plot_array_layout.py +77 -54
- simtools/applications/plot_simtel_events.py +11 -13
- simtools/applications/plot_tabular_data.py +17 -38
- simtools/applications/plot_tabular_data_for_model_parameter.py +16 -23
- simtools/applications/print_version.py +14 -42
- simtools/applications/production_derive_corsika_limits.py +5 -9
- simtools/applications/production_derive_statistics.py +12 -25
- simtools/applications/production_generate_grid.py +20 -48
- simtools/applications/production_merge_corsika_limits.py +17 -21
- simtools/applications/run_application.py +12 -32
- simtools/applications/simulate_flasher.py +21 -25
- simtools/applications/simulate_illuminator.py +7 -14
- simtools/applications/simulate_pedestals.py +13 -13
- simtools/applications/simulate_prod.py +21 -33
- simtools/applications/simulate_prod_htcondor_generator.py +11 -25
- simtools/applications/submit_array_layouts.py +16 -19
- simtools/applications/submit_data_from_external.py +18 -34
- simtools/applications/submit_model_parameter_from_external.py +27 -40
- simtools/applications/validate_camera_efficiency.py +23 -21
- simtools/applications/validate_camera_fov.py +21 -26
- simtools/applications/validate_cumulative_psf.py +27 -35
- simtools/applications/validate_file_using_schema.py +15 -33
- simtools/applications/validate_optics.py +27 -33
- simtools/camera/camera_efficiency.py +0 -2
- simtools/configuration/commandline_parser.py +39 -13
- simtools/configuration/configurator.py +1 -6
- simtools/corsika/corsika_config.py +2 -9
- simtools/data_model/data_reader.py +0 -2
- simtools/data_model/metadata_collector.py +0 -2
- simtools/data_model/model_data_writer.py +1 -3
- simtools/data_model/schema.py +36 -34
- simtools/data_model/validate_data.py +0 -2
- simtools/db/db_handler.py +61 -296
- simtools/db/db_model_upload.py +1 -1
- simtools/db/mongo_db.py +535 -0
- simtools/dependencies.py +33 -8
- simtools/io/hdf5_handler.py +0 -5
- simtools/io/legacy_data_handler.py +0 -5
- simtools/job_execution/job_manager.py +0 -3
- simtools/layout/array_layout.py +7 -9
- simtools/layout/array_layout_utils.py +3 -3
- simtools/layout/telescope_position.py +0 -2
- simtools/model/array_model.py +38 -71
- simtools/model/calibration_model.py +12 -11
- simtools/model/camera.py +0 -2
- simtools/model/mirrors.py +0 -2
- simtools/model/model_parameter.py +200 -140
- simtools/model/model_repository.py +159 -35
- simtools/model/model_utils.py +3 -8
- simtools/model/site_model.py +59 -29
- simtools/model/telescope_model.py +21 -15
- simtools/production_configuration/calculate_statistical_uncertainties_grid_point.py +0 -2
- simtools/production_configuration/derive_production_statistics.py +0 -2
- simtools/production_configuration/interpolation_handler.py +0 -2
- simtools/ray_tracing/mirror_panel_psf.py +4 -4
- simtools/ray_tracing/psf_analysis.py +0 -2
- simtools/ray_tracing/psf_parameter_optimisation.py +1 -1
- simtools/ray_tracing/ray_tracing.py +0 -2
- simtools/reporting/docs_auto_report_generator.py +109 -1
- simtools/reporting/docs_read_parameters.py +4 -9
- simtools/runners/corsika_runner.py +0 -2
- simtools/runners/corsika_simtel_runner.py +0 -2
- simtools/runners/simtel_runner.py +0 -2
- simtools/schemas/model_parameters/transit_time_random.schema.yml +29 -0
- simtools/schemas/simulation_models_info.schema.yml +2 -1
- simtools/simtel/simtel_config_reader.py +0 -2
- simtools/simtel/simtel_config_writer.py +128 -33
- simtools/simtel/simtel_io_metadata.py +3 -3
- simtools/simtel/simulator_array.py +9 -21
- simtools/simtel/simulator_camera_efficiency.py +0 -2
- simtools/simtel/simulator_light_emission.py +1 -3
- simtools/simtel/simulator_ray_tracing.py +0 -2
- simtools/simulator.py +2 -6
- simtools/testing/assertions.py +52 -8
- simtools/testing/configuration.py +17 -4
- simtools/testing/validate_output.py +4 -8
- simtools/utils/general.py +5 -13
- simtools/utils/geometry.py +0 -5
- simtools/utils/names.py +1 -13
- simtools/utils/value_conversion.py +10 -5
- simtools/version.py +85 -0
- simtools/visualization/plot_array_layout.py +129 -23
- simtools/visualization/plot_incident_angles.py +0 -2
- simtools/visualization/plot_pixels.py +1 -1
- simtools/visualization/plot_psf.py +1 -1
- simtools/visualization/plot_simtel_events.py +0 -11
- simtools/visualization/plot_tables.py +1 -1
- simtools/visualization/visualize.py +0 -12
- {gammasimtools-0.22.0.dist-info → gammasimtools-0.24.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.22.0.dist-info → gammasimtools-0.24.0.dist-info}/entry_points.txt +0 -0
- {gammasimtools-0.22.0.dist-info → gammasimtools-0.24.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.22.0.dist-info → gammasimtools-0.24.0.dist-info}/top_level.txt +0 -0
|
@@ -19,7 +19,7 @@ class ReportGenerator:
|
|
|
19
19
|
def __init__(self, db_config, args, output_path):
|
|
20
20
|
"""Initialise class."""
|
|
21
21
|
self._logger = logging.getLogger(__name__)
|
|
22
|
-
self.db = db_handler.DatabaseHandler(
|
|
22
|
+
self.db = db_handler.DatabaseHandler(db_config=db_config)
|
|
23
23
|
self.db_config = db_config
|
|
24
24
|
self.args = args
|
|
25
25
|
self.output_path = output_path
|
|
@@ -175,6 +175,10 @@ class ReportGenerator:
|
|
|
175
175
|
f"Markdown report generated for {site} Telescope {telescope}: {self.output_path}"
|
|
176
176
|
)
|
|
177
177
|
|
|
178
|
+
# Also generate calibration device parameter comparison reports when using --all_telescopes
|
|
179
|
+
if self.args.get("all_telescopes"):
|
|
180
|
+
self._generate_calibration_device_parameter_reports()
|
|
181
|
+
|
|
178
182
|
def _generate_observatory_report_combinations(self) -> Generator[tuple[str, str], None, None]:
|
|
179
183
|
"""Generate combinations of sites and model versions for observatory reports.
|
|
180
184
|
|
|
@@ -215,3 +219,107 @@ class ReportGenerator:
|
|
|
215
219
|
"""Generate all observatory reports based on which --all_* flags are passed."""
|
|
216
220
|
for params in self._generate_observatory_report_combinations():
|
|
217
221
|
self._generate_single_observatory_report(*params)
|
|
222
|
+
|
|
223
|
+
def auto_generate_simulation_configuration_reports(self):
|
|
224
|
+
"""Generate simulation configuration reports for one or all model versions.
|
|
225
|
+
|
|
226
|
+
If --all_model_versions is set, produce reports for every model version in
|
|
227
|
+
the DB; otherwise produce reports only for the configured model_version.
|
|
228
|
+
"""
|
|
229
|
+
model_versions = (
|
|
230
|
+
self.db.get_model_versions()
|
|
231
|
+
if self.args.get("all_model_versions")
|
|
232
|
+
else [self.args["model_version"]]
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
for version in model_versions:
|
|
236
|
+
# update args and create a per-version output directory
|
|
237
|
+
self.args.update({"model_version": version})
|
|
238
|
+
output_path = Path(self.output_path) / str(version)
|
|
239
|
+
|
|
240
|
+
ReadParameters(
|
|
241
|
+
self.db_config, self.args, output_path
|
|
242
|
+
).produce_simulation_configuration_report()
|
|
243
|
+
|
|
244
|
+
logger.info(f"Configuration reports for (v{version}) produced: {output_path}")
|
|
245
|
+
|
|
246
|
+
def auto_generate_calibration_reports(self):
|
|
247
|
+
"""Generate calibration reports for one or all model versions.
|
|
248
|
+
|
|
249
|
+
Mirrors the pattern used by other auto_generate_* methods: if
|
|
250
|
+
--all_model_versions is set, produce reports for every model version in
|
|
251
|
+
the DB; otherwise produce reports only for the configured model_version.
|
|
252
|
+
"""
|
|
253
|
+
model_versions = (
|
|
254
|
+
self.db.get_model_versions()
|
|
255
|
+
if self.args.get("all_model_versions")
|
|
256
|
+
else [self.args["model_version"]]
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
for version in model_versions:
|
|
260
|
+
# update args and create a per-version output directory
|
|
261
|
+
self.args.update({"model_version": version})
|
|
262
|
+
output_path = Path(self.output_path) / str(version)
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
ReadParameters(self.db_config, self.args, output_path).produce_calibration_reports()
|
|
266
|
+
logger.info(f"Calibration reports for (v{version}) produced: {output_path}")
|
|
267
|
+
except ValueError as err:
|
|
268
|
+
# Some model versions do not have calibration_devices in the DB;
|
|
269
|
+
msg = str(err)
|
|
270
|
+
if "calibration_devices" in msg and "zero results" in msg:
|
|
271
|
+
logger.info(
|
|
272
|
+
f"Skipping model version {version}: no calibration devices defined ({msg})"
|
|
273
|
+
)
|
|
274
|
+
continue
|
|
275
|
+
# re-raise unexpected ValueErrors
|
|
276
|
+
raise
|
|
277
|
+
|
|
278
|
+
def _generate_calibration_device_parameter_reports(self):
|
|
279
|
+
"""Generate parameter comparison reports for calibration devices for all model versions."""
|
|
280
|
+
# Get all model versions since no specific version is provided when using --all_telescopes
|
|
281
|
+
model_versions = self.db.get_model_versions()
|
|
282
|
+
|
|
283
|
+
for version in model_versions:
|
|
284
|
+
self._process_calibration_devices_for_version(version)
|
|
285
|
+
|
|
286
|
+
def _process_calibration_devices_for_version(self, version):
|
|
287
|
+
"""Process calibration devices for a specific model version."""
|
|
288
|
+
try:
|
|
289
|
+
# Get all calibration devices for this version
|
|
290
|
+
calibration_array_elements = self.db.get_array_elements(
|
|
291
|
+
version, collection="calibration_devices"
|
|
292
|
+
)
|
|
293
|
+
array_elements = calibration_array_elements.copy()
|
|
294
|
+
|
|
295
|
+
# Add design models
|
|
296
|
+
for element in calibration_array_elements:
|
|
297
|
+
design_model = self.db.get_design_model(version, element, "calibration_devices")
|
|
298
|
+
if design_model and design_model not in array_elements:
|
|
299
|
+
array_elements.append(design_model)
|
|
300
|
+
|
|
301
|
+
if array_elements:
|
|
302
|
+
# Create a copy of args with the current version for this iteration
|
|
303
|
+
version_args = self.args.copy()
|
|
304
|
+
version_args["model_version"] = version
|
|
305
|
+
|
|
306
|
+
# Generate parameter comparison reports for calibration devices
|
|
307
|
+
ReadParameters(
|
|
308
|
+
self.db_config, version_args, self.output_path
|
|
309
|
+
).generate_model_parameter_reports_for_devices(array_elements)
|
|
310
|
+
|
|
311
|
+
logger.info(
|
|
312
|
+
"Calibration device parameter reports generated for"
|
|
313
|
+
f" v{version}: {self.output_path}"
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
except ValueError as err:
|
|
317
|
+
# Some model versions may not have calibration_devices
|
|
318
|
+
msg = str(err)
|
|
319
|
+
if "calibration_devices" in msg and "zero results" in msg:
|
|
320
|
+
logger.info(
|
|
321
|
+
f"Skipping model version {version}: no calibration devices defined ({msg})"
|
|
322
|
+
)
|
|
323
|
+
return
|
|
324
|
+
# re-raise unexpected ValueErrors
|
|
325
|
+
raise
|
|
@@ -29,7 +29,7 @@ class ReadParameters:
|
|
|
29
29
|
def __init__(self, db_config, args, output_path):
|
|
30
30
|
"""Initialise class."""
|
|
31
31
|
self._logger = logging.getLogger(__name__)
|
|
32
|
-
self.db = db_handler.DatabaseHandler(
|
|
32
|
+
self.db = db_handler.DatabaseHandler(db_config=db_config)
|
|
33
33
|
self.db_config = db_config
|
|
34
34
|
self.array_element = args.get("telescope", None)
|
|
35
35
|
self.site = args.get("site", None)
|
|
@@ -543,7 +543,8 @@ class ReadParameters:
|
|
|
543
543
|
telescope_name=self.array_element,
|
|
544
544
|
model_version=self.model_version,
|
|
545
545
|
label="reports",
|
|
546
|
-
|
|
546
|
+
db_config=self.db_config,
|
|
547
|
+
ignore_software_version=True,
|
|
547
548
|
)
|
|
548
549
|
|
|
549
550
|
output_filename = Path(self.output_path / (telescope_model.name + ".md"))
|
|
@@ -896,9 +897,6 @@ class ReadParameters:
|
|
|
896
897
|
output_filename, calibration_device, data, design_model
|
|
897
898
|
)
|
|
898
899
|
|
|
899
|
-
# produce parameter comparison reports (site-independent)
|
|
900
|
-
self._generate_model_parameter_reports_for_devices(array_elements)
|
|
901
|
-
|
|
902
900
|
def _collect_calibration_array_elements(self):
|
|
903
901
|
"""Return a list of calibration devices including their design models."""
|
|
904
902
|
calibration_array_elements = self.db.get_array_elements(
|
|
@@ -954,11 +952,8 @@ class ReadParameters:
|
|
|
954
952
|
|
|
955
953
|
self._write_to_file(display_group, file)
|
|
956
954
|
|
|
957
|
-
def
|
|
955
|
+
def generate_model_parameter_reports_for_devices(self, array_elements):
|
|
958
956
|
"""Create model-parameter comparison reports for calibration devices."""
|
|
959
|
-
new_output_path = Path(self.output_path).parent.parent / "parameters"
|
|
960
|
-
new_output_path.mkdir(parents=True, exist_ok=True)
|
|
961
|
-
self.output_path = new_output_path
|
|
962
957
|
for calibration_device in array_elements:
|
|
963
958
|
device_sites = names.get_site_from_array_element_name(calibration_device)
|
|
964
959
|
# parameters are site independent so just take the first site to read from db
|
|
@@ -7,8 +7,6 @@ from pathlib import Path
|
|
|
7
7
|
from simtools.io import io_handler
|
|
8
8
|
from simtools.runners.runner_services import RunnerServices
|
|
9
9
|
|
|
10
|
-
__all__ = ["CorsikaRunner", "MissingRequiredEntryInCorsikaConfigError"]
|
|
11
|
-
|
|
12
10
|
|
|
13
11
|
class MissingRequiredEntryInCorsikaConfigError(Exception):
|
|
14
12
|
"""Exception for missing required entry in corsika config."""
|
|
@@ -8,8 +8,6 @@ from pathlib import Path
|
|
|
8
8
|
import simtools.utils.general as gen
|
|
9
9
|
from simtools.runners.runner_services import RunnerServices
|
|
10
10
|
|
|
11
|
-
__all__ = ["InvalidOutputFileError", "SimtelExecutionError", "SimtelRunner"]
|
|
12
|
-
|
|
13
11
|
|
|
14
12
|
class SimtelExecutionError(Exception):
|
|
15
13
|
"""Exception for sim_telarray execution error."""
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
%YAML 1.2
|
|
2
|
+
---
|
|
3
|
+
title: Schema for transit_time_random model parameter
|
|
4
|
+
schema_version: 0.1.0
|
|
5
|
+
meta_schema: simpipe-schema
|
|
6
|
+
meta_schema_url: https://raw.githubusercontent.com/gammasim/simtools/main/src/simtools/schemas/model_parameter_and_data_schema.metaschema.yml
|
|
7
|
+
meta_schema_version: 0.1.0
|
|
8
|
+
name: transit_time_random
|
|
9
|
+
description: Event-wise and pixel-wise random fluctuations in the signal transit time.
|
|
10
|
+
data:
|
|
11
|
+
- type: float64
|
|
12
|
+
unit: ns
|
|
13
|
+
default: 0.
|
|
14
|
+
allowed_range:
|
|
15
|
+
min: 0.0
|
|
16
|
+
instrument:
|
|
17
|
+
class: Camera
|
|
18
|
+
activity:
|
|
19
|
+
setting:
|
|
20
|
+
- SetParameterFromExternal
|
|
21
|
+
validation:
|
|
22
|
+
- ValidateParameterByExpert
|
|
23
|
+
- ValidateCameraTimeResponse
|
|
24
|
+
source:
|
|
25
|
+
- Initial instrument setup
|
|
26
|
+
simulation_software:
|
|
27
|
+
- name: sim_telarray
|
|
28
|
+
- name: simtools
|
|
29
|
+
version: ">=0.22.0"
|
|
@@ -14,11 +14,12 @@ definitions:
|
|
|
14
14
|
model_version:
|
|
15
15
|
$ref: 'common_definitions.schema.yml#/$defs/semantic_version_pattern'
|
|
16
16
|
model_update:
|
|
17
|
-
type: string
|
|
17
|
+
type: [string, 'null']
|
|
18
18
|
description: The type of update for the model version.
|
|
19
19
|
enum:
|
|
20
20
|
- patch_update
|
|
21
21
|
- full_update
|
|
22
|
+
- null
|
|
22
23
|
model_version_history:
|
|
23
24
|
type: array
|
|
24
25
|
description: A list of previous model versions.
|
|
@@ -13,8 +13,6 @@ import simtools.version
|
|
|
13
13
|
from simtools.io import ascii_handler
|
|
14
14
|
from simtools.utils import names
|
|
15
15
|
|
|
16
|
-
__all__ = ["SimtelConfigWriter"]
|
|
17
|
-
|
|
18
16
|
|
|
19
17
|
def sim_telarray_random_seeds(seed, number):
|
|
20
18
|
"""
|
|
@@ -67,6 +65,7 @@ class SimtelConfigWriter:
|
|
|
67
65
|
model_version,
|
|
68
66
|
layout_name=None,
|
|
69
67
|
telescope_model_name=None,
|
|
68
|
+
telescope_design_model=None,
|
|
70
69
|
label=None,
|
|
71
70
|
simtel_path=None,
|
|
72
71
|
):
|
|
@@ -79,9 +78,12 @@ class SimtelConfigWriter:
|
|
|
79
78
|
self._label = label
|
|
80
79
|
self._layout_name = layout_name
|
|
81
80
|
self._telescope_model_name = telescope_model_name
|
|
81
|
+
self._telescope_design_model = telescope_design_model
|
|
82
82
|
self._simtel_path = simtel_path
|
|
83
83
|
|
|
84
|
-
def write_telescope_config_file(
|
|
84
|
+
def write_telescope_config_file(
|
|
85
|
+
self, config_file_path, parameters, telescope_name=None, telescope_design_model=None
|
|
86
|
+
):
|
|
85
87
|
"""
|
|
86
88
|
Write the sim_telarray config file for a single telescope.
|
|
87
89
|
|
|
@@ -93,22 +95,30 @@ class SimtelConfigWriter:
|
|
|
93
95
|
Model parameters
|
|
94
96
|
telescope_name: str
|
|
95
97
|
Name of the telescope (use self._telescope_model_name if None)
|
|
98
|
+
telescope_design_model: str
|
|
99
|
+
Telescope design model.
|
|
96
100
|
"""
|
|
97
101
|
self._logger.debug(f"Writing telescope config file {config_file_path}")
|
|
98
102
|
|
|
99
103
|
simtel_par = self._get_parameters_for_sim_telarray(parameters, config_file_path)
|
|
104
|
+
telescope_name = telescope_name or self._telescope_model_name
|
|
105
|
+
_telescope_design_model = telescope_design_model or self._telescope_design_model
|
|
100
106
|
|
|
101
107
|
with open(config_file_path, "w", encoding="utf-8") as file:
|
|
102
108
|
self._write_header(file, "TELESCOPE CONFIGURATION FILE")
|
|
103
109
|
|
|
104
|
-
telescope_name = telescope_name or self._telescope_model_name
|
|
105
110
|
file.write("#ifdef TELESCOPE\n")
|
|
106
111
|
file.write(f" echo Configuration for {telescope_name} - TELESCOPE $(TELESCOPE)\n")
|
|
107
112
|
file.write("#endif\n\n")
|
|
108
113
|
|
|
109
114
|
for simtel_name, simtel_value in simtel_par.items():
|
|
110
115
|
file.write(f"{simtel_name} = {self._get_value_string_for_simtel(simtel_value)}\n")
|
|
111
|
-
for meta in self._get_sim_telarray_metadata(
|
|
116
|
+
for meta in self._get_sim_telarray_metadata(
|
|
117
|
+
"telescope",
|
|
118
|
+
parameters,
|
|
119
|
+
telescope_name,
|
|
120
|
+
telescope_design_model=_telescope_design_model,
|
|
121
|
+
):
|
|
112
122
|
file.write(f"{meta}\n")
|
|
113
123
|
|
|
114
124
|
def _get_parameters_for_sim_telarray(self, parameters, config_file_path):
|
|
@@ -211,12 +221,17 @@ class SimtelConfigWriter:
|
|
|
211
221
|
value = "none" if value is None else value # simtel requires 'none'
|
|
212
222
|
if isinstance(value, bool):
|
|
213
223
|
value = 1 if value else 0
|
|
214
|
-
elif isinstance(value, (list, np.ndarray)):
|
|
224
|
+
elif isinstance(value, (list, np.ndarray)):
|
|
215
225
|
value = gen.convert_list_to_string(value, shorten_list=True)
|
|
216
226
|
return value
|
|
217
227
|
|
|
218
228
|
def _get_sim_telarray_metadata(
|
|
219
|
-
self,
|
|
229
|
+
self,
|
|
230
|
+
config_type,
|
|
231
|
+
model_parameters,
|
|
232
|
+
telescope_model_name,
|
|
233
|
+
additional_metadata=None,
|
|
234
|
+
telescope_design_model=None,
|
|
220
235
|
):
|
|
221
236
|
"""
|
|
222
237
|
Return sim_telarray metadata.
|
|
@@ -231,6 +246,8 @@ class SimtelConfigWriter:
|
|
|
231
246
|
Name of the telescope model
|
|
232
247
|
additional_metadata: dict
|
|
233
248
|
Dictionary with additional metadata to include using 'set'.
|
|
249
|
+
telescope_design_model: str
|
|
250
|
+
Name of the telescope design model.
|
|
234
251
|
|
|
235
252
|
Returns
|
|
236
253
|
-------
|
|
@@ -241,14 +258,15 @@ class SimtelConfigWriter:
|
|
|
241
258
|
f"config_release = {self._model_version} with simtools v{simtools.version.__version__}",
|
|
242
259
|
f"config_version = {self._model_version}",
|
|
243
260
|
]
|
|
261
|
+
telescope_design_model = telescope_design_model or "design_model_not_set"
|
|
244
262
|
if config_type == "telescope":
|
|
245
263
|
meta_parameters.extend(
|
|
246
264
|
[
|
|
247
|
-
f"camera_config_name = {
|
|
248
|
-
"camera_config_variant = ",
|
|
265
|
+
f"camera_config_name = {telescope_design_model}",
|
|
266
|
+
f"camera_config_variant = {telescope_model_name}",
|
|
249
267
|
f"camera_config_version = {self._model_version}",
|
|
250
|
-
f"optics_config_name = {
|
|
251
|
-
"optics_config_variant = ",
|
|
268
|
+
f"optics_config_name = {telescope_design_model}",
|
|
269
|
+
f"optics_config_variant = {telescope_model_name}",
|
|
252
270
|
f"optics_config_version = {self._model_version}",
|
|
253
271
|
]
|
|
254
272
|
)
|
|
@@ -510,7 +528,7 @@ class SimtelConfigWriter:
|
|
|
510
528
|
"""
|
|
511
529
|
file.write(self.TAB + "% Site parameters\n")
|
|
512
530
|
for par, value in site_parameters.items():
|
|
513
|
-
simtel_name,
|
|
531
|
+
simtel_name, simtel_value = self._convert_model_parameters_to_simtel_format(
|
|
514
532
|
names.get_simulation_software_name_from_parameter_name(
|
|
515
533
|
par, software_name="sim_telarray"
|
|
516
534
|
),
|
|
@@ -519,9 +537,9 @@ class SimtelConfigWriter:
|
|
|
519
537
|
telescope_model,
|
|
520
538
|
)
|
|
521
539
|
if simtel_name is not None:
|
|
522
|
-
file.write(f"{self.TAB}{simtel_name} = {
|
|
540
|
+
file.write(f"{self.TAB}{simtel_name} = {simtel_value}\n")
|
|
523
541
|
for meta in self._get_sim_telarray_metadata(
|
|
524
|
-
"site", site_parameters,
|
|
542
|
+
"site", site_parameters, None, additional_metadata
|
|
525
543
|
):
|
|
526
544
|
file.write(f"{self.TAB}{meta}\n")
|
|
527
545
|
file.write("\n")
|
|
@@ -574,34 +592,111 @@ class SimtelConfigWriter:
|
|
|
574
592
|
telescope_model: dict of TelescopeModel
|
|
575
593
|
Telescope models.
|
|
576
594
|
"""
|
|
595
|
+
trigger_per_telescope_type = self._group_telescopes_by_type(telescope_model)
|
|
596
|
+
hardstereo_lines, non_hardstereo_groups, all_non_hardstereo_tels, multiplicity = (
|
|
597
|
+
self._process_telescope_triggers(array_triggers, trigger_per_telescope_type)
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
array_triggers_file = "array_triggers.dat"
|
|
601
|
+
with open(model_path / array_triggers_file, "w", encoding="utf-8") as file:
|
|
602
|
+
file.write("# Array trigger definition\n")
|
|
603
|
+
self._write_trigger_lines(
|
|
604
|
+
file, hardstereo_lines, non_hardstereo_groups, all_non_hardstereo_tels, multiplicity
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
return array_triggers_file
|
|
608
|
+
|
|
609
|
+
def _group_telescopes_by_type(self, telescope_model):
|
|
610
|
+
"""Group telescopes by their type."""
|
|
577
611
|
trigger_per_telescope_type = {}
|
|
578
612
|
for count, tel_name in enumerate(telescope_model.keys()):
|
|
579
613
|
telescope_type = names.get_array_element_type_from_name(tel_name)
|
|
580
614
|
trigger_per_telescope_type.setdefault(telescope_type, []).append(count + 1)
|
|
615
|
+
return trigger_per_telescope_type
|
|
616
|
+
|
|
617
|
+
def _process_telescope_triggers(self, array_triggers, trigger_per_telescope_type):
|
|
618
|
+
"""Process telescope triggers and group them by hardstereo and parameters."""
|
|
619
|
+
hardstereo_lines = []
|
|
620
|
+
non_hardstereo_groups = {}
|
|
621
|
+
all_non_hardstereo_tels = []
|
|
622
|
+
multiplicity = None
|
|
581
623
|
|
|
582
|
-
trigger_lines = {}
|
|
583
624
|
for tel_type, tel_list in trigger_per_telescope_type.items():
|
|
584
625
|
trigger_dict = self._get_array_triggers_for_telescope_type(
|
|
585
626
|
array_triggers, tel_type, len(tel_list)
|
|
586
627
|
)
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
628
|
+
width, minsep = self._extract_trigger_parameters(trigger_dict)
|
|
629
|
+
multiplicity = trigger_dict["multiplicity"]["value"] # Store for later use
|
|
630
|
+
|
|
631
|
+
if trigger_dict.get("hard_stereo", {}).get("value"):
|
|
632
|
+
line = self._build_trigger_line(
|
|
633
|
+
trigger_dict, tel_list, width, minsep, hardstereo=True
|
|
634
|
+
)
|
|
635
|
+
hardstereo_lines.append(line)
|
|
636
|
+
else:
|
|
637
|
+
key = (width, minsep)
|
|
638
|
+
non_hardstereo_groups.setdefault(key, []).extend(tel_list)
|
|
639
|
+
all_non_hardstereo_tels.extend(tel_list)
|
|
640
|
+
|
|
641
|
+
return hardstereo_lines, non_hardstereo_groups, all_non_hardstereo_tels, multiplicity
|
|
642
|
+
|
|
643
|
+
def _extract_trigger_parameters(self, trigger_dict):
|
|
644
|
+
"""Extract width and min_separation parameters from trigger dictionary."""
|
|
645
|
+
width = trigger_dict["width"]["value"] * u.Unit(trigger_dict["width"]["unit"]).to("ns")
|
|
646
|
+
minsep = None
|
|
647
|
+
if all(trigger_dict["min_separation"][key] is not None for key in ["value", "unit"]):
|
|
648
|
+
minsep = trigger_dict["min_separation"]["value"] * u.Unit(
|
|
649
|
+
trigger_dict["min_separation"]["unit"]
|
|
650
|
+
).to("m")
|
|
651
|
+
return width, minsep
|
|
652
|
+
|
|
653
|
+
def _build_trigger_line(self, trigger_dict, tel_list, width, minsep, hardstereo=False):
|
|
654
|
+
"""Build a trigger line string."""
|
|
655
|
+
line = f"Trigger {trigger_dict['multiplicity']['value']} of "
|
|
656
|
+
line += ", ".join(map(str, tel_list))
|
|
657
|
+
line += f" width {width}"
|
|
658
|
+
if hardstereo:
|
|
659
|
+
line += " hardstereo"
|
|
660
|
+
if minsep is not None:
|
|
661
|
+
line += f" minsep {minsep}"
|
|
662
|
+
return line
|
|
663
|
+
|
|
664
|
+
def _write_trigger_lines(
|
|
665
|
+
self, file, hardstereo_lines, non_hardstereo_groups, all_non_hardstereo_tels, multiplicity
|
|
666
|
+
):
|
|
667
|
+
"""Write all trigger lines to file."""
|
|
668
|
+
# Write hardstereo lines first
|
|
669
|
+
for line in hardstereo_lines:
|
|
670
|
+
file.write(f"{line}\n")
|
|
671
|
+
|
|
672
|
+
# Write individual non-hardstereo groups if they have different parameters
|
|
673
|
+
if len(non_hardstereo_groups) > 1:
|
|
674
|
+
for (width, minsep), tel_list in non_hardstereo_groups.items():
|
|
675
|
+
line = f"Trigger {multiplicity} of "
|
|
676
|
+
line += ", ".join(map(str, tel_list))
|
|
677
|
+
line += f" width {width}"
|
|
678
|
+
if minsep is not None:
|
|
679
|
+
line += f" minsep {minsep}"
|
|
680
|
+
file.write(f"{line}\n")
|
|
681
|
+
|
|
682
|
+
# Write combined line with all non-hardstereo telescopes using shortest values
|
|
683
|
+
if all_non_hardstereo_tels:
|
|
684
|
+
min_width = min(width for width, minsep in non_hardstereo_groups.keys())
|
|
685
|
+
min_minsep = self._get_minimum_minsep(non_hardstereo_groups)
|
|
686
|
+
|
|
687
|
+
combined_line = f"Trigger {multiplicity} of "
|
|
688
|
+
combined_line += ", ".join(map(str, sorted(all_non_hardstereo_tels)))
|
|
689
|
+
combined_line += f" width {min_width}"
|
|
690
|
+
if min_minsep is not None:
|
|
691
|
+
combined_line += f" minsep {min_minsep}"
|
|
692
|
+
file.write(f"{combined_line}\n")
|
|
693
|
+
|
|
694
|
+
def _get_minimum_minsep(self, non_hardstereo_groups):
|
|
695
|
+
"""Get minimum min_separation value from groups."""
|
|
696
|
+
minsep_values = [
|
|
697
|
+
minsep for width, minsep in non_hardstereo_groups.keys() if minsep is not None
|
|
698
|
+
]
|
|
699
|
+
return min(minsep_values) if minsep_values else None
|
|
605
700
|
|
|
606
701
|
def _get_array_triggers_for_telescope_type(
|
|
607
702
|
self, array_triggers, telescope_type, num_telescopes_of_type
|
|
@@ -105,8 +105,8 @@ def get_sim_telarray_telescope_id(telescope_name, file):
|
|
|
105
105
|
_, telescope_meta = read_sim_telarray_metadata(file)
|
|
106
106
|
telescope_name_to_sim_telarray_id = {}
|
|
107
107
|
for tel_id in telescope_meta.keys():
|
|
108
|
-
_optics_name = telescope_meta[tel_id].get("
|
|
109
|
-
_camera_name = telescope_meta[tel_id].get("
|
|
108
|
+
_optics_name = telescope_meta[tel_id].get("optics_config_variant", None)
|
|
109
|
+
_camera_name = telescope_meta[tel_id].get("camera_config_variant", None)
|
|
110
110
|
if _optics_name == _camera_name and _optics_name == telescope_name:
|
|
111
111
|
telescope_name_to_sim_telarray_id[telescope_name] = tel_id
|
|
112
112
|
|
|
@@ -132,7 +132,7 @@ def get_sim_telarray_telescope_id_to_telescope_name_mapping(file):
|
|
|
132
132
|
for i, (tel_id, meta) in enumerate(telescope_meta.items()):
|
|
133
133
|
try:
|
|
134
134
|
telescope_name = names.validate_array_element_name(
|
|
135
|
-
meta.get("
|
|
135
|
+
meta.get("optics_config_variant", f"Unknown-{tel_id}")
|
|
136
136
|
)
|
|
137
137
|
except ValueError:
|
|
138
138
|
telescope_name = _guess_telescope_name_for_legacy_files(i, file)
|
|
@@ -6,8 +6,6 @@ from simtools.io import io_handler
|
|
|
6
6
|
from simtools.runners.simtel_runner import InvalidOutputFileError, SimtelRunner
|
|
7
7
|
from simtools.utils.general import clear_default_sim_telarray_cfg_directories
|
|
8
8
|
|
|
9
|
-
__all__ = ["SimulatorArray"]
|
|
10
|
-
|
|
11
9
|
|
|
12
10
|
class SimulatorArray(SimtelRunner):
|
|
13
11
|
"""
|
|
@@ -73,41 +71,33 @@ class SimulatorArray(SimtelRunner):
|
|
|
73
71
|
command = self._common_run_command(run_number, weak_pointing)
|
|
74
72
|
|
|
75
73
|
if self.calibration_config:
|
|
76
|
-
command += self._make_run_command_for_calibration_simulations(
|
|
74
|
+
command += self._make_run_command_for_calibration_simulations()
|
|
77
75
|
else:
|
|
78
|
-
command += self._make_run_command_for_shower_simulations(
|
|
76
|
+
command += self._make_run_command_for_shower_simulations()
|
|
77
|
+
|
|
78
|
+
# "-C show=all" should be the last option
|
|
79
|
+
command += super().get_config_option("show", "all")
|
|
80
|
+
command += f" {input_file} | gzip > {self._log_file} 2>&1 || exit"
|
|
79
81
|
|
|
80
82
|
return clear_default_sim_telarray_cfg_directories(command)
|
|
81
83
|
|
|
82
|
-
def _make_run_command_for_shower_simulations(self
|
|
84
|
+
def _make_run_command_for_shower_simulations(self):
|
|
83
85
|
"""
|
|
84
86
|
Build and return the command to run sim_telarray shower simulations.
|
|
85
87
|
|
|
86
|
-
Parameters
|
|
87
|
-
----------
|
|
88
|
-
input_file: str
|
|
89
|
-
Full path of the input CORSIKA file
|
|
90
|
-
run_number: int (optional)
|
|
91
|
-
run number
|
|
92
|
-
weak_pointing: bool (optional)
|
|
93
|
-
Specify weak pointing option for sim_telarray.
|
|
94
|
-
|
|
95
88
|
Returns
|
|
96
89
|
-------
|
|
97
90
|
str
|
|
98
91
|
Command to run sim_telarray.
|
|
99
92
|
"""
|
|
100
|
-
|
|
101
|
-
command += f" | gzip > {self._log_file} 2>&1 || exit"
|
|
102
|
-
command += super().get_config_option(
|
|
93
|
+
return super().get_config_option(
|
|
103
94
|
"power_law",
|
|
104
95
|
SimulatorArray.get_power_law_for_sim_telarray_histograms(
|
|
105
96
|
self.corsika_config.primary_particle
|
|
106
97
|
),
|
|
107
98
|
)
|
|
108
|
-
return command
|
|
109
99
|
|
|
110
|
-
def _make_run_command_for_calibration_simulations(self
|
|
100
|
+
def _make_run_command_for_calibration_simulations(self):
|
|
111
101
|
"""Build sim_telarray command for calibration simulations."""
|
|
112
102
|
cfg = self.calibration_config
|
|
113
103
|
altitude = self.corsika_config.array_model.site_model.get_parameter_value_with_unit(
|
|
@@ -133,7 +123,6 @@ class SimulatorArray(SimtelRunner):
|
|
|
133
123
|
n_events = cfg.get("number_of_flasher_events", cfg["number_of_events"])
|
|
134
124
|
command += super().get_config_option("laser_events", n_events)
|
|
135
125
|
|
|
136
|
-
command += f" {input_file} | gzip > {self._log_file} 2>&1 || exit"
|
|
137
126
|
return command
|
|
138
127
|
|
|
139
128
|
def _common_run_command(self, run_number, weak_pointing=None):
|
|
@@ -162,7 +151,6 @@ class SimulatorArray(SimtelRunner):
|
|
|
162
151
|
)
|
|
163
152
|
elif self.sim_telarray_seeds and self.sim_telarray_seeds.get("seed"):
|
|
164
153
|
command += super().get_config_option("random_seed", self.sim_telarray_seeds["seed"])
|
|
165
|
-
command += super().get_config_option("show", "all")
|
|
166
154
|
command += super().get_config_option("output_file", output_file)
|
|
167
155
|
|
|
168
156
|
return command
|
|
@@ -15,8 +15,6 @@ from simtools.runners.simtel_runner import SimtelRunner
|
|
|
15
15
|
from simtools.utils.general import clear_default_sim_telarray_cfg_directories
|
|
16
16
|
from simtools.utils.geometry import fiducial_radius_from_shape
|
|
17
17
|
|
|
18
|
-
__all__ = ["SimulatorLightEmission"]
|
|
19
|
-
|
|
20
18
|
|
|
21
19
|
class SimulatorLightEmission(SimtelRunner):
|
|
22
20
|
"""
|
|
@@ -41,7 +39,7 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
41
39
|
simtel_path=light_emission_config.get("simtel_path"), label=label, corsika_config=None
|
|
42
40
|
)
|
|
43
41
|
|
|
44
|
-
self.output_directory = self.io_handler.get_output_directory(
|
|
42
|
+
self.output_directory = self.io_handler.get_output_directory()
|
|
45
43
|
|
|
46
44
|
self.telescope_model, self.site_model, self.calibration_model = (
|
|
47
45
|
initialize_simulation_models(
|
|
@@ -10,8 +10,6 @@ from simtools.runners.simtel_runner import SimtelRunner
|
|
|
10
10
|
from simtools.utils import names
|
|
11
11
|
from simtools.utils.general import clear_default_sim_telarray_cfg_directories
|
|
12
12
|
|
|
13
|
-
__all__ = ["SimulatorRayTracing"]
|
|
14
|
-
|
|
15
13
|
# pylint: disable=no-member
|
|
16
14
|
# The line above is needed because there are members which are created
|
|
17
15
|
# by adding them to the __dict__ of the class rather than directly.
|