gammasimtools 0.26.0__py3-none-any.whl → 0.27.1__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.26.0.dist-info → gammasimtools-0.27.1.dist-info}/METADATA +5 -1
- {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.dist-info}/RECORD +70 -66
- {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.dist-info}/WHEEL +1 -1
- {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.dist-info}/entry_points.txt +1 -1
- simtools/_version.py +2 -2
- simtools/applications/convert_geo_coordinates_of_array_elements.py +2 -1
- simtools/applications/db_get_array_layouts_from_db.py +1 -1
- simtools/applications/{calculate_incident_angles.py → derive_incident_angle.py} +16 -16
- simtools/applications/derive_mirror_rnda.py +111 -177
- simtools/applications/generate_corsika_histograms.py +38 -1
- simtools/applications/generate_regular_arrays.py +73 -36
- simtools/applications/simulate_flasher.py +3 -13
- simtools/applications/simulate_illuminator.py +2 -10
- simtools/applications/simulate_pedestals.py +1 -1
- simtools/applications/simulate_prod.py +8 -7
- simtools/applications/submit_data_from_external.py +2 -1
- simtools/applications/validate_camera_efficiency.py +28 -27
- simtools/applications/validate_cumulative_psf.py +1 -3
- simtools/applications/validate_optics.py +2 -1
- simtools/atmosphere.py +83 -0
- simtools/camera/camera_efficiency.py +171 -48
- simtools/camera/single_photon_electron_spectrum.py +6 -6
- simtools/configuration/commandline_parser.py +47 -9
- simtools/constants.py +5 -0
- simtools/corsika/corsika_config.py +88 -185
- simtools/corsika/corsika_histograms.py +246 -69
- simtools/data_model/model_data_writer.py +46 -49
- simtools/data_model/schema.py +2 -0
- simtools/db/db_handler.py +4 -2
- simtools/db/mongo_db.py +2 -2
- simtools/io/ascii_handler.py +52 -4
- simtools/io/io_handler.py +23 -12
- simtools/job_execution/job_manager.py +154 -79
- simtools/job_execution/process_pool.py +137 -0
- simtools/layout/array_layout.py +0 -1
- simtools/layout/array_layout_utils.py +143 -21
- simtools/model/array_model.py +22 -50
- simtools/model/calibration_model.py +4 -4
- simtools/model/model_parameter.py +123 -73
- simtools/model/model_utils.py +40 -1
- simtools/model/site_model.py +4 -4
- simtools/model/telescope_model.py +4 -5
- simtools/ray_tracing/incident_angles.py +87 -6
- simtools/ray_tracing/mirror_panel_psf.py +337 -217
- simtools/ray_tracing/psf_analysis.py +57 -42
- simtools/ray_tracing/psf_parameter_optimisation.py +3 -2
- simtools/ray_tracing/ray_tracing.py +37 -10
- simtools/runners/corsika_runner.py +52 -191
- simtools/runners/corsika_simtel_runner.py +74 -100
- simtools/runners/runner_services.py +214 -213
- simtools/runners/simtel_runner.py +27 -155
- simtools/runners/simtools_runner.py +9 -69
- simtools/schemas/application_workflow.metaschema.yml +8 -0
- simtools/settings.py +19 -0
- simtools/simtel/simtel_config_writer.py +0 -55
- simtools/simtel/simtel_seeds.py +184 -0
- simtools/simtel/simulator_array.py +115 -103
- simtools/simtel/simulator_camera_efficiency.py +66 -42
- simtools/simtel/simulator_light_emission.py +110 -123
- simtools/simtel/simulator_ray_tracing.py +78 -63
- simtools/simulator.py +135 -346
- simtools/testing/sim_telarray_metadata.py +13 -11
- simtools/testing/validate_output.py +87 -19
- simtools/utils/general.py +6 -17
- simtools/utils/random.py +36 -0
- simtools/visualization/plot_corsika_histograms.py +2 -0
- simtools/visualization/plot_incident_angles.py +48 -1
- simtools/visualization/plot_psf.py +160 -18
- {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.26.0.dist-info → gammasimtools-0.27.1.dist-info}/top_level.txt +0 -0
|
@@ -483,7 +483,56 @@ def _get_array_name(array_name):
|
|
|
483
483
|
return array_name[1:], int(array_name[0])
|
|
484
484
|
|
|
485
485
|
|
|
486
|
-
def
|
|
486
|
+
def _create_star_array(tel_name, pos_x, pos_y, pos_z, n_telescopes, tel_type, site, distance):
|
|
487
|
+
"""Create star-shaped array positions along x and y axes."""
|
|
488
|
+
axis_sequence = ["x", "y", "-x", "-y"]
|
|
489
|
+
step = 1
|
|
490
|
+
for i in range(n_telescopes):
|
|
491
|
+
tel_name.append(
|
|
492
|
+
names.generate_array_element_name_from_type_site_id(tel_type, site, f"{i + 1:02d}")
|
|
493
|
+
)
|
|
494
|
+
axis = axis_sequence[i % 4]
|
|
495
|
+
dist = distance * step
|
|
496
|
+
if axis == "x":
|
|
497
|
+
pos_x.append(dist)
|
|
498
|
+
pos_y.append(0 * u.m)
|
|
499
|
+
elif axis == "-x":
|
|
500
|
+
pos_x.append(-dist)
|
|
501
|
+
pos_y.append(0 * u.m)
|
|
502
|
+
elif axis == "y":
|
|
503
|
+
pos_x.append(0 * u.m)
|
|
504
|
+
pos_y.append(dist)
|
|
505
|
+
elif axis == "-y":
|
|
506
|
+
pos_x.append(0 * u.m)
|
|
507
|
+
pos_y.append(-dist)
|
|
508
|
+
pos_z.append(0 * u.m)
|
|
509
|
+
|
|
510
|
+
if (i + 1) % 4 == 0:
|
|
511
|
+
step += 1
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def _create_square_array(tel_name, pos_x, pos_y, pos_z, n_tel, tel_type, site, distance):
|
|
515
|
+
"""Create square array positions."""
|
|
516
|
+
if n_tel == 1:
|
|
517
|
+
tel_name.append(names.generate_array_element_name_from_type_site_id(tel_type, site, "01"))
|
|
518
|
+
pos_x.append(0 * u.m)
|
|
519
|
+
pos_y.append(0 * u.m)
|
|
520
|
+
pos_z.append(0 * u.m)
|
|
521
|
+
elif n_tel == 4:
|
|
522
|
+
for i in range(1, 5):
|
|
523
|
+
tel_name.append(
|
|
524
|
+
names.generate_array_element_name_from_type_site_id(tel_type, site, f"0{i}")
|
|
525
|
+
)
|
|
526
|
+
pos_x.append(distance * (-1) ** (i // 2))
|
|
527
|
+
pos_y.append(distance * (-1) ** (i % 2))
|
|
528
|
+
pos_z.append(0 * u.m)
|
|
529
|
+
else:
|
|
530
|
+
raise ValueError(f"Unsupported number of telescopes for square array: {n_tel}.")
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def create_regular_array(
|
|
534
|
+
array_name, site, n_telescopes, telescope_type, telescope_distance, shape="square"
|
|
535
|
+
):
|
|
487
536
|
"""
|
|
488
537
|
Create a regular array layout table.
|
|
489
538
|
|
|
@@ -493,8 +542,14 @@ def create_regular_array(array_name, site, telescope_distance):
|
|
|
493
542
|
Name of the regular array (e.g. "4MST").
|
|
494
543
|
site : str
|
|
495
544
|
Site identifier.
|
|
496
|
-
|
|
497
|
-
|
|
545
|
+
n_telescopes : int
|
|
546
|
+
Number of telescopes in the array.
|
|
547
|
+
telescope_type : str
|
|
548
|
+
Type of telescope (e.g. "MST").
|
|
549
|
+
telescope_distance : Quantity
|
|
550
|
+
Distance between telescopes in the array.
|
|
551
|
+
shape : str
|
|
552
|
+
Shape of the array: "square" or "star" (default: "square").
|
|
498
553
|
|
|
499
554
|
Returns
|
|
500
555
|
-------
|
|
@@ -502,26 +557,31 @@ def create_regular_array(array_name, site, telescope_distance):
|
|
|
502
557
|
Table with the regular array layout.
|
|
503
558
|
"""
|
|
504
559
|
tel_name, pos_x, pos_y, pos_z = [], [], [], []
|
|
505
|
-
tel_size, n_tel = _get_array_name(array_name)
|
|
506
|
-
tel_size = array_name[1:4]
|
|
507
560
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
561
|
+
if shape == "square":
|
|
562
|
+
_create_square_array(
|
|
563
|
+
tel_name,
|
|
564
|
+
pos_x,
|
|
565
|
+
pos_y,
|
|
566
|
+
pos_z,
|
|
567
|
+
n_telescopes,
|
|
568
|
+
telescope_type,
|
|
569
|
+
site,
|
|
570
|
+
telescope_distance,
|
|
571
|
+
)
|
|
572
|
+
elif shape == "star":
|
|
573
|
+
_create_star_array(
|
|
574
|
+
tel_name,
|
|
575
|
+
pos_x,
|
|
576
|
+
pos_y,
|
|
577
|
+
pos_z,
|
|
578
|
+
n_telescopes,
|
|
579
|
+
telescope_type,
|
|
580
|
+
site,
|
|
581
|
+
telescope_distance,
|
|
582
|
+
)
|
|
523
583
|
else:
|
|
524
|
-
raise ValueError(f"Unsupported
|
|
584
|
+
raise ValueError(f"Unsupported array shape: {shape}. Allowed: 'square' or 'star'.")
|
|
525
585
|
|
|
526
586
|
table = QTable(meta={"array_name": array_name, "site": site})
|
|
527
587
|
table["telescope_name"] = tel_name
|
|
@@ -591,3 +651,65 @@ def write_array_elements_from_file_to_repository(
|
|
|
591
651
|
output_path=repository_path / instrument,
|
|
592
652
|
output_file=f"{parameter_name}.json",
|
|
593
653
|
)
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def write_array_elements_info_yaml(
|
|
657
|
+
array_table, site, model_version, output_file, parameter_version="2.0.0"
|
|
658
|
+
):
|
|
659
|
+
"""
|
|
660
|
+
Write YAML file for array layout in a format compatible with overwrite.
|
|
661
|
+
|
|
662
|
+
Parameters
|
|
663
|
+
----------
|
|
664
|
+
array_table : astropy.table.Table
|
|
665
|
+
Table with telescope positions.
|
|
666
|
+
site : str
|
|
667
|
+
Site identifier (e.g., 'North' or 'South').
|
|
668
|
+
model_version : str
|
|
669
|
+
Model version.
|
|
670
|
+
output_file : Path
|
|
671
|
+
Path to the output YAML file.
|
|
672
|
+
parameter_version : str
|
|
673
|
+
Parameter version to use in the YAML file.
|
|
674
|
+
"""
|
|
675
|
+
telescope_names = [str(name) for name in array_table["telescope_name"]]
|
|
676
|
+
|
|
677
|
+
data = {
|
|
678
|
+
"model_version": model_version,
|
|
679
|
+
"model_update": "patch_update",
|
|
680
|
+
"model_version_history": [model_version],
|
|
681
|
+
"description": f"Regular array layout: {array_table.meta['array_name']}",
|
|
682
|
+
"changes": {
|
|
683
|
+
f"OBS-{site}": {
|
|
684
|
+
"array_layouts": {
|
|
685
|
+
"version": parameter_version,
|
|
686
|
+
"value": [],
|
|
687
|
+
"unit": None,
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
data["changes"][f"OBS-{site}"]["array_layouts"]["value"].append(
|
|
694
|
+
{"name": array_table.meta["array_name"], "elements": telescope_names}
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
for tel_name, pos_x, pos_y, pos_z in zip(
|
|
698
|
+
telescope_names,
|
|
699
|
+
array_table["position_x"],
|
|
700
|
+
array_table["position_y"],
|
|
701
|
+
array_table["position_z"],
|
|
702
|
+
):
|
|
703
|
+
data["changes"][tel_name] = {
|
|
704
|
+
"array_element_position_ground": {
|
|
705
|
+
"version": parameter_version,
|
|
706
|
+
"value": [
|
|
707
|
+
float(pos_x.to(u.m).value),
|
|
708
|
+
float(pos_y.to(u.m).value),
|
|
709
|
+
float(pos_z.to(u.m).value),
|
|
710
|
+
],
|
|
711
|
+
"unit": "m",
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
ascii_handler.write_data_to_file(data, output_file)
|
simtools/model/array_model.py
CHANGED
|
@@ -9,9 +9,10 @@ from astropy.table import QTable
|
|
|
9
9
|
from simtools.data_model import data_reader, schema
|
|
10
10
|
from simtools.io import io_handler
|
|
11
11
|
from simtools.model.calibration_model import CalibrationModel
|
|
12
|
+
from simtools.model.model_utils import read_overwrite_model_parameter_dict
|
|
12
13
|
from simtools.model.site_model import SiteModel
|
|
13
14
|
from simtools.model.telescope_model import TelescopeModel
|
|
14
|
-
from simtools.simtel
|
|
15
|
+
from simtools.simtel import simtel_config_writer, simtel_seeds
|
|
15
16
|
from simtools.utils import general, names
|
|
16
17
|
|
|
17
18
|
|
|
@@ -50,7 +51,6 @@ class ArrayModel:
|
|
|
50
51
|
):
|
|
51
52
|
"""Initialize ArrayModel."""
|
|
52
53
|
self._logger = logging.getLogger(__name__)
|
|
53
|
-
self._logger.debug("Init ArrayModel")
|
|
54
54
|
self.model_version = model_version
|
|
55
55
|
self.label = label
|
|
56
56
|
self.layout_name = (
|
|
@@ -62,7 +62,9 @@ class ArrayModel:
|
|
|
62
62
|
self._config_file_directory = None
|
|
63
63
|
self.io_handler = io_handler.IOHandler()
|
|
64
64
|
|
|
65
|
-
self.
|
|
65
|
+
self.overwrite_model_parameter_dict = read_overwrite_model_parameter_dict(
|
|
66
|
+
overwrite_model_parameters
|
|
67
|
+
)
|
|
66
68
|
|
|
67
69
|
self.array_elements, self.site_model, self.telescope_models, self.calibration_models = (
|
|
68
70
|
self._initialize(site, array_elements, calibration_device_types)
|
|
@@ -70,7 +72,7 @@ class ArrayModel:
|
|
|
70
72
|
|
|
71
73
|
self._telescope_model_files_exported = False
|
|
72
74
|
self._array_model_file_exported = False
|
|
73
|
-
self.
|
|
75
|
+
self.sim_telarray_seed = None
|
|
74
76
|
|
|
75
77
|
def _initialize(self, site, array_elements_config, calibration_device_types):
|
|
76
78
|
"""
|
|
@@ -99,7 +101,7 @@ class ArrayModel:
|
|
|
99
101
|
site=names.validate_site_name(site),
|
|
100
102
|
model_version=self.model_version,
|
|
101
103
|
label=self.label,
|
|
102
|
-
|
|
104
|
+
overwrite_model_parameter_dict=self.overwrite_model_parameter_dict,
|
|
103
105
|
)
|
|
104
106
|
|
|
105
107
|
# Case 1: array_elements is a file name
|
|
@@ -127,41 +129,6 @@ class ArrayModel:
|
|
|
127
129
|
|
|
128
130
|
return array_elements, site_model, telescope_models, calibration_models
|
|
129
131
|
|
|
130
|
-
@property
|
|
131
|
-
def sim_telarray_seeds(self):
|
|
132
|
-
"""
|
|
133
|
-
Return sim_telarray seeds.
|
|
134
|
-
|
|
135
|
-
Returns
|
|
136
|
-
-------
|
|
137
|
-
dict
|
|
138
|
-
Dictionary with sim_telarray seeds.
|
|
139
|
-
"""
|
|
140
|
-
return self._sim_telarray_seeds
|
|
141
|
-
|
|
142
|
-
@sim_telarray_seeds.setter
|
|
143
|
-
def sim_telarray_seeds(self, value):
|
|
144
|
-
"""
|
|
145
|
-
Set sim_telarray seeds.
|
|
146
|
-
|
|
147
|
-
Parameters
|
|
148
|
-
----------
|
|
149
|
-
value: dict
|
|
150
|
-
Dictionary with sim_telarray seeds.
|
|
151
|
-
"""
|
|
152
|
-
if isinstance(value, dict):
|
|
153
|
-
required_keys = {
|
|
154
|
-
"seed",
|
|
155
|
-
"random_instrument_instances",
|
|
156
|
-
"seed_file_name",
|
|
157
|
-
}
|
|
158
|
-
if not required_keys.issubset(value):
|
|
159
|
-
raise ValueError(
|
|
160
|
-
"sim_telarray_seeds dictionary must contain the following keys: "
|
|
161
|
-
f"{required_keys}"
|
|
162
|
-
)
|
|
163
|
-
self._sim_telarray_seeds = value
|
|
164
|
-
|
|
165
132
|
@property
|
|
166
133
|
def config_file_path(self):
|
|
167
134
|
"""
|
|
@@ -242,7 +209,7 @@ class ArrayModel:
|
|
|
242
209
|
telescope_name=element_name,
|
|
243
210
|
model_version=self.model_version,
|
|
244
211
|
label=self.label,
|
|
245
|
-
|
|
212
|
+
overwrite_model_parameter_dict=self.overwrite_model_parameter_dict,
|
|
246
213
|
)
|
|
247
214
|
calibration_models[element_name] = self._build_calibration_models(
|
|
248
215
|
telescope_models[element_name],
|
|
@@ -274,7 +241,7 @@ class ArrayModel:
|
|
|
274
241
|
calibration_device_model_name=device_name,
|
|
275
242
|
model_version=self.model_version,
|
|
276
243
|
label=self.label,
|
|
277
|
-
|
|
244
|
+
overwrite_model_parameter_dict=self.overwrite_model_parameter_dict,
|
|
278
245
|
)
|
|
279
246
|
return calibration_models
|
|
280
247
|
|
|
@@ -289,7 +256,6 @@ class ArrayModel:
|
|
|
289
256
|
for tel_model in self.telescope_models.values():
|
|
290
257
|
name = tel_model.name
|
|
291
258
|
if name not in exported_models:
|
|
292
|
-
self._logger.debug(f"Exporting configuration file for telescope {name}")
|
|
293
259
|
tel_model.write_sim_telarray_config_file(
|
|
294
260
|
additional_models=self.calibration_models.get(tel_model.name)
|
|
295
261
|
)
|
|
@@ -306,7 +272,7 @@ class ArrayModel:
|
|
|
306
272
|
self.site_model.export_model_files()
|
|
307
273
|
|
|
308
274
|
self._logger.info(f"Writing array configuration file into {self.config_file_path}")
|
|
309
|
-
simtel_writer = SimtelConfigWriter(
|
|
275
|
+
simtel_writer = simtel_config_writer.SimtelConfigWriter(
|
|
310
276
|
site=self.site_model.site,
|
|
311
277
|
layout_name=self.layout_name,
|
|
312
278
|
model_version=self.model_version,
|
|
@@ -531,10 +497,16 @@ class ArrayModel:
|
|
|
531
497
|
dict
|
|
532
498
|
Dictionary with additional metadata.
|
|
533
499
|
"""
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
metadata["nsb_integrated_flux"] = self.site_model.get_nsb_integrated_flux()
|
|
500
|
+
return {
|
|
501
|
+
"nsb_integrated_flux": self.site_model.get_nsb_integrated_flux(),
|
|
502
|
+
}
|
|
539
503
|
|
|
540
|
-
|
|
504
|
+
def initialize_seeds(self, zenith_angle=None, azimuth_angle=None):
|
|
505
|
+
"""Initialize sim_telarray seeds for instrument and shower simulations."""
|
|
506
|
+
self.sim_telarray_seed = simtel_seeds.SimtelSeeds(
|
|
507
|
+
output_path=self.get_config_directory(),
|
|
508
|
+
site=self.site_model.site,
|
|
509
|
+
model_version=self.model_version,
|
|
510
|
+
zenith_angle=zenith_angle,
|
|
511
|
+
azimuth_angle=azimuth_angle,
|
|
512
|
+
)
|
|
@@ -21,8 +21,8 @@ class CalibrationModel(ModelParameter):
|
|
|
21
21
|
Model version.
|
|
22
22
|
label: str, optional
|
|
23
23
|
Instance label. Important for output file naming.
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
overwrite_model_parameter_dict: dict, optional
|
|
25
|
+
Dictionary to overwrite model parameters from DB with provided values.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
28
|
def __init__(
|
|
@@ -31,7 +31,7 @@ class CalibrationModel(ModelParameter):
|
|
|
31
31
|
calibration_device_model_name,
|
|
32
32
|
model_version,
|
|
33
33
|
label=None,
|
|
34
|
-
|
|
34
|
+
overwrite_model_parameter_dict=None,
|
|
35
35
|
):
|
|
36
36
|
"""Initialize CalibrationModel."""
|
|
37
37
|
super().__init__(
|
|
@@ -40,7 +40,7 @@ class CalibrationModel(ModelParameter):
|
|
|
40
40
|
collection="calibration_devices",
|
|
41
41
|
model_version=model_version,
|
|
42
42
|
label=label,
|
|
43
|
-
|
|
43
|
+
overwrite_model_parameter_dict=overwrite_model_parameter_dict,
|
|
44
44
|
)
|
|
45
45
|
|
|
46
46
|
self._logger = logging.getLogger(__name__)
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
import logging
|
|
5
5
|
import shutil
|
|
6
6
|
from copy import copy, deepcopy
|
|
7
|
+
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
import astropy.units as u
|
|
9
10
|
|
|
10
11
|
import simtools.utils.general as gen
|
|
11
12
|
from simtools.data_model import schema
|
|
12
13
|
from simtools.db import db_handler
|
|
13
|
-
from simtools.io import
|
|
14
|
+
from simtools.io import io_handler
|
|
14
15
|
from simtools.model import legacy_model_parameter
|
|
15
16
|
from simtools.simtel.simtel_config_writer import SimtelConfigWriter
|
|
16
17
|
from simtools.utils import names, value_conversion
|
|
@@ -40,8 +41,8 @@ class ModelParameter:
|
|
|
40
41
|
as stored under collection in the DB.
|
|
41
42
|
label: str
|
|
42
43
|
Instance label. Used for output file naming.
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
overwrite_model_parameter_dict: dict, optional
|
|
45
|
+
Dictionary to overwrite model parameters from DB with provided values.
|
|
45
46
|
Instance label. Important for output file naming.
|
|
46
47
|
ignore_software_version: bool
|
|
47
48
|
If True, ignore software version checks for deprecated parameters.
|
|
@@ -55,7 +56,7 @@ class ModelParameter:
|
|
|
55
56
|
array_element_name=None,
|
|
56
57
|
collection="telescopes",
|
|
57
58
|
label=None,
|
|
58
|
-
|
|
59
|
+
overwrite_model_parameter_dict=None,
|
|
59
60
|
ignore_software_version=False,
|
|
60
61
|
):
|
|
61
62
|
self._logger = logging.getLogger(__name__)
|
|
@@ -81,7 +82,7 @@ class ModelParameter:
|
|
|
81
82
|
)
|
|
82
83
|
self._config_file_directory = None
|
|
83
84
|
self._config_file_path = None
|
|
84
|
-
self.
|
|
85
|
+
self.overwrite_model_parameter_dict = overwrite_model_parameter_dict
|
|
85
86
|
self._added_parameter_files = None
|
|
86
87
|
self._is_exported_model_files_up_to_date = False
|
|
87
88
|
|
|
@@ -276,8 +277,6 @@ class ModelParameter:
|
|
|
276
277
|
)
|
|
277
278
|
self._config_file_path = self.config_file_directory.joinpath(config_file_name)
|
|
278
279
|
|
|
279
|
-
self._logger.debug(f"Config file path: {self._config_file_path}")
|
|
280
|
-
|
|
281
280
|
def get_simulation_software_parameters(self, simulation_software):
|
|
282
281
|
"""
|
|
283
282
|
Get simulation software parameters.
|
|
@@ -325,8 +324,7 @@ class ModelParameter:
|
|
|
325
324
|
self.site, self.name, self.collection, self.model_version
|
|
326
325
|
)
|
|
327
326
|
)
|
|
328
|
-
|
|
329
|
-
self.overwrite_parameters_from_file(self.overwrite_model_parameters)
|
|
327
|
+
self.overwrite_parameters(self.overwrite_model_parameter_dict)
|
|
330
328
|
self._check_model_parameter_versions(self.parameters)
|
|
331
329
|
|
|
332
330
|
self._load_simulation_software_parameter()
|
|
@@ -396,22 +394,20 @@ class ModelParameter:
|
|
|
396
394
|
raise InvalidModelParameterError(f"Parameter {par_name} not in the model")
|
|
397
395
|
|
|
398
396
|
if value is None and parameter_version:
|
|
399
|
-
|
|
400
|
-
parameter=par_name,
|
|
401
|
-
site=self.site,
|
|
402
|
-
array_element_name=self.name,
|
|
403
|
-
parameter_version=parameter_version,
|
|
404
|
-
)
|
|
405
|
-
if _para_dict:
|
|
406
|
-
self.parameters[par_name] = _para_dict.get(par_name)
|
|
407
|
-
self._logger.debug(
|
|
408
|
-
f"Changing parameter {par_name} to version {parameter_version} with value "
|
|
409
|
-
f"{self.parameters[par_name]['value']}"
|
|
410
|
-
)
|
|
397
|
+
self._overwrite_model_parameter_from_db(par_name, parameter_version)
|
|
411
398
|
else:
|
|
412
|
-
|
|
399
|
+
self._overwrite_model_parameter_from_value(par_name, value, parameter_version)
|
|
413
400
|
|
|
414
|
-
|
|
401
|
+
# In case parameter is a file, the model files will be outdated
|
|
402
|
+
if self.get_parameter_file_flag(par_name):
|
|
403
|
+
self._is_exported_model_files_up_to_date = False
|
|
404
|
+
|
|
405
|
+
def _overwrite_model_parameter_from_value(self, par_name, value, parameter_version=None):
|
|
406
|
+
"""Overwrite model parameter from provided value only."""
|
|
407
|
+
value = gen.convert_string_to_list(value) if isinstance(value, str) else value
|
|
408
|
+
par_type = self.get_parameter_type(par_name)
|
|
409
|
+
|
|
410
|
+
if par_type in ("list", "dict"):
|
|
415
411
|
if not gen.validate_data_type(
|
|
416
412
|
reference_dtype=par_type,
|
|
417
413
|
value=value,
|
|
@@ -419,40 +415,40 @@ class ModelParameter:
|
|
|
419
415
|
allow_subtypes=True,
|
|
420
416
|
):
|
|
421
417
|
raise ValueError(f"Could not cast {value} of type {type(value)} to {par_type}.")
|
|
418
|
+
else:
|
|
419
|
+
for value_element in gen.ensure_iterable(value):
|
|
420
|
+
if not gen.validate_data_type(
|
|
421
|
+
reference_dtype=par_type,
|
|
422
|
+
value=value_element,
|
|
423
|
+
dtype=None,
|
|
424
|
+
allow_subtypes=True,
|
|
425
|
+
):
|
|
426
|
+
raise ValueError(
|
|
427
|
+
f"Could not cast {value_element} of type "
|
|
428
|
+
f"{type(value_element)} to {par_type}."
|
|
429
|
+
)
|
|
422
430
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
Parameters
|
|
445
|
-
----------
|
|
446
|
-
file_name: str
|
|
447
|
-
File containing the parameters to be changed.
|
|
448
|
-
"""
|
|
449
|
-
changes_data = schema.validate_dict_using_schema(
|
|
450
|
-
data=ascii_handler.collect_data_from_file(file_name=file_name),
|
|
451
|
-
schema_file="simulation_models_info.schema.yml",
|
|
452
|
-
).get("changes", {})
|
|
453
|
-
|
|
454
|
-
key_for_changes = self._get_key_for_parameter_changes(self.site, self.name, changes_data)
|
|
455
|
-
self.overwrite_parameters(changes_data.get(key_for_changes, {}) if key_for_changes else {})
|
|
431
|
+
self._logger.debug(
|
|
432
|
+
f"Changing parameter {par_name} from {self.get_parameter_value(par_name)} to {value}"
|
|
433
|
+
)
|
|
434
|
+
self.parameters[par_name]["value"] = value
|
|
435
|
+
if parameter_version:
|
|
436
|
+
self.parameters[par_name]["parameter_version"] = parameter_version
|
|
437
|
+
|
|
438
|
+
def _overwrite_model_parameter_from_db(self, par_name, parameter_version):
|
|
439
|
+
"""Overwrite model parameter from DB for a specific version."""
|
|
440
|
+
_para_dict = self.db.get_model_parameter(
|
|
441
|
+
parameter=par_name,
|
|
442
|
+
site=self.site,
|
|
443
|
+
array_element_name=self.name,
|
|
444
|
+
parameter_version=parameter_version,
|
|
445
|
+
)
|
|
446
|
+
if _para_dict:
|
|
447
|
+
self.parameters[par_name] = _para_dict.get(par_name)
|
|
448
|
+
self._logger.debug(
|
|
449
|
+
f"Changing parameter {par_name} to version {parameter_version} with value "
|
|
450
|
+
f"{self.parameters[par_name]['value']}"
|
|
451
|
+
)
|
|
456
452
|
|
|
457
453
|
def _get_key_for_parameter_changes(self, site, array_element_name, changes_data):
|
|
458
454
|
"""
|
|
@@ -494,7 +490,7 @@ class ModelParameter:
|
|
|
494
490
|
|
|
495
491
|
return None
|
|
496
492
|
|
|
497
|
-
def overwrite_parameters(self, changes):
|
|
493
|
+
def overwrite_parameters(self, changes, flat_dict=False):
|
|
498
494
|
"""
|
|
499
495
|
Change the value of multiple existing parameters in the model.
|
|
500
496
|
|
|
@@ -502,23 +498,43 @@ class ModelParameter:
|
|
|
502
498
|
|
|
503
499
|
Allows for two types of 'changes' dictionary:
|
|
504
500
|
|
|
505
|
-
- simple: '{parameter_name: new_value, ...}'
|
|
506
|
-
- model repository style:
|
|
507
|
-
'{parameter_name: {"value": new_value, "version": new_version}, ...}'
|
|
501
|
+
- simple (flat_dict=True): '{parameter_name: new_value, ...}'
|
|
502
|
+
- model repository style (flat_dict=False):
|
|
503
|
+
'{array_element: {parameter_name: {"value": new_value, "version": new_version}, ...}}'
|
|
508
504
|
|
|
509
505
|
Parameters
|
|
510
506
|
----------
|
|
511
507
|
changes: dict
|
|
512
508
|
Parameters to be changed.
|
|
513
509
|
"""
|
|
510
|
+
if not changes:
|
|
511
|
+
return
|
|
512
|
+
if not flat_dict:
|
|
513
|
+
key_for_changes = self._get_key_for_parameter_changes(self.site, self.name, changes)
|
|
514
|
+
changes = changes.get(key_for_changes, {})
|
|
515
|
+
if not changes:
|
|
516
|
+
return
|
|
517
|
+
|
|
518
|
+
if flat_dict:
|
|
519
|
+
self._logger.debug(f"Overwriting parameters with changes: {changes}")
|
|
520
|
+
else:
|
|
521
|
+
self._logger.debug(
|
|
522
|
+
f"Overwriting parameters for {key_for_changes} with changes: {changes}"
|
|
523
|
+
)
|
|
524
|
+
|
|
514
525
|
for par_name, par_value in changes.items():
|
|
515
|
-
if par_name in self.parameters:
|
|
516
|
-
|
|
517
|
-
self.
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
526
|
+
if par_name not in self.parameters:
|
|
527
|
+
self._logger.warning(
|
|
528
|
+
f"Parameter {par_name} not found in model {self.name}, cannot overwrite it."
|
|
529
|
+
)
|
|
530
|
+
continue
|
|
531
|
+
|
|
532
|
+
if isinstance(par_value, dict) and ("value" in par_value or "version" in par_value):
|
|
533
|
+
self.overwrite_model_parameter(
|
|
534
|
+
par_name, par_value.get("value"), par_value.get("version")
|
|
535
|
+
)
|
|
536
|
+
else:
|
|
537
|
+
self.overwrite_model_parameter(par_name, par_value)
|
|
522
538
|
|
|
523
539
|
def overwrite_model_file(self, par_name, file_path):
|
|
524
540
|
"""
|
|
@@ -566,7 +582,29 @@ class ModelParameter:
|
|
|
566
582
|
)
|
|
567
583
|
self._is_exported_model_files_up_to_date = True
|
|
568
584
|
|
|
569
|
-
def
|
|
585
|
+
def get_config_file_path(self, label=None):
|
|
586
|
+
"""Return config file path for a given label.
|
|
587
|
+
|
|
588
|
+
Parameters
|
|
589
|
+
----------
|
|
590
|
+
label : str or None
|
|
591
|
+
Label used for output file naming. If None, use this model's label.
|
|
592
|
+
|
|
593
|
+
Returns
|
|
594
|
+
-------
|
|
595
|
+
pathlib.Path
|
|
596
|
+
Path to the sim_telarray configuration file.
|
|
597
|
+
"""
|
|
598
|
+
config_file_name = names.simtel_config_file_name(
|
|
599
|
+
self.site,
|
|
600
|
+
telescope_model_name=self.name,
|
|
601
|
+
label=self.label if label is None else label,
|
|
602
|
+
)
|
|
603
|
+
return self.config_file_directory.joinpath(config_file_name)
|
|
604
|
+
|
|
605
|
+
def write_sim_telarray_config_file(
|
|
606
|
+
self, additional_models=None, label=None, config_file_path=None
|
|
607
|
+
):
|
|
570
608
|
"""
|
|
571
609
|
Write the sim_telarray configuration file.
|
|
572
610
|
|
|
@@ -574,15 +612,26 @@ class ModelParameter:
|
|
|
574
612
|
----------
|
|
575
613
|
additional_models: TelescopeModel or SiteModel
|
|
576
614
|
Model object for additional parameter to be written to the config file.
|
|
615
|
+
label: str or None
|
|
616
|
+
Optional label override used for output file naming.
|
|
617
|
+
config_file_path: pathlib.Path or str or None
|
|
618
|
+
Optional explicit path of the config file. If not given, it is derived from ``label``.
|
|
577
619
|
"""
|
|
578
620
|
self.parameters.update(self._simulation_config_parameters.get("sim_telarray", {}))
|
|
579
621
|
self.export_model_files(update_if_necessary=True)
|
|
580
622
|
|
|
581
623
|
self._add_additional_models(additional_models)
|
|
582
624
|
|
|
583
|
-
|
|
625
|
+
config_file_path = (
|
|
626
|
+
Path(config_file_path)
|
|
627
|
+
if config_file_path is not None
|
|
628
|
+
else self.get_config_file_path(label=label)
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
# Ensure the writer label matches the config file naming label.
|
|
632
|
+
self._load_simtel_config_writer(label=label)
|
|
584
633
|
self.simtel_config_writer.write_telescope_config_file(
|
|
585
|
-
config_file_path=
|
|
634
|
+
config_file_path=config_file_path,
|
|
586
635
|
parameters=self.parameters,
|
|
587
636
|
)
|
|
588
637
|
|
|
@@ -613,15 +662,16 @@ class ModelParameter:
|
|
|
613
662
|
self._set_config_file_directory_and_name()
|
|
614
663
|
return self._config_file_path
|
|
615
664
|
|
|
616
|
-
def _load_simtel_config_writer(self):
|
|
665
|
+
def _load_simtel_config_writer(self, label=None):
|
|
617
666
|
"""Load the SimtelConfigWriter object."""
|
|
618
|
-
|
|
667
|
+
desired_label = self.label if label is None else label
|
|
668
|
+
if label is not None or self.simtel_config_writer is None:
|
|
619
669
|
self.simtel_config_writer = SimtelConfigWriter(
|
|
620
670
|
site=self.site,
|
|
621
671
|
telescope_model_name=self.name,
|
|
622
672
|
telescope_design_model=self.design_model,
|
|
623
673
|
model_version=self.model_version,
|
|
624
|
-
label=
|
|
674
|
+
label=desired_label,
|
|
625
675
|
)
|
|
626
676
|
|
|
627
677
|
def export_nsb_spectrum_to_telescope_altitude_correction_file(self, model_directory):
|