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
|
@@ -185,7 +185,7 @@ class PrimaryParticle:
|
|
|
185
185
|
"silicon": {"corsika7_id": 2814},
|
|
186
186
|
"iron": {"corsika7_id": 5626},
|
|
187
187
|
}
|
|
188
|
-
for
|
|
188
|
+
for ids in particles.values():
|
|
189
189
|
ids["pdg_id"] = Corsika7ID(ids["corsika7_id"]).to_pdgid().numerator
|
|
190
190
|
ids["pdg_name"] = Particle.findall(pdgid=ids["pdg_id"])[0].name
|
|
191
191
|
|
|
@@ -360,6 +360,9 @@ class MetadataCollector:
|
|
|
360
360
|
"Metadata extraction from sim_telarray files is not supported yet."
|
|
361
361
|
)
|
|
362
362
|
continue
|
|
363
|
+
elif Path(metadata_file).name.endswith((".corsika.zst", ".corsika")):
|
|
364
|
+
self._logger.warning("Metadata extraction from CORSIKA files is not supported yet.")
|
|
365
|
+
continue
|
|
363
366
|
else:
|
|
364
367
|
raise ValueError(f"Unknown metadata file format: {metadata_file}")
|
|
365
368
|
|
|
@@ -422,7 +425,7 @@ class MetadataCollector:
|
|
|
422
425
|
product_dict["creation_time"] = gen.now_date_time_in_isoformat()
|
|
423
426
|
product_dict["description"] = self.schema_dict.get("description", None)
|
|
424
427
|
|
|
425
|
-
# DATA:CATEGORY
|
|
428
|
+
# metadata DATA:CATEGORY
|
|
426
429
|
product_dict["data"]["category"] = "SIM"
|
|
427
430
|
product_dict["data"]["level"] = "R1"
|
|
428
431
|
product_dict["data"]["type"] = "Service"
|
|
@@ -431,7 +434,7 @@ class MetadataCollector:
|
|
|
431
434
|
except KeyError:
|
|
432
435
|
pass
|
|
433
436
|
|
|
434
|
-
# DATA:MODEL
|
|
437
|
+
# metadata DATA:MODEL
|
|
435
438
|
product_dict["data"]["model"]["name"] = (
|
|
436
439
|
self.schema_dict.get("name")
|
|
437
440
|
or self.args_dict.get("metadata_product_data_name")
|
|
@@ -8,13 +8,9 @@ Follows CTAO top-level data model definition.
|
|
|
8
8
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
import logging
|
|
12
|
-
|
|
13
11
|
import simtools.data_model.schema
|
|
14
12
|
import simtools.utils.general as gen
|
|
15
13
|
|
|
16
|
-
_logger = logging.getLogger(__name__)
|
|
17
|
-
|
|
18
14
|
|
|
19
15
|
def get_default_metadata_dict(
|
|
20
16
|
schema_file=None, observatory="CTA", schema_version="latest", lower_case=True
|
|
@@ -7,6 +7,7 @@ import packaging.version
|
|
|
7
7
|
from astropy.io.registry.base import IORegistryError
|
|
8
8
|
|
|
9
9
|
import simtools.utils.general as gen
|
|
10
|
+
from simtools import settings
|
|
10
11
|
from simtools.data_model import schema, validate_data
|
|
11
12
|
from simtools.data_model.metadata_collector import MetadataCollector
|
|
12
13
|
from simtools.db import db_handler
|
|
@@ -20,69 +21,62 @@ class ModelDataWriter:
|
|
|
20
21
|
|
|
21
22
|
Parameters
|
|
22
23
|
----------
|
|
23
|
-
|
|
24
|
+
output_file: str
|
|
24
25
|
Name of output file.
|
|
25
|
-
|
|
26
|
+
output_file_format: str
|
|
26
27
|
Format of output file.
|
|
27
|
-
args_dict: Dictionary
|
|
28
|
-
Dictionary with configuration parameters.
|
|
29
28
|
output_path: str or Path
|
|
30
29
|
Path to output file.
|
|
31
|
-
args_dict: dict
|
|
32
|
-
Dictionary with configuration parameters.
|
|
33
|
-
|
|
34
30
|
"""
|
|
35
31
|
|
|
36
|
-
def __init__(
|
|
37
|
-
self,
|
|
38
|
-
product_data_file=None,
|
|
39
|
-
product_data_format=None,
|
|
40
|
-
output_path=None,
|
|
41
|
-
args_dict=None,
|
|
42
|
-
):
|
|
32
|
+
def __init__(self, output_file=None, output_file_format=None, output_path=None):
|
|
43
33
|
"""Initialize model data writer."""
|
|
44
34
|
self._logger = logging.getLogger(__name__)
|
|
45
35
|
self.io_handler = io_handler.IOHandler()
|
|
46
36
|
self.schema_dict = {}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
self.
|
|
37
|
+
self.output_label = "model_data_writer"
|
|
38
|
+
self.io_handler.set_paths(
|
|
39
|
+
output_path=output_path or settings.config.args.get("output_path"),
|
|
40
|
+
output_path_label=self.output_label,
|
|
41
|
+
)
|
|
51
42
|
try:
|
|
52
|
-
self.
|
|
43
|
+
self.output_file = self.io_handler.get_output_file(
|
|
44
|
+
file_name=output_file, output_path_label=self.output_label
|
|
45
|
+
)
|
|
53
46
|
except TypeError:
|
|
54
|
-
self.
|
|
55
|
-
self.
|
|
47
|
+
self.output_file = None
|
|
48
|
+
self.output_file_format = self._derive_data_format(output_file_format, self.output_file)
|
|
56
49
|
|
|
57
50
|
@staticmethod
|
|
58
51
|
def dump(
|
|
59
|
-
|
|
52
|
+
output_file=None,
|
|
53
|
+
metadata=None,
|
|
54
|
+
product_data=None,
|
|
55
|
+
output_file_format="ascii.ecsv",
|
|
56
|
+
validate_schema_file=None,
|
|
60
57
|
):
|
|
61
58
|
"""
|
|
62
59
|
Write model data and metadata (as static method).
|
|
63
60
|
|
|
64
61
|
Parameters
|
|
65
62
|
----------
|
|
66
|
-
args_dict: dict
|
|
67
|
-
Dictionary with configuration parameters (including output file name and path).
|
|
68
63
|
output_file: string or Path
|
|
69
64
|
Name of output file (args["output_file"] is used if this parameter is not set).
|
|
70
65
|
metadata: MetadataCollector object
|
|
71
66
|
Metadata to be written.
|
|
72
67
|
product_data: astropy Table
|
|
73
68
|
Model data to be written
|
|
69
|
+
output_file_format: str
|
|
70
|
+
Format of output file.
|
|
74
71
|
validate_schema_file: str
|
|
75
72
|
Schema file used in validation of output data.
|
|
76
|
-
|
|
77
73
|
"""
|
|
78
74
|
writer = ModelDataWriter(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
),
|
|
82
|
-
product_data_format=args_dict.get("output_file_format", "ascii.ecsv"),
|
|
83
|
-
args_dict=args_dict,
|
|
75
|
+
output_file=output_file,
|
|
76
|
+
output_file_format=output_file_format,
|
|
84
77
|
)
|
|
85
|
-
|
|
78
|
+
skip_output_validation = settings.config.args.get("skip_output_validation", True)
|
|
79
|
+
if validate_schema_file is not None and not skip_output_validation:
|
|
86
80
|
product_data = writer.validate_and_transform(
|
|
87
81
|
product_data_table=product_data,
|
|
88
82
|
validate_schema_file=validate_schema_file,
|
|
@@ -98,10 +92,10 @@ class ModelDataWriter:
|
|
|
98
92
|
output_file,
|
|
99
93
|
output_path=None,
|
|
100
94
|
metadata_input_dict=None,
|
|
101
|
-
db_config=None,
|
|
102
95
|
unit=None,
|
|
103
96
|
meta_parameter=False,
|
|
104
97
|
model_parameter_schema_version=None,
|
|
98
|
+
check_db_for_existing_parameter=True,
|
|
105
99
|
):
|
|
106
100
|
"""
|
|
107
101
|
Generate DB-style model parameter dict and write it to json file.
|
|
@@ -122,14 +116,14 @@ class ModelDataWriter:
|
|
|
122
116
|
Path to output file.
|
|
123
117
|
metadata_input_dict: dict
|
|
124
118
|
Input to metadata collector.
|
|
125
|
-
db_config: dict
|
|
126
|
-
Database configuration. If not None, check if parameter with the same version exists.
|
|
127
119
|
unit: str
|
|
128
120
|
Unit of the parameter value (if applicable and value is not of type astropy Quantity).
|
|
129
121
|
meta_parameter: bool
|
|
130
122
|
Setting for meta parameter flag.
|
|
131
123
|
model_parameter_schema_version: str, None
|
|
132
124
|
Version of the model parameter schema (if None, use schema version from schema dict).
|
|
125
|
+
check_db_for_existing_parameter: bool
|
|
126
|
+
If True, check if parameter with same version exists in DB before writing.
|
|
133
127
|
|
|
134
128
|
Returns
|
|
135
129
|
-------
|
|
@@ -137,15 +131,12 @@ class ModelDataWriter:
|
|
|
137
131
|
Validated parameter dictionary.
|
|
138
132
|
"""
|
|
139
133
|
writer = ModelDataWriter(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
args_dict=None,
|
|
134
|
+
output_file=output_file,
|
|
135
|
+
output_file_format="json",
|
|
143
136
|
output_path=output_path,
|
|
144
137
|
)
|
|
145
|
-
if
|
|
146
|
-
writer.check_db_for_existing_parameter(
|
|
147
|
-
parameter_name, instrument, parameter_version, db_config
|
|
148
|
-
)
|
|
138
|
+
if check_db_for_existing_parameter:
|
|
139
|
+
writer.check_db_for_existing_parameter(parameter_name, instrument, parameter_version)
|
|
149
140
|
|
|
150
141
|
unique_id = None
|
|
151
142
|
if metadata_input_dict is not None:
|
|
@@ -170,9 +161,7 @@ class ModelDataWriter:
|
|
|
170
161
|
writer.write_dict_to_model_parameter_json(output_file, _json_dict)
|
|
171
162
|
return _json_dict
|
|
172
163
|
|
|
173
|
-
def check_db_for_existing_parameter(
|
|
174
|
-
self, parameter_name, instrument, parameter_version, db_config
|
|
175
|
-
):
|
|
164
|
+
def check_db_for_existing_parameter(self, parameter_name, instrument, parameter_version):
|
|
176
165
|
"""
|
|
177
166
|
Check if a parameter with the same version exists in the simulation model database.
|
|
178
167
|
|
|
@@ -184,15 +173,15 @@ class ModelDataWriter:
|
|
|
184
173
|
Name of the instrument.
|
|
185
174
|
parameter_version: str
|
|
186
175
|
Version of the parameter.
|
|
187
|
-
db_config: dict
|
|
188
|
-
Database configuration.
|
|
189
176
|
|
|
190
177
|
Raises
|
|
191
178
|
------
|
|
192
179
|
ValueError
|
|
193
180
|
If parameter with the same version exists in the database.
|
|
194
181
|
"""
|
|
195
|
-
db = db_handler.DatabaseHandler(
|
|
182
|
+
db = db_handler.DatabaseHandler()
|
|
183
|
+
if not db.is_configured():
|
|
184
|
+
return
|
|
196
185
|
try:
|
|
197
186
|
db.get_model_parameter(
|
|
198
187
|
parameter=parameter_name,
|
|
@@ -373,8 +362,10 @@ class ModelDataWriter:
|
|
|
373
362
|
"""
|
|
374
363
|
try:
|
|
375
364
|
unit_list = []
|
|
376
|
-
|
|
377
|
-
|
|
365
|
+
unit_list = [
|
|
366
|
+
data["unit"] if data["unit"] != "dimensionless" else None
|
|
367
|
+
for data in self.schema_dict["data"]
|
|
368
|
+
]
|
|
378
369
|
return unit_list if len(unit_list) > 1 else unit_list[0]
|
|
379
370
|
except (KeyError, IndexError):
|
|
380
371
|
pass
|
|
@@ -436,19 +427,17 @@ class ModelDataWriter:
|
|
|
436
427
|
gen.change_dict_keys_case(metadata.get_top_level_metadata(), True)
|
|
437
428
|
)
|
|
438
429
|
|
|
439
|
-
self._logger.info(f"Writing data to {self.
|
|
440
|
-
if isinstance(product_data, dict) and Path(self.
|
|
441
|
-
self.write_dict_to_model_parameter_json(self.
|
|
430
|
+
self._logger.info(f"Writing data to {self.output_file}")
|
|
431
|
+
if isinstance(product_data, dict) and Path(self.output_file).suffix == ".json":
|
|
432
|
+
self.write_dict_to_model_parameter_json(self.output_file, product_data)
|
|
442
433
|
return
|
|
443
434
|
try:
|
|
444
|
-
product_data.write(
|
|
445
|
-
self.product_data_file, format=self.product_data_format, overwrite=True
|
|
446
|
-
)
|
|
435
|
+
product_data.write(self.output_file, format=self.output_file_format, overwrite=True)
|
|
447
436
|
except IORegistryError:
|
|
448
|
-
self._logger.error(f"Error writing model data to {self.
|
|
437
|
+
self._logger.error(f"Error writing model data to {self.output_file}.")
|
|
449
438
|
raise
|
|
450
439
|
if metadata is not None:
|
|
451
|
-
metadata.write(self.
|
|
440
|
+
metadata.write(self.output_file, add_activity_name=True)
|
|
452
441
|
|
|
453
442
|
def write_dict_to_model_parameter_json(self, file_name, data_dict):
|
|
454
443
|
"""
|
|
@@ -467,10 +456,13 @@ class ModelDataWriter:
|
|
|
467
456
|
if data writing was not successful.
|
|
468
457
|
"""
|
|
469
458
|
data_dict = ModelDataWriter.prepare_data_dict_for_writing(data_dict)
|
|
470
|
-
|
|
459
|
+
output_file = self.io_handler.get_output_file(
|
|
460
|
+
file_name, output_path_label=self.output_label
|
|
461
|
+
)
|
|
462
|
+
self._logger.info(f"Writing data to {output_file}")
|
|
471
463
|
ascii_handler.write_data_to_file(
|
|
472
464
|
data=data_dict,
|
|
473
|
-
output_file=
|
|
465
|
+
output_file=output_file,
|
|
474
466
|
sort_keys=True,
|
|
475
467
|
numpy_types=True,
|
|
476
468
|
)
|
|
@@ -510,9 +502,12 @@ class ModelDataWriter:
|
|
|
510
502
|
return data_dict
|
|
511
503
|
|
|
512
504
|
@staticmethod
|
|
513
|
-
def
|
|
505
|
+
def _derive_data_format(product_data_format, output_file=None):
|
|
514
506
|
"""
|
|
515
|
-
|
|
507
|
+
Derive data format and ensure conformance with astropy data format naming.
|
|
508
|
+
|
|
509
|
+
If product_data_format is None and output_file is given, derive format
|
|
510
|
+
from output_file suffix.
|
|
516
511
|
|
|
517
512
|
Parameters
|
|
518
513
|
----------
|
|
@@ -520,6 +515,6 @@ class ModelDataWriter:
|
|
|
520
515
|
format identifier
|
|
521
516
|
|
|
522
517
|
"""
|
|
523
|
-
if product_data_format
|
|
524
|
-
product_data_format = "
|
|
525
|
-
return product_data_format
|
|
518
|
+
if product_data_format is None and output_file is not None:
|
|
519
|
+
product_data_format = Path(output_file).suffix.lstrip(".")
|
|
520
|
+
return "ascii.ecsv" if product_data_format == "ecsv" else product_data_format
|
simtools/data_model/schema.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Module providing functionality to read and validate dictionaries using schema."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
from functools import lru_cache
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
import jsonschema
|
|
@@ -153,6 +154,7 @@ def _validate_meta_schema_url(data):
|
|
|
153
154
|
raise FileNotFoundError(f"Meta schema URL does not exist: {data['meta_schema_url']}")
|
|
154
155
|
|
|
155
156
|
|
|
157
|
+
@lru_cache
|
|
156
158
|
def _retrieve_yaml_schema_from_uri(uri):
|
|
157
159
|
"""Load schema from a file URI."""
|
|
158
160
|
path = SCHEMA_PATH / Path(uri.removeprefix("file:/"))
|
|
@@ -928,9 +928,7 @@ class DataValidator:
|
|
|
928
928
|
"""Return value as sorted list."""
|
|
929
929
|
return [value] if isinstance(value, str) else sorted(value)
|
|
930
930
|
|
|
931
|
-
instrument_sites = []
|
|
932
|
-
for inst in instruments:
|
|
933
|
-
instrument_sites.append(names.get_site_from_array_element_name(inst))
|
|
931
|
+
instrument_sites = [names.get_site_from_array_element_name(inst) for inst in instruments]
|
|
934
932
|
# names.get_site_from_array_element_name might return a list
|
|
935
933
|
flat_sites = [
|
|
936
934
|
s
|
simtools/db/db_handler.py
CHANGED
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
+
from simtools import settings
|
|
7
8
|
from simtools.data_model import validate_data
|
|
8
9
|
from simtools.db.mongo_db import MongoDBHandler
|
|
9
10
|
from simtools.io import io_handler
|
|
@@ -20,11 +21,6 @@ class DatabaseHandler:
|
|
|
20
21
|
|
|
21
22
|
- db_simulation_model_version (from db_config): version of the simulation model database
|
|
22
23
|
- model_version (from production_tables): version of the model contained in the database
|
|
23
|
-
|
|
24
|
-
Parameters
|
|
25
|
-
----------
|
|
26
|
-
db_config: dict
|
|
27
|
-
Dictionary with the DB configuration.
|
|
28
24
|
"""
|
|
29
25
|
|
|
30
26
|
ALLOWED_FILE_EXTENSIONS = [".dat", ".txt", ".lis", ".cfg", ".yml", ".yaml", ".ecsv"]
|
|
@@ -33,13 +29,17 @@ class DatabaseHandler:
|
|
|
33
29
|
model_parameters_cached = {}
|
|
34
30
|
model_versions_cached = {}
|
|
35
31
|
|
|
36
|
-
def __init__(self
|
|
32
|
+
def __init__(self):
|
|
37
33
|
"""Initialize the DatabaseHandler class."""
|
|
38
34
|
self._logger = logging.getLogger(__name__)
|
|
39
35
|
|
|
40
|
-
self.db_config =
|
|
36
|
+
self.db_config = (
|
|
37
|
+
MongoDBHandler.validate_db_config(dict(settings.config.db_config))
|
|
38
|
+
if settings.config.db_config
|
|
39
|
+
else None
|
|
40
|
+
)
|
|
41
41
|
self.io_handler = io_handler.IOHandler()
|
|
42
|
-
self.mongo_db_handler = MongoDBHandler(db_config) if self.db_config else None
|
|
42
|
+
self.mongo_db_handler = MongoDBHandler(self.db_config) if self.db_config else None
|
|
43
43
|
|
|
44
44
|
self.db_name = (
|
|
45
45
|
MongoDBHandler.get_db_name(
|
|
@@ -50,6 +50,17 @@ class DatabaseHandler:
|
|
|
50
50
|
else None
|
|
51
51
|
)
|
|
52
52
|
|
|
53
|
+
def is_configured(self):
|
|
54
|
+
"""
|
|
55
|
+
Check if the DatabaseHandler is configured.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
bool
|
|
60
|
+
True if the DatabaseHandler is configured, False otherwise.
|
|
61
|
+
"""
|
|
62
|
+
return self.mongo_db_handler is not None
|
|
63
|
+
|
|
53
64
|
def get_db_name(self, db_name=None, db_simulation_model_version=None, model_name=None):
|
|
54
65
|
"""Build DB name from configuration."""
|
|
55
66
|
if db_name:
|
|
@@ -249,9 +260,7 @@ class DatabaseHandler:
|
|
|
249
260
|
collection,
|
|
250
261
|
)
|
|
251
262
|
if cache_dict:
|
|
252
|
-
self._logger.debug(f"Found {array_element} in cache (key: {cache_key})")
|
|
253
263
|
return cache_dict
|
|
254
|
-
self._logger.debug(f"Did not find {array_element} in cache (key: {cache_key})")
|
|
255
264
|
|
|
256
265
|
try:
|
|
257
266
|
parameter_version_table = production_table["parameters"][array_element]
|
|
@@ -862,6 +871,10 @@ class DatabaseHandler:
|
|
|
862
871
|
array_element_name,
|
|
863
872
|
]
|
|
864
873
|
except KeyError as exc:
|
|
874
|
+
# simplified model definitions when e.g. adding new telescopes without design model
|
|
875
|
+
if settings.config.args.get("ignore_missing_design_model", False):
|
|
876
|
+
element_type = names.get_array_element_type_from_name(array_element_name)
|
|
877
|
+
return [array_element_name, f"{element_type}-01", f"{element_type}-design"]
|
|
865
878
|
raise KeyError(
|
|
866
879
|
f"Failed generated array element list for db query for {array_element_name}"
|
|
867
880
|
) from exc
|
simtools/db/mongo_db.py
CHANGED
|
@@ -4,7 +4,7 @@ import io
|
|
|
4
4
|
import logging
|
|
5
5
|
import re
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from threading import Lock
|
|
7
|
+
from threading import Lock as _Lock
|
|
8
8
|
|
|
9
9
|
import gridfs
|
|
10
10
|
import jsonschema
|
|
@@ -126,7 +126,7 @@ class MongoDBHandler: # pylint: disable=unsubscriptable-object
|
|
|
126
126
|
"""
|
|
127
127
|
|
|
128
128
|
db_client: MongoClient = None
|
|
129
|
-
_lock =
|
|
129
|
+
_lock = _Lock()
|
|
130
130
|
_logger = logging.getLogger(__name__)
|
|
131
131
|
|
|
132
132
|
def __init__(self, db_config=None):
|
simtools/dependencies.py
CHANGED
|
@@ -9,27 +9,26 @@ This modules provides two main functionalities:
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import logging
|
|
12
|
-
import os
|
|
13
12
|
import re
|
|
14
13
|
import subprocess
|
|
15
14
|
from pathlib import Path
|
|
16
15
|
|
|
17
16
|
import yaml
|
|
18
17
|
|
|
18
|
+
from simtools import settings
|
|
19
19
|
from simtools.io import ascii_handler
|
|
20
|
+
from simtools.utils import general as gen
|
|
20
21
|
from simtools.version import __version__
|
|
21
22
|
|
|
22
23
|
_logger = logging.getLogger(__name__)
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
def get_version_string(
|
|
26
|
+
def get_version_string(run_time=None):
|
|
26
27
|
"""
|
|
27
28
|
Print the versions of the dependencies.
|
|
28
29
|
|
|
29
30
|
Parameters
|
|
30
31
|
----------
|
|
31
|
-
db_config : dict, optional
|
|
32
|
-
Database configuration dictionary.
|
|
33
32
|
run_time : list, optional
|
|
34
33
|
Runtime environment command (e.g., Docker).
|
|
35
34
|
|
|
@@ -40,10 +39,13 @@ def get_version_string(db_config=None, run_time=None):
|
|
|
40
39
|
|
|
41
40
|
"""
|
|
42
41
|
return (
|
|
43
|
-
f"Database name: {get_database_version_or_name(
|
|
44
|
-
f"Database version: {get_database_version_or_name(
|
|
42
|
+
f"Database name: {get_database_version_or_name(version=False)}\n"
|
|
43
|
+
f"Database version: {get_database_version_or_name(version=True)}\n"
|
|
45
44
|
f"sim_telarray version: {get_sim_telarray_version(run_time)}\n"
|
|
45
|
+
"sim_telarray exe: "
|
|
46
|
+
f"{settings.config.sim_telarray_exe if settings.config.sim_telarray_exe else 'None'}\n"
|
|
46
47
|
f"CORSIKA version: {get_corsika_version(run_time)}\n"
|
|
48
|
+
f"CORSIKA exe: {settings.config.corsika_exe if settings.config.corsika_exe else 'None'}\n"
|
|
47
49
|
f"Build options: {get_build_options(run_time)}\n"
|
|
48
50
|
f"Runtime environment: {run_time if run_time else 'None'}\n"
|
|
49
51
|
)
|
|
@@ -73,14 +75,12 @@ def get_software_version(software):
|
|
|
73
75
|
raise ValueError(f"Unknown software: {software}") from exc
|
|
74
76
|
|
|
75
77
|
|
|
76
|
-
def get_database_version_or_name(
|
|
78
|
+
def get_database_version_or_name(version=True):
|
|
77
79
|
"""
|
|
78
80
|
Get the version or name of the simulation model data base used.
|
|
79
81
|
|
|
80
82
|
Parameters
|
|
81
83
|
----------
|
|
82
|
-
db_config : dict
|
|
83
|
-
Dictionary containing the database configuration.
|
|
84
84
|
version : bool
|
|
85
85
|
If True, return the version of the database. If False, return the name.
|
|
86
86
|
|
|
@@ -91,8 +91,10 @@ def get_database_version_or_name(db_config, version=True):
|
|
|
91
91
|
|
|
92
92
|
"""
|
|
93
93
|
if version:
|
|
94
|
-
return db_config and db_config.get(
|
|
95
|
-
|
|
94
|
+
return settings.config.db_config and settings.config.db_config.get(
|
|
95
|
+
"db_simulation_model_version"
|
|
96
|
+
)
|
|
97
|
+
return settings.config.db_config and settings.config.db_config.get("db_simulation_model")
|
|
96
98
|
|
|
97
99
|
|
|
98
100
|
def get_sim_telarray_version(run_time=None):
|
|
@@ -111,16 +113,13 @@ def get_sim_telarray_version(run_time=None):
|
|
|
111
113
|
str
|
|
112
114
|
Version of the sim_telarray package.
|
|
113
115
|
"""
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
_logger.warning("Environment variable SIMTOOLS_SIMTEL_PATH is not set.")
|
|
116
|
+
if settings.config.sim_telarray_exe is None:
|
|
117
|
+
_logger.warning("sim_telarray environment not configured.")
|
|
117
118
|
return None
|
|
118
|
-
sim_telarray_path = Path(sim_telarray_path) / "sim_telarray" / "bin" / "sim_telarray"
|
|
119
|
-
|
|
120
119
|
if run_time is None:
|
|
121
|
-
command = [str(
|
|
120
|
+
command = [str(settings.config.sim_telarray_exe), "--version"]
|
|
122
121
|
else:
|
|
123
|
-
command = [*run_time, str(
|
|
122
|
+
command = [*run_time, str(settings.config.sim_telarray_exe), "--version"]
|
|
124
123
|
|
|
125
124
|
_logger.debug(f"Running command: {command}")
|
|
126
125
|
result = subprocess.run(command, capture_output=True, text=True, check=False)
|
|
@@ -151,19 +150,15 @@ def get_corsika_version(run_time=None):
|
|
|
151
150
|
str
|
|
152
151
|
Version of the CORSIKA package.
|
|
153
152
|
"""
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
_logger.warning("Environment variable SIMTOOLS_SIMTEL_PATH is not set.")
|
|
153
|
+
if settings.config.corsika_exe is None:
|
|
154
|
+
_logger.warning("CORSIKA environment not configured.")
|
|
157
155
|
return None
|
|
158
|
-
corsika_command = Path(corsika_path) / "corsika-run" / "corsika"
|
|
159
156
|
|
|
160
157
|
if run_time is None:
|
|
161
|
-
command = [str(
|
|
158
|
+
command = [str(settings.config.corsika_exe)]
|
|
162
159
|
else:
|
|
163
|
-
command = [*run_time, str(
|
|
160
|
+
command = [*run_time, str(settings.config.corsika_exe)]
|
|
164
161
|
|
|
165
|
-
# Below I do not use the standard context manager because
|
|
166
|
-
# it makes mocking in the tests significantly more difficult
|
|
167
162
|
process = subprocess.Popen( # pylint: disable=consider-using-with
|
|
168
163
|
command,
|
|
169
164
|
stdout=subprocess.PIPE,
|
|
@@ -197,9 +192,14 @@ def get_corsika_version(run_time=None):
|
|
|
197
192
|
|
|
198
193
|
def get_build_options(run_time=None):
|
|
199
194
|
"""
|
|
200
|
-
Return CORSIKA / sim_telarray build options.
|
|
195
|
+
Return CORSIKA / sim_telarray config and build options.
|
|
196
|
+
|
|
197
|
+
For CORSIKA / sim_telarray build for simtools version >0.25.0:
|
|
198
|
+
expects build_opts.yml file in each CORSIKA and sim_telarray
|
|
199
|
+
directories.
|
|
201
200
|
|
|
202
|
-
|
|
201
|
+
For CORSIKA / sim_telarray build for simtools version <=0.25.0:
|
|
202
|
+
expects a build_opts.yml file in the sim_telarray directory.
|
|
203
203
|
|
|
204
204
|
Parameters
|
|
205
205
|
----------
|
|
@@ -209,28 +209,71 @@ def get_build_options(run_time=None):
|
|
|
209
209
|
Returns
|
|
210
210
|
-------
|
|
211
211
|
dict
|
|
212
|
-
|
|
212
|
+
CORSIKA / sim_telarray build options.
|
|
213
213
|
"""
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
build_opts = {}
|
|
215
|
+
for package in ["corsika", "sim_telarray"]:
|
|
216
|
+
path = _get_package_path(package)
|
|
217
|
+
if not path:
|
|
218
|
+
continue
|
|
219
|
+
try:
|
|
220
|
+
build_opts.update(_get_build_options_from_file(path / "build_opts.yml", run_time))
|
|
221
|
+
except (FileNotFoundError, TypeError, ValueError):
|
|
222
|
+
# legacy fallback only for sim_telarray
|
|
223
|
+
if package == "sim_telarray":
|
|
224
|
+
try:
|
|
225
|
+
legacy_path = path.parent / "build_opts.yml"
|
|
226
|
+
build_opts.update(_get_build_options_from_file(legacy_path, run_time))
|
|
227
|
+
except (FileNotFoundError, TypeError, ValueError):
|
|
228
|
+
_logger.debug(f"No build options found for {package}.")
|
|
229
|
+
if not build_opts:
|
|
230
|
+
raise FileNotFoundError("No build option file found.")
|
|
231
|
+
|
|
232
|
+
return build_opts
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _get_package_path(package):
|
|
236
|
+
"""Get the package path from settings or environment variables."""
|
|
237
|
+
path = getattr(settings.config, f"{package}_path")
|
|
238
|
+
if path is None:
|
|
239
|
+
path = gen.load_environment_variables().get(f"{package}_path")
|
|
240
|
+
return Path(path) if path else None
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _get_build_options_from_file(build_opts_path, run_time=None):
|
|
244
|
+
"""Read build options from file."""
|
|
220
245
|
if run_time is None:
|
|
221
246
|
try:
|
|
222
247
|
return ascii_handler.collect_data_from_file(build_opts_path)
|
|
223
248
|
except FileNotFoundError as exc:
|
|
224
|
-
raise FileNotFoundError("No
|
|
249
|
+
raise FileNotFoundError("No build option file found.") from exc
|
|
225
250
|
|
|
226
251
|
command = [*run_time, "cat", str(build_opts_path)]
|
|
227
|
-
_logger.debug(f"Reading
|
|
252
|
+
_logger.debug(f"Reading build option with command: {command}")
|
|
228
253
|
|
|
229
254
|
result = subprocess.run(command, capture_output=True, text=True, check=False)
|
|
230
255
|
if result.returncode:
|
|
231
|
-
raise FileNotFoundError(f"No
|
|
256
|
+
raise FileNotFoundError(f"No build option file found in container: {result.stderr}")
|
|
232
257
|
|
|
233
258
|
try:
|
|
234
259
|
return yaml.safe_load(result.stdout)
|
|
235
260
|
except yaml.YAMLError as exc:
|
|
236
261
|
raise ValueError(f"Error parsing build_opts.yml from container: {exc}") from exc
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def export_build_info(output_file, run_time=None):
|
|
265
|
+
"""
|
|
266
|
+
Export build and version information to a file.
|
|
267
|
+
|
|
268
|
+
Parameters
|
|
269
|
+
----------
|
|
270
|
+
output_file : str
|
|
271
|
+
Path to the output file.
|
|
272
|
+
run_time : list, optional
|
|
273
|
+
Runtime environment command (e.g., Docker).
|
|
274
|
+
"""
|
|
275
|
+
build_info = get_build_options(run_time)
|
|
276
|
+
build_info["simtools"] = __version__
|
|
277
|
+
build_info["database_name"] = get_database_version_or_name(version=False)
|
|
278
|
+
build_info["database_version"] = get_database_version_or_name(version=True)
|
|
279
|
+
ascii_handler.write_data_to_file(data=build_info, output_file=Path(output_file))
|