gammasimtools 0.16.0__py3-none-any.whl → 0.17.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.16.0.dist-info → gammasimtools-0.17.0.dist-info}/METADATA +4 -2
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.17.0.dist-info}/RECORD +60 -54
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.17.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.17.0.dist-info}/entry_points.txt +3 -1
- simtools/_version.py +2 -2
- simtools/applications/derive_ctao_array_layouts.py +5 -5
- simtools/applications/generate_simtel_event_data.py +36 -46
- simtools/applications/merge_tables.py +104 -0
- simtools/applications/plot_array_layout.py +145 -258
- simtools/applications/production_derive_corsika_limits.py +35 -220
- simtools/applications/production_derive_statistics.py +77 -43
- simtools/applications/simulate_light_emission.py +1 -0
- simtools/applications/simulate_prod.py +30 -18
- simtools/applications/simulate_prod_htcondor_generator.py +0 -1
- simtools/applications/submit_array_layouts.py +93 -0
- simtools/applications/verify_simulation_model_production_tables.py +52 -0
- simtools/camera/camera_efficiency.py +3 -3
- simtools/configuration/commandline_parser.py +28 -34
- simtools/configuration/configurator.py +0 -4
- simtools/corsika/corsika_config.py +17 -12
- simtools/corsika/primary_particle.py +46 -13
- simtools/data_model/metadata_collector.py +7 -3
- simtools/db/db_handler.py +11 -11
- simtools/db/db_model_upload.py +2 -2
- simtools/io_operations/io_handler.py +2 -2
- simtools/io_operations/io_table_handler.py +345 -0
- simtools/job_execution/htcondor_script_generator.py +2 -2
- simtools/job_execution/job_manager.py +7 -121
- simtools/layout/array_layout_utils.py +385 -0
- simtools/model/array_model.py +5 -0
- simtools/model/model_repository.py +134 -0
- simtools/production_configuration/{calculate_statistical_errors_grid_point.py → calculate_statistical_uncertainties_grid_point.py} +101 -112
- simtools/production_configuration/derive_corsika_limits.py +239 -111
- simtools/production_configuration/derive_corsika_limits_grid.py +189 -0
- simtools/production_configuration/derive_production_statistics.py +57 -26
- simtools/production_configuration/derive_production_statistics_handler.py +70 -37
- simtools/production_configuration/interpolation_handler.py +296 -94
- simtools/ray_tracing/ray_tracing.py +7 -6
- simtools/reporting/docs_read_parameters.py +104 -62
- simtools/runners/corsika_simtel_runner.py +4 -1
- simtools/runners/runner_services.py +5 -4
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +41 -0
- simtools/schemas/production_configuration_metrics.schema.yml +2 -2
- simtools/simtel/simtel_config_writer.py +34 -14
- simtools/simtel/simtel_io_event_reader.py +301 -194
- simtools/simtel/simtel_io_event_writer.py +207 -227
- simtools/simtel/simtel_io_file_info.py +9 -4
- simtools/simtel/simtel_io_metadata.py +20 -5
- simtools/simtel/simulator_array.py +2 -2
- simtools/simtel/simulator_light_emission.py +79 -34
- simtools/simtel/simulator_ray_tracing.py +2 -2
- simtools/simulator.py +101 -68
- simtools/testing/validate_output.py +4 -1
- simtools/utils/general.py +1 -1
- simtools/utils/names.py +5 -5
- simtools/visualization/plot_array_layout.py +242 -0
- simtools/visualization/plot_pixels.py +681 -0
- simtools/visualization/visualize.py +3 -219
- simtools/applications/production_generate_simulation_config.py +0 -152
- simtools/layout/ctao_array_layouts.py +0 -172
- simtools/production_configuration/generate_simulation_config.py +0 -158
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.17.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.17.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
"""Retrieve, merge, and write layout dictionaries."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import simtools.utils.general as gen
|
|
7
|
+
from simtools.data_model import data_reader
|
|
8
|
+
from simtools.data_model.metadata_collector import MetadataCollector
|
|
9
|
+
from simtools.data_model.model_data_writer import ModelDataWriter
|
|
10
|
+
from simtools.io_operations import io_handler
|
|
11
|
+
from simtools.model.array_model import ArrayModel
|
|
12
|
+
from simtools.model.site_model import SiteModel
|
|
13
|
+
from simtools.utils import names
|
|
14
|
+
|
|
15
|
+
_logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def retrieve_ctao_array_layouts(site, repository_url, branch_name="main"):
|
|
19
|
+
"""
|
|
20
|
+
Retrieve array layouts from CTAO common identifiers repository.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
site : str
|
|
25
|
+
Site identifier.
|
|
26
|
+
repository_url : str
|
|
27
|
+
URL or path to CTAO common identifiers
|
|
28
|
+
branch_name : str
|
|
29
|
+
Repository branch to use for CTAO common identifiers.
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
dict
|
|
34
|
+
Array layouts for all CTAO sites.
|
|
35
|
+
"""
|
|
36
|
+
_logger.info(f"Retrieving array layouts from {repository_url} on branch {branch_name}.")
|
|
37
|
+
|
|
38
|
+
if gen.is_url(repository_url):
|
|
39
|
+
array_element_ids = gen.collect_data_from_http(
|
|
40
|
+
url=f"{repository_url}/{branch_name}/array-element-ids.json"
|
|
41
|
+
)
|
|
42
|
+
sub_arrays = gen.collect_data_from_http(
|
|
43
|
+
url=f"{repository_url}/{branch_name}/subarray-ids.json"
|
|
44
|
+
)
|
|
45
|
+
else:
|
|
46
|
+
array_element_ids = gen.collect_data_from_file(
|
|
47
|
+
Path(repository_url) / "array-element-ids.json"
|
|
48
|
+
)
|
|
49
|
+
sub_arrays = gen.collect_data_from_file(Path(repository_url) / "subarray-ids.json")
|
|
50
|
+
|
|
51
|
+
return _get_ctao_layouts_per_site(site, sub_arrays, array_element_ids)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _get_ctao_layouts_per_site(site, sub_arrays, array_element_ids):
|
|
55
|
+
"""
|
|
56
|
+
Get array layouts for CTAO sites.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
site : str
|
|
61
|
+
Site identifier.
|
|
62
|
+
sub_arrays : dict
|
|
63
|
+
Sub-array definitions.
|
|
64
|
+
array_element_ids : dict
|
|
65
|
+
Array element definitions.
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
dict
|
|
70
|
+
Array layouts for CTAO sites.
|
|
71
|
+
"""
|
|
72
|
+
layouts_per_site = []
|
|
73
|
+
|
|
74
|
+
for array in sub_arrays.get("subarrays", []):
|
|
75
|
+
elements = []
|
|
76
|
+
for ids in array.get("array_element_ids", []):
|
|
77
|
+
element_name = _get_ctao_array_element_name(ids, array_element_ids)
|
|
78
|
+
if names.get_site_from_array_element_name(element_name) != site:
|
|
79
|
+
break
|
|
80
|
+
elements.append(element_name)
|
|
81
|
+
if len(elements) > 0:
|
|
82
|
+
array_layout = {
|
|
83
|
+
"name": array.get("name"),
|
|
84
|
+
"elements": elements,
|
|
85
|
+
}
|
|
86
|
+
layouts_per_site.append(array_layout)
|
|
87
|
+
|
|
88
|
+
_logger.info(f"CTAO array layout definition: {layouts_per_site}")
|
|
89
|
+
return layouts_per_site
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _get_ctao_array_element_name(ids, array_element_ids):
|
|
93
|
+
"""Return array element name for common identifier."""
|
|
94
|
+
for element in array_element_ids.get("array_elements", []):
|
|
95
|
+
if element.get("id") == ids:
|
|
96
|
+
return element.get("name")
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def merge_array_layouts(layouts_1, layouts_2):
|
|
101
|
+
"""
|
|
102
|
+
Compare two array layout dictionaries and merge them.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
layouts_1 : dict
|
|
107
|
+
Array layout dictionary 1.
|
|
108
|
+
layouts_2 : dict
|
|
109
|
+
Array layout dictionary 2.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
dict
|
|
114
|
+
Merged array layout dictionary based on layout_1.
|
|
115
|
+
"""
|
|
116
|
+
merged_layout = layouts_1
|
|
117
|
+
for layout_2 in layouts_2:
|
|
118
|
+
layout_found = False
|
|
119
|
+
for layout_1 in layouts_1.get("value", {}):
|
|
120
|
+
if sorted(layout_1["elements"]) == sorted(layout_2["elements"]):
|
|
121
|
+
print(
|
|
122
|
+
f"Equal telescope list: simtools '{layout_1['name']}' "
|
|
123
|
+
f"and CTAO '{layout_2['name']}'"
|
|
124
|
+
)
|
|
125
|
+
layout_1["name"] = layout_2["name"]
|
|
126
|
+
layout_found = True
|
|
127
|
+
if not layout_found:
|
|
128
|
+
merged_layout["value"].append(
|
|
129
|
+
{
|
|
130
|
+
"name": layout_2["name"],
|
|
131
|
+
"elements": layout_2["elements"],
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
_logger.info(f"Adding {layout_2['name']} with {layout_2['elements']}")
|
|
135
|
+
return merged_layout
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def write_array_layouts(array_layouts, args_dict, db_config):
|
|
139
|
+
"""
|
|
140
|
+
Write array layouts as model parameter.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
args_dict : dict
|
|
145
|
+
Command line arguments.
|
|
146
|
+
array_layouts : dict
|
|
147
|
+
Array layouts to be written.
|
|
148
|
+
db_config : dict
|
|
149
|
+
Database configuration.
|
|
150
|
+
"""
|
|
151
|
+
site = args_dict.get("site") or array_layouts.get("site")
|
|
152
|
+
_logger.info(f"Writing updated array layouts to the database for site {site}.")
|
|
153
|
+
|
|
154
|
+
io_handler_instance = io_handler.IOHandler()
|
|
155
|
+
io_handler_instance.set_paths(
|
|
156
|
+
output_path=args_dict["output_path"],
|
|
157
|
+
use_plain_output_path=args_dict["use_plain_output_path"],
|
|
158
|
+
)
|
|
159
|
+
output_file = io_handler_instance.get_output_file(
|
|
160
|
+
f"array-layouts-{args_dict['updated_parameter_version']}.json"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
ModelDataWriter.dump_model_parameter(
|
|
164
|
+
parameter_name="array_layouts",
|
|
165
|
+
value=array_layouts["value"],
|
|
166
|
+
instrument=site,
|
|
167
|
+
parameter_version=args_dict.get("updated_parameter_version"),
|
|
168
|
+
output_file=output_file,
|
|
169
|
+
use_plain_output_path=args_dict["use_plain_output_path"],
|
|
170
|
+
db_config=db_config,
|
|
171
|
+
)
|
|
172
|
+
MetadataCollector.dump(
|
|
173
|
+
args_dict,
|
|
174
|
+
output_file,
|
|
175
|
+
add_activity_name=True,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def validate_array_layouts_with_db(production_table, array_layouts):
|
|
180
|
+
"""
|
|
181
|
+
Validate array layouts against the production table in the database.
|
|
182
|
+
|
|
183
|
+
Confirm that every telescope defined in the array layouts exist in the
|
|
184
|
+
production table.
|
|
185
|
+
|
|
186
|
+
Parameters
|
|
187
|
+
----------
|
|
188
|
+
production_table : dict
|
|
189
|
+
Production table from the database.
|
|
190
|
+
array_layouts : dict
|
|
191
|
+
Array layouts to be validated.
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
dict
|
|
196
|
+
Validated array layouts.
|
|
197
|
+
"""
|
|
198
|
+
db_elements = set(production_table.get("parameters", {}).keys())
|
|
199
|
+
|
|
200
|
+
invalid_array_elements = [
|
|
201
|
+
e
|
|
202
|
+
for layout in array_layouts.get("value", [])
|
|
203
|
+
for e in layout.get("elements", [])
|
|
204
|
+
if e not in db_elements
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
if invalid_array_elements:
|
|
208
|
+
raise ValueError(f"Invalid array elements found: {invalid_array_elements}. ")
|
|
209
|
+
|
|
210
|
+
return array_layouts
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def get_array_layouts_from_parameter_file(
|
|
214
|
+
file_path, model_version, db_config, coordinate_system="ground"
|
|
215
|
+
):
|
|
216
|
+
"""
|
|
217
|
+
Retrieve array layouts from parameter file.
|
|
218
|
+
|
|
219
|
+
Parameters
|
|
220
|
+
----------
|
|
221
|
+
file_path : str or Path
|
|
222
|
+
Path to the array layout parameter file.
|
|
223
|
+
model_version : str
|
|
224
|
+
Model version to retrieve.
|
|
225
|
+
db_config : dict
|
|
226
|
+
Database configuration.
|
|
227
|
+
coordinate_system : str
|
|
228
|
+
Coordinate system to use for the array elements (default is "ground").
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
list
|
|
233
|
+
List of dictionaries containing array layout names and their elements.
|
|
234
|
+
"""
|
|
235
|
+
array_layouts = gen.collect_data_from_file(file_path)
|
|
236
|
+
try:
|
|
237
|
+
value = array_layouts["value"]
|
|
238
|
+
except KeyError as exc:
|
|
239
|
+
raise ValueError("Missing 'value' key in layout file.") from exc
|
|
240
|
+
site = array_layouts.get("site")
|
|
241
|
+
|
|
242
|
+
layouts = []
|
|
243
|
+
for layout in value:
|
|
244
|
+
layouts.append(
|
|
245
|
+
_get_array_layout_dict(
|
|
246
|
+
db_config, model_version, site, None, layout["name"], coordinate_system
|
|
247
|
+
)
|
|
248
|
+
)
|
|
249
|
+
return layouts
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def get_array_layouts_from_db(
|
|
253
|
+
layout_name, site, model_version, db_config, coordinate_system="ground"
|
|
254
|
+
):
|
|
255
|
+
"""
|
|
256
|
+
Retrieve all array layouts from the database and return as list of astropy tables.
|
|
257
|
+
|
|
258
|
+
Parameters
|
|
259
|
+
----------
|
|
260
|
+
layout_name : str
|
|
261
|
+
Name of the array layout to retrieve (for None, all layouts are retrieved).
|
|
262
|
+
site : str
|
|
263
|
+
Site identifier.
|
|
264
|
+
model_version : str
|
|
265
|
+
Model version to retrieve.
|
|
266
|
+
db_config : dict
|
|
267
|
+
Database configuration.
|
|
268
|
+
coordinate_system : str
|
|
269
|
+
Coordinate system to use for the array elements (default is "ground").
|
|
270
|
+
|
|
271
|
+
Returns
|
|
272
|
+
-------
|
|
273
|
+
list
|
|
274
|
+
List of dictionaries containing array layout names and their elements.
|
|
275
|
+
"""
|
|
276
|
+
layout_names = []
|
|
277
|
+
if layout_name:
|
|
278
|
+
layout_names.append(layout_name)
|
|
279
|
+
else:
|
|
280
|
+
site_model = SiteModel(site=site, model_version=model_version, mongo_db_config=db_config)
|
|
281
|
+
layout_names = site_model.get_list_of_array_layouts()
|
|
282
|
+
|
|
283
|
+
layouts = []
|
|
284
|
+
for _layout_name in layout_names:
|
|
285
|
+
layouts.append(
|
|
286
|
+
_get_array_layout_dict(
|
|
287
|
+
db_config, model_version, site, None, _layout_name, coordinate_system
|
|
288
|
+
)
|
|
289
|
+
)
|
|
290
|
+
if len(layouts) == 1:
|
|
291
|
+
return layouts[0]
|
|
292
|
+
return layouts
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def get_array_layouts_using_telescope_lists_from_db(
|
|
296
|
+
telescope_lists, site, model_version, db_config, coordinate_system="ground"
|
|
297
|
+
):
|
|
298
|
+
"""
|
|
299
|
+
Retrieve array layouts from the database using telescope lists.
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
telescope_lists : list
|
|
304
|
+
List of telescope lists to retrieve array layouts for.
|
|
305
|
+
site : str
|
|
306
|
+
Site identifier.
|
|
307
|
+
model_version : str
|
|
308
|
+
Model version to retrieve.
|
|
309
|
+
db_config : dict
|
|
310
|
+
Database configuration.
|
|
311
|
+
coordinate_system : str
|
|
312
|
+
Coordinate system to use for the array elements (default is "ground").
|
|
313
|
+
|
|
314
|
+
Returns
|
|
315
|
+
-------
|
|
316
|
+
list
|
|
317
|
+
List of dictionaries containing array layout names and their elements.
|
|
318
|
+
|
|
319
|
+
"""
|
|
320
|
+
layouts = []
|
|
321
|
+
for telescope_list in telescope_lists:
|
|
322
|
+
_site = site
|
|
323
|
+
if _site is None:
|
|
324
|
+
sites = {names.get_site_from_array_element_name(t) for t in telescope_list}
|
|
325
|
+
if len(sites) != 1:
|
|
326
|
+
raise ValueError(
|
|
327
|
+
f"Telescope list contains elements from multiple sites: {sites}."
|
|
328
|
+
"Please specify a site."
|
|
329
|
+
)
|
|
330
|
+
_site = sites.pop()
|
|
331
|
+
|
|
332
|
+
layouts.append(
|
|
333
|
+
_get_array_layout_dict(
|
|
334
|
+
db_config, model_version, _site, telescope_list, None, coordinate_system
|
|
335
|
+
)
|
|
336
|
+
)
|
|
337
|
+
return layouts
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def get_array_layouts_from_file(file_path):
|
|
341
|
+
"""
|
|
342
|
+
Retrieve array layout(s) from astropy table file(s).
|
|
343
|
+
|
|
344
|
+
Parameters
|
|
345
|
+
----------
|
|
346
|
+
file_path : str or Path or list of str or list of Path
|
|
347
|
+
Path(s) to array layout files(s).
|
|
348
|
+
|
|
349
|
+
Returns
|
|
350
|
+
-------
|
|
351
|
+
list
|
|
352
|
+
List of dictionaries containing array layout names and their elements.
|
|
353
|
+
"""
|
|
354
|
+
if isinstance(file_path, str | Path):
|
|
355
|
+
file_path = [file_path]
|
|
356
|
+
|
|
357
|
+
layouts = []
|
|
358
|
+
for _file in file_path:
|
|
359
|
+
layouts.append(
|
|
360
|
+
{
|
|
361
|
+
"name": (Path(_file).name).split(".")[0],
|
|
362
|
+
"array_elements": data_reader.read_table_from_file(file_name=_file),
|
|
363
|
+
}
|
|
364
|
+
)
|
|
365
|
+
return layouts
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def _get_array_layout_dict(
|
|
369
|
+
db_config, model_version, site, telescope_list, layout_name, coordinate_system
|
|
370
|
+
):
|
|
371
|
+
"""Return array layout dictionary for a given telescope list."""
|
|
372
|
+
array_model = ArrayModel(
|
|
373
|
+
mongo_db_config=db_config,
|
|
374
|
+
model_version=model_version,
|
|
375
|
+
site=site,
|
|
376
|
+
array_elements=telescope_list,
|
|
377
|
+
layout_name=layout_name,
|
|
378
|
+
)
|
|
379
|
+
return {
|
|
380
|
+
"name": layout_name if layout_name else "list",
|
|
381
|
+
"site": site,
|
|
382
|
+
"array_elements": array_model.export_array_elements_as_table(
|
|
383
|
+
coordinate_system=coordinate_system
|
|
384
|
+
),
|
|
385
|
+
}
|
simtools/model/array_model.py
CHANGED
|
@@ -38,6 +38,8 @@ class ArrayModel:
|
|
|
38
38
|
the array element positions).
|
|
39
39
|
sim_telarray_seeds : dict, optional
|
|
40
40
|
Dictionary with configuration for sim_telarray random instrument setup.
|
|
41
|
+
simtel_path: str, Path, optional
|
|
42
|
+
Path to the sim_telarray installation directory.
|
|
41
43
|
"""
|
|
42
44
|
|
|
43
45
|
def __init__(
|
|
@@ -49,6 +51,7 @@ class ArrayModel:
|
|
|
49
51
|
layout_name: str | None = None,
|
|
50
52
|
array_elements: str | Path | list[str] | None = None,
|
|
51
53
|
sim_telarray_seeds: dict | None = None,
|
|
54
|
+
simtel_path: str | Path | None = None,
|
|
52
55
|
):
|
|
53
56
|
"""Initialize ArrayModel."""
|
|
54
57
|
self._logger = logging.getLogger(__name__)
|
|
@@ -69,6 +72,7 @@ class ArrayModel:
|
|
|
69
72
|
self._telescope_model_files_exported = False
|
|
70
73
|
self._array_model_file_exported = False
|
|
71
74
|
self.sim_telarray_seeds = sim_telarray_seeds
|
|
75
|
+
self.simtel_path = simtel_path
|
|
72
76
|
|
|
73
77
|
def _initialize(self, site: str, array_elements_config: str | Path | list[str]):
|
|
74
78
|
"""
|
|
@@ -258,6 +262,7 @@ class ArrayModel:
|
|
|
258
262
|
layout_name=self.layout_name,
|
|
259
263
|
model_version=self.model_version,
|
|
260
264
|
label=self.label,
|
|
265
|
+
simtel_path=self.simtel_path,
|
|
261
266
|
)
|
|
262
267
|
simtel_writer.write_array_config_file(
|
|
263
268
|
config_file_path=self.config_file_path,
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Utilities for managing the simulation models repository.
|
|
2
|
+
|
|
3
|
+
Simulation model parameters and production tables are managed through
|
|
4
|
+
a gitlab repository ('SimulationModels'). This module provides service
|
|
5
|
+
functions to interact with and verify the repository.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from simtools.utils import general as gen
|
|
12
|
+
from simtools.utils import names
|
|
13
|
+
|
|
14
|
+
_logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def verify_simulation_model_production_tables(simulation_models_path):
|
|
18
|
+
"""
|
|
19
|
+
Verify the simulation model production tables in the specified path.
|
|
20
|
+
|
|
21
|
+
Checks that all model parameters defined in the production tables are
|
|
22
|
+
present in the simulation models repository.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
simulation_models_path : str
|
|
27
|
+
Path to the simulation models repository.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
bool
|
|
32
|
+
True if all parameters found, False if any missing.
|
|
33
|
+
"""
|
|
34
|
+
productions_path = Path(simulation_models_path) / "simulation-models" / "productions"
|
|
35
|
+
production_files = list(productions_path.rglob("*.json"))
|
|
36
|
+
|
|
37
|
+
_logger.info(
|
|
38
|
+
f"Verifying {len(production_files)} simulation model production "
|
|
39
|
+
f"tables in {simulation_models_path}"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
missing_files = []
|
|
43
|
+
total_checked = 0
|
|
44
|
+
|
|
45
|
+
for production_file in production_files:
|
|
46
|
+
file_missing, file_checked = _verify_model_parameters_for_production(
|
|
47
|
+
simulation_models_path, production_file
|
|
48
|
+
)
|
|
49
|
+
missing_files.extend(file_missing)
|
|
50
|
+
total_checked += file_checked
|
|
51
|
+
|
|
52
|
+
_logger.info(f"Checked {total_checked} parameters, {len(missing_files)} missing")
|
|
53
|
+
|
|
54
|
+
if missing_files:
|
|
55
|
+
for missing_file in missing_files:
|
|
56
|
+
_logger.error(f"Missing: {missing_file}")
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
_logger.info("Verification passed: All parameters found")
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _verify_model_parameters_for_production(simulation_models_path, production_file):
|
|
64
|
+
"""
|
|
65
|
+
Verify that model parameters defined in the production tables exist.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
simulation_models_path : str
|
|
70
|
+
Path to the simulation models repository.
|
|
71
|
+
production_file : Path
|
|
72
|
+
Path to the production file.
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
tuple
|
|
77
|
+
(missing_files_list, total_checked_count)
|
|
78
|
+
"""
|
|
79
|
+
production_table = gen.collect_data_from_file(production_file)
|
|
80
|
+
missing_files = []
|
|
81
|
+
total_checked = 0
|
|
82
|
+
|
|
83
|
+
parameters = production_table.get("parameters", {})
|
|
84
|
+
for array_element, par_dict in parameters.items():
|
|
85
|
+
if isinstance(par_dict, dict):
|
|
86
|
+
for param_name, param_version in par_dict.items():
|
|
87
|
+
total_checked += 1
|
|
88
|
+
parameter_file = _get_model_parameter_file_path(
|
|
89
|
+
simulation_models_path, array_element, param_name, param_version
|
|
90
|
+
)
|
|
91
|
+
if parameter_file and not parameter_file.exists():
|
|
92
|
+
missing_files.append(str(parameter_file))
|
|
93
|
+
|
|
94
|
+
return missing_files, total_checked
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _get_model_parameter_file_path(
|
|
98
|
+
simulation_models_path, array_element, parameter_name, parameter_version
|
|
99
|
+
):
|
|
100
|
+
"""
|
|
101
|
+
Get the file path for a model parameter.
|
|
102
|
+
|
|
103
|
+
Take into account path structure based on collections and array elements.
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
simulation_models_path : str
|
|
108
|
+
Path to the simulation models repository.
|
|
109
|
+
array_element : str
|
|
110
|
+
Name of the array element (e.g., 'telescope').
|
|
111
|
+
parameter_name : str
|
|
112
|
+
Name of the parameter.
|
|
113
|
+
parameter_version : str
|
|
114
|
+
Version of the parameter.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
Path
|
|
119
|
+
The file path to the model parameter JSON file.
|
|
120
|
+
"""
|
|
121
|
+
collection = names.get_collection_name_from_parameter_name(parameter_name)
|
|
122
|
+
return (
|
|
123
|
+
Path(simulation_models_path)
|
|
124
|
+
/ "simulation-models"
|
|
125
|
+
/ "model_parameters"
|
|
126
|
+
/ (
|
|
127
|
+
collection
|
|
128
|
+
if collection in ("configuration_sim_telarray", "configuration_corsika")
|
|
129
|
+
else ""
|
|
130
|
+
)
|
|
131
|
+
/ (array_element if collection != "configuration_corsika" else "")
|
|
132
|
+
/ parameter_name
|
|
133
|
+
/ f"{parameter_name}-{parameter_version}.json"
|
|
134
|
+
)
|