gammasimtools 0.5.1__py3-none-any.whl → 0.6.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.
Files changed (78) hide show
  1. {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/METADATA +80 -28
  2. gammasimtools-0.6.1.dist-info/RECORD +91 -0
  3. {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/entry_points.txt +4 -2
  5. simtools/_version.py +14 -2
  6. simtools/applications/add_file_to_db.py +2 -1
  7. simtools/applications/compare_cumulative_psf.py +10 -15
  8. simtools/applications/db_development_tools/add_new_parameter_to_db.py +12 -6
  9. simtools/applications/derive_mirror_rnda.py +95 -71
  10. simtools/applications/generate_corsika_histograms.py +216 -131
  11. simtools/applications/generate_default_metadata.py +110 -0
  12. simtools/applications/generate_simtel_array_histograms.py +192 -0
  13. simtools/applications/get_file_from_db.py +1 -1
  14. simtools/applications/get_parameter.py +3 -3
  15. simtools/applications/make_regular_arrays.py +89 -93
  16. simtools/applications/{plot_layout_array.py → plot_array_layout.py} +15 -14
  17. simtools/applications/print_array_elements.py +81 -34
  18. simtools/applications/produce_array_config.py +2 -2
  19. simtools/applications/production.py +39 -5
  20. simtools/applications/sim_showers_for_trigger_rates.py +26 -30
  21. simtools/applications/simulate_prod.py +49 -107
  22. simtools/applications/submit_data_from_external.py +8 -10
  23. simtools/applications/tune_psf.py +16 -18
  24. simtools/applications/validate_camera_efficiency.py +63 -9
  25. simtools/applications/validate_camera_fov.py +9 -13
  26. simtools/applications/validate_file_using_schema.py +127 -0
  27. simtools/applications/validate_optics.py +13 -15
  28. simtools/camera_efficiency.py +73 -80
  29. simtools/configuration/commandline_parser.py +52 -22
  30. simtools/configuration/configurator.py +98 -33
  31. simtools/constants.py +9 -0
  32. simtools/corsika/corsika_config.py +28 -22
  33. simtools/corsika/corsika_default_config.py +282 -0
  34. simtools/corsika/corsika_histograms.py +328 -282
  35. simtools/corsika/corsika_histograms_visualize.py +162 -163
  36. simtools/corsika/corsika_runner.py +8 -4
  37. simtools/corsika_simtel/corsika_simtel_runner.py +18 -23
  38. simtools/data_model/data_reader.py +129 -0
  39. simtools/data_model/metadata_collector.py +346 -118
  40. simtools/data_model/metadata_model.py +123 -218
  41. simtools/data_model/model_data_writer.py +79 -22
  42. simtools/data_model/validate_data.py +96 -46
  43. simtools/db_handler.py +67 -42
  44. simtools/io_operations/__init__.py +0 -0
  45. simtools/io_operations/hdf5_handler.py +112 -0
  46. simtools/{io_handler.py → io_operations/io_handler.py} +51 -22
  47. simtools/job_execution/job_manager.py +1 -1
  48. simtools/layout/{layout_array.py → array_layout.py} +168 -199
  49. simtools/layout/geo_coordinates.py +196 -0
  50. simtools/layout/telescope_position.py +12 -12
  51. simtools/model/array_model.py +16 -14
  52. simtools/model/camera.py +5 -8
  53. simtools/model/mirrors.py +136 -73
  54. simtools/model/model_utils.py +1 -69
  55. simtools/model/telescope_model.py +32 -25
  56. simtools/psf_analysis.py +26 -19
  57. simtools/ray_tracing.py +54 -26
  58. simtools/schemas/data.metaschema.yml +400 -0
  59. simtools/schemas/metadata.metaschema.yml +566 -0
  60. simtools/simtel/simtel_config_writer.py +14 -5
  61. simtools/simtel/simtel_histograms.py +266 -83
  62. simtools/simtel/simtel_runner.py +8 -7
  63. simtools/simtel/simtel_runner_array.py +7 -8
  64. simtools/simtel/simtel_runner_camera_efficiency.py +48 -2
  65. simtools/simtel/simtel_runner_ray_tracing.py +61 -25
  66. simtools/simulator.py +43 -50
  67. simtools/utils/general.py +232 -286
  68. simtools/utils/geometry.py +163 -0
  69. simtools/utils/names.py +294 -142
  70. simtools/visualization/legend_handlers.py +115 -9
  71. simtools/visualization/visualize.py +13 -13
  72. gammasimtools-0.5.1.dist-info/RECORD +0 -83
  73. simtools/applications/plot_simtel_histograms.py +0 -120
  74. simtools/applications/validate_schema_files.py +0 -135
  75. simtools/corsika/corsika_output_visualize.py +0 -345
  76. simtools/data_model/validate_schema.py +0 -285
  77. {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/LICENSE +0 -0
  78. {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/top_level.txt +0 -0
simtools/utils/names.py CHANGED
@@ -1,28 +1,30 @@
1
1
  import logging
2
+ import re
2
3
 
3
4
  _logger = logging.getLogger(__name__)
4
5
 
5
6
  __all__ = [
7
+ "array_element_id_from_telescope_model_name",
6
8
  "camera_efficiency_log_file_name",
7
9
  "camera_efficiency_results_file_name",
8
10
  "camera_efficiency_simtel_file_name",
9
- "convert_telescope_model_name_to_yaml",
11
+ "convert_telescope_model_name_to_yaml_name",
10
12
  "get_site_from_telescope_name",
11
- "get_telescope_type",
12
- "is_valid_name",
13
+ "get_telescope_class",
13
14
  "layout_telescope_list_file_name",
14
15
  "ray_tracing_file_name",
15
16
  "ray_tracing_plot_file_name",
16
17
  "ray_tracing_results_file_name",
18
+ "sanitize_name",
17
19
  "simtel_array_config_file_name",
20
+ "simtel_single_mirror_list_file_name",
18
21
  "simtel_telescope_config_file_name",
19
- "simtools_instrument_name",
22
+ "get_telescope_name_db",
20
23
  "split_telescope_model_name",
21
- "validate_camera_name",
22
- "validate_layout_array_name",
24
+ "telescope_model_name_from_array_element_id",
25
+ "translate_simtools_to_corsika",
26
+ "validate_array_layout_name",
23
27
  "validate_model_version_name",
24
- "validate_name",
25
- "validate_simtel_mode_name",
26
28
  "validate_site_name",
27
29
  "validate_sub_system_name",
28
30
  "validate_telescope_id_name",
@@ -34,28 +36,40 @@ lst = "LST"
34
36
  mst = "MST"
35
37
  sct = "SCT"
36
38
  sst = "SST"
39
+ hess = "HESS"
40
+ magic = "MAGIC"
41
+ veritas = "VERITAS"
37
42
 
38
43
  all_telescope_class_names = {
39
44
  lst: ["lst"],
40
45
  mst: ["mst"],
41
46
  sct: ["sct"],
42
47
  sst: ["sst"],
48
+ hess: ["hess"],
49
+ magic: ["magic"],
50
+ veritas: ["veritas"],
43
51
  }
44
52
 
45
- all_camera_names = {
46
- "SST": ["sst"],
53
+ all_subsystem_names = {
54
+ "SST": ["sst", "ssts", "SSTS"],
47
55
  "ASTRI": ["astri"],
48
56
  "GCT": ["gct", "gct-s"],
49
57
  "1M": ["1m"],
50
- "FlashCam": ["flashcam", "flash-cam"],
51
- "NectarCam": ["nectarcam", "nectar-cam"],
52
- "SCT": ["sct"],
53
- "LST": ["lst"],
58
+ "FlashCam": ["flashcam", "flash-cam", "msts", "MSTS"],
59
+ "NectarCam": ["nectarcam", "nectar-cam", "mstn", "MSTN"],
60
+ "SCT": ["sct", "scts", "SCTS"],
61
+ "LST": ["lst", "lsts", "LSTS", "lstn", "LSTN"],
62
+ "Camera": ["Camera", "camera"],
63
+ "Structure": ["Structure", "structure"],
64
+ "MAGIC": ["magic", "MAGIC"],
65
+ "VERITAS": ["veritas", "VERITAS"],
66
+ "HESS": ["hess", "HESS"],
54
67
  }
55
68
 
56
- all_structure_names = {"Structure": ["Structure", "structure"]}
57
-
58
- all_site_names = {"South": ["paranal", "south"], "North": ["lapalma", "north"]}
69
+ all_site_names = {
70
+ "South": ["paranal", "south", "cta-south", "ctao-south", "s"],
71
+ "North": ["lapalma", "north", "cta-north", "ctao-north", "n"],
72
+ }
59
73
 
60
74
  all_model_version_names = {
61
75
  "2015-07-21": [""],
@@ -76,21 +90,11 @@ all_model_version_names = {
76
90
  "2020-06-28": ["prod5"],
77
91
  "prod4-prototype": [""],
78
92
  "default": [],
79
- "Current": [],
93
+ "Released": [],
80
94
  "Latest": [],
81
95
  }
82
96
 
83
- all_simtel_mode_names = {
84
- "RayTracing": ["raytracing", "ray-tracing"],
85
- "RayTracingSingleMirror": [
86
- "raytracing-singlemirror",
87
- "ray-tracing-singlemirror",
88
- "ray-tracing-single-mirror",
89
- ],
90
- "Trigger": ["trigger"],
91
- }
92
-
93
- all_layout_array_names = {
97
+ all_array_layout_names = {
94
98
  "4LST": ["4-lst", "4lst"],
95
99
  "1LST": ["1-lst", "1lst"],
96
100
  "4MST": ["4-mst", "4mst"],
@@ -101,8 +105,16 @@ all_layout_array_names = {
101
105
  "TestLayout": ["test-layout"],
102
106
  }
103
107
 
104
- corsika_to_simtools_names = {
105
- "OBSLEV": "corsika_obs_level",
108
+ # array elements as defined by CTAO
109
+ # (includes for now only telescopes;
110
+ # can be extended to other elements)
111
+ all_array_element_id_names = {
112
+ "lstn": ["LSTN", "lstn"],
113
+ "mstn": ["MSTN", "mstn"],
114
+ "lsts": ["LSTS", "lsts"],
115
+ "msts": ["MSTS", "msts"],
116
+ "ssts": ["SSTS", "ssts"],
117
+ "scts": ["SCTS", "scts"],
106
118
  }
107
119
 
108
120
 
@@ -120,24 +132,24 @@ def validate_sub_system_name(name):
120
132
  str
121
133
  Validated name.
122
134
  """
123
- return validate_name(name, {**all_camera_names, **all_structure_names})
135
+ return _validate_name(name, all_subsystem_names)
124
136
 
125
137
 
126
- def validate_camera_name(name):
138
+ def validate_telescope_class_name(name):
127
139
  """
128
- Validate a camera name.
140
+ Validate a telescope class name (LST, MST, SST, ...).
129
141
 
130
142
  Parameters
131
143
  ----------
132
144
  name: str
133
- Camera name
145
+ Telescope class name.
134
146
 
135
147
  Returns
136
148
  -------
137
149
  str
138
150
  Validated name.
139
151
  """
140
- return validate_name(name, all_camera_names)
152
+ return _validate_name(name, all_telescope_class_names)
141
153
 
142
154
 
143
155
  def validate_telescope_id_name(name):
@@ -146,11 +158,11 @@ def validate_telescope_id_name(name):
146
158
 
147
159
  Valid names e.g.,
148
160
  - D
149
- - telescope ID
161
+ - telescope ID (e.g., 1, 5, 15)
150
162
 
151
163
  Parameters
152
164
  ----------
153
- name: str
165
+ name: str or int
154
166
  Telescope ID name.
155
167
 
156
168
  Returns
@@ -164,8 +176,8 @@ def validate_telescope_id_name(name):
164
176
  If name is not valid.
165
177
  """
166
178
 
167
- if name == "D" or name.isdigit():
168
- return name
179
+ if isinstance(name, int) or name.upper() in ("D", "D234", "TEST") or name.isdigit():
180
+ return str(name).upper()
169
181
 
170
182
  msg = f"Invalid telescope ID name {name}"
171
183
  _logger.error(msg)
@@ -186,24 +198,7 @@ def validate_model_version_name(name):
186
198
  str
187
199
  Validated name.
188
200
  """
189
- return validate_name(name, all_model_version_names)
190
-
191
-
192
- def validate_simtel_mode_name(name):
193
- """
194
- Validate a sim_telarray mode name.
195
-
196
- Parameters
197
- ----------
198
- name: str
199
- sim_telarray mode name.
200
-
201
- Returns
202
- -------
203
- str
204
- Validated name.
205
- """
206
- return validate_name(name, all_simtel_mode_names)
201
+ return _validate_name(name, all_model_version_names)
207
202
 
208
203
 
209
204
  def validate_site_name(name):
@@ -220,12 +215,12 @@ def validate_site_name(name):
220
215
  str
221
216
  Validated name.
222
217
  """
223
- return validate_name(name, all_site_names)
218
+ return _validate_name(name, all_site_names)
224
219
 
225
220
 
226
- def validate_layout_array_name(name):
221
+ def validate_array_layout_name(name):
227
222
  """
228
- Validate a layout array name.
223
+ Validate a array layout name.
229
224
 
230
225
  Parameters
231
226
  ----------
@@ -237,10 +232,10 @@ def validate_layout_array_name(name):
237
232
  str
238
233
  Validated name.
239
234
  """
240
- return validate_name(name, all_layout_array_names)
235
+ return _validate_name(name, all_array_layout_names)
241
236
 
242
237
 
243
- def validate_name(name, all_names):
238
+ def _validate_name(name, all_names):
244
239
  """
245
240
  Validate a name given the all_names options. For each key in all_names, a list of options is \
246
241
  given. If name is in this list, the key name is returned.
@@ -262,7 +257,7 @@ def validate_name(name, all_names):
262
257
  If name is not valid.
263
258
  """
264
259
 
265
- if not is_valid_name(name, all_names):
260
+ if not _is_valid_name(name, all_names):
266
261
  msg = f"Invalid name {name}"
267
262
  raise ValueError(msg)
268
263
  for main_name, list_of_names in all_names.items():
@@ -273,7 +268,7 @@ def validate_name(name, all_names):
273
268
  return None
274
269
 
275
270
 
276
- def is_valid_name(name, all_names):
271
+ def _is_valid_name(name, all_names):
277
272
  """
278
273
  Check if name is valid.
279
274
 
@@ -313,27 +308,27 @@ def validate_telescope_model_name(name):
313
308
  Validated name.
314
309
  """
315
310
 
316
- tel_class, tel_type = split_telescope_model_name(name)
317
- tel_class = validate_name(tel_class, all_telescope_class_names)
318
- if "flashcam" in tel_type:
319
- tel_type = tel_type.replace("flashcam", "FlashCam")
320
- if "nectarcam" in tel_type:
321
- tel_type = tel_type.replace("nectarcam", "NectarCam")
322
- if "1m" in tel_type:
323
- tel_type = tel_type.replace("1m", "1M")
324
- if "gct" in tel_type:
325
- tel_type = tel_type.replace("gct", "GCT")
326
- if "astri" in tel_type:
327
- tel_type = tel_type.replace("astri", "ASTRI")
328
- if "-d" in "-" + tel_type:
329
- tel_type = tel_type.replace("d", "D")
311
+ # e.g, MSTN or MSTN-01
312
+ try:
313
+ return _validate_name(name, all_array_element_id_names)
314
+ except ValueError:
315
+ pass
330
316
 
331
- return tel_class + "-" + tel_type
317
+ # e.g., MST-FlashCam or MST-FlashCam-01
318
+ tel_class, tel_type, tel_id = split_telescope_model_name(name)
319
+ _telescope_name = tel_class
320
+ if tel_class != tel_type and len(tel_type) > 0:
321
+ _telescope_name += "-" + tel_type
322
+ if len(tel_id) > 0:
323
+ _telescope_name += "-" + tel_id
324
+ return _telescope_name
332
325
 
333
326
 
334
327
  def split_telescope_model_name(name):
335
328
  """
336
- Split a telescope name into class and type.
329
+ Split a telescope name into class, type, telescope id.
330
+ Allow various inputs, e.g., MST-FlashCam-01, MST-FlashCam,
331
+ MSTN-01, MSTN, MST-1
337
332
 
338
333
  Parameters
339
334
  ----------
@@ -342,14 +337,44 @@ def split_telescope_model_name(name):
342
337
 
343
338
  Returns
344
339
  -------
345
- str, str
346
- class (LST, MST, SST ...) and type (any complement).
340
+ str, str, str
341
+ class (LST, MST, SST ...), type (any complement), telescope id
347
342
  """
348
-
349
343
  name_parts = name.split("-")
344
+ # e.g., MSTN or MSTN-01
345
+ try:
346
+ _is_valid_name(name_parts[0], all_array_element_id_names)
347
+ return (
348
+ validate_telescope_class_name(name_parts[0][0:3]),
349
+ validate_sub_system_name(name_parts[0]),
350
+ validate_telescope_id_name(name_parts[1]) if len(name_parts) > 1 else "",
351
+ )
352
+ except ValueError:
353
+ pass
354
+
355
+ # e.g., MST-FlashCam or MST-FlashCam-01, MST-1
356
+ # (note that this complicated, as LST-1 is a valid
357
+ # name without explicit subsystem given in name)
350
358
  tel_class = name_parts[0]
351
- tel_type = "-".join(name_parts[1:])
352
- return tel_class, tel_type
359
+ try:
360
+ tel_id = validate_telescope_id_name(name_parts[-1])
361
+ _tmp_tel_type = name_parts[1:-1]
362
+ except ValueError:
363
+ tel_id = ""
364
+ _tmp_tel_type = name_parts[1:]
365
+ if len(_tmp_tel_type) > 0:
366
+ tel_type = "-".join(_tmp_tel_type)
367
+ else:
368
+ try:
369
+ tel_type = validate_sub_system_name(tel_class)
370
+ except ValueError:
371
+ tel_type = ""
372
+
373
+ return (
374
+ validate_telescope_class_name(tel_class),
375
+ validate_sub_system_name(tel_type) if len(tel_type) > 0 else "",
376
+ validate_telescope_id_name(tel_id) if len(tel_id) > 0 else "",
377
+ )
353
378
 
354
379
 
355
380
  def get_site_from_telescope_name(name):
@@ -366,12 +391,20 @@ def get_site_from_telescope_name(name):
366
391
  str
367
392
  Site name (South or North).
368
393
  """
394
+ # e.g, MSTN or MSTN-01 (tested by get_telescope_class)
395
+ try:
396
+ get_telescope_class(name)
397
+ return validate_site_name(name[3])
398
+ except ValueError:
399
+ pass
400
+ # e.g., South-MST-FlashCam
369
401
  return validate_site_name(name.split("-")[0])
370
402
 
371
403
 
372
404
  def validate_telescope_name_db(name):
373
405
  """
374
406
  Validate a telescope DB name.
407
+ Examples are North-LST-1, North-MST-NectarCam-D, or South-SST-Structure-D.
375
408
 
376
409
  Parameters
377
410
  ----------
@@ -388,7 +421,7 @@ def validate_telescope_name_db(name):
388
421
  return f"{validate_site_name(site)}-{validate_telescope_model_name(tel_model_name)}"
389
422
 
390
423
 
391
- def convert_telescope_model_name_to_yaml(name):
424
+ def convert_telescope_model_name_to_yaml_name(name):
392
425
  """
393
426
  Get telescope name following the old convention (yaml files) from the current telescope name.
394
427
 
@@ -407,8 +440,9 @@ def convert_telescope_model_name_to_yaml(name):
407
440
  ValueError
408
441
  if name is not valid.
409
442
  """
410
- tel_class, tel_type = split_telescope_model_name(name)
411
- new_name = tel_class + "-" + tel_type
443
+ tel_class, tel_type, tel_id = split_telescope_model_name(name)
444
+ new_name = tel_class if tel_class == tel_type else tel_class + "-" + tel_type
445
+ new_name = new_name + "-" + tel_id if len(tel_id) > 0 else new_name
412
446
  old_names = {
413
447
  "SST-D": "SST",
414
448
  "SST-1M": "SST-1M",
@@ -422,14 +456,97 @@ def convert_telescope_model_name_to_yaml(name):
422
456
  }
423
457
 
424
458
  if new_name not in old_names:
425
- raise ValueError(f"Telescope name {name} could not be converted to yml names")
459
+ raise ValueError(f"Telescope name {name}/{new_name} could not be converted to yml names")
426
460
 
427
461
  return old_names[new_name]
428
462
 
429
463
 
430
- def simtools_instrument_name(site, telescope_class_name, sub_system_name, telescope_id_name):
464
+ def array_element_id_from_telescope_model_name(site, telescope_model_name):
465
+ """
466
+ Array element ID (CTAO convention) from telescope model name.
467
+ This returns e.g., "LSTN" for any LST telescope in the North site.
468
+ If a telescope number is given, it adds it as e.g., "LSTN-01".
469
+
470
+ Parameters
471
+ ----------
472
+ site: str
473
+ Observatory site (e.g., South or North)
474
+ telescope_class_name: str
475
+ Name of the telescope class (e.g. LST-1, LST-D234, MST-FlashCam-D, ...)
476
+
477
+ Returns
478
+ -------
479
+ str
480
+ Array element ID (CTAO style).
481
+
482
+ """
483
+
484
+ _class, _type, _tel_id = split_telescope_model_name(telescope_model_name)
485
+ _id = _class.upper() + site[0].upper()
486
+ if _tel_id.isdigit():
487
+ _id += f"-{int(_tel_id):02d}"
488
+ return _id
489
+
490
+
491
+ def telescope_model_name_from_array_element_id(
492
+ array_element_id, sub_system_name="structure", available_telescopes=None
493
+ ):
494
+ """
495
+ Telescope model name from array element ID (CTAO convention).
496
+ Does not include the site in the returned name (e.g., returns
497
+ South-MST-FlashCam-1 for MSTS-01; this method is quite finetuned).
498
+
499
+ Parameters
500
+ ----------
501
+ array_element_id: str
502
+ Array element ID (CTAO convention).
503
+ available_telescopes: list
504
+ List of available telescopes.
505
+
506
+ Returns
507
+ -------
508
+ str
509
+ Telescope model name.
510
+ """
511
+
512
+ name_parts = array_element_id.split("-")
513
+ try:
514
+ _class = name_parts[0][0:3]
515
+ _site = validate_site_name(name_parts[0][3])
516
+ except IndexError as exc:
517
+ _logger.error("Invalid array element ID %s", array_element_id)
518
+ raise exc
519
+ try:
520
+ _id = int(name_parts[1])
521
+ except (ValueError, IndexError):
522
+ _id = "D"
523
+
524
+ if _class in ("LST", "SCT"):
525
+ sub_system_name = None
526
+ elif _class == "MST" and sub_system_name.lower() == "camera":
527
+ sub_system_name = "NectarCam" if _site == "North" else "FlashCam"
528
+
529
+ _simtools_name = get_telescope_name_db(
530
+ site=_site,
531
+ telescope_class_name=_class,
532
+ sub_system_name=sub_system_name,
533
+ telescope_id_name=_id,
534
+ )
535
+ if available_telescopes is not None and _simtools_name not in available_telescopes:
536
+ _logger.debug("Telescope %s not available", _simtools_name)
537
+ _simtools_name = get_telescope_name_db(
538
+ site=_site,
539
+ telescope_class_name=_class,
540
+ sub_system_name=sub_system_name,
541
+ telescope_id_name="D234" if _site == "North" and _class == "LST" else "D",
542
+ )
543
+ return _simtools_name.split("-", 1)[1]
544
+
545
+
546
+ def get_telescope_name_db(site, telescope_class_name, sub_system_name, telescope_id_name):
431
547
  """
432
548
  Instrument name following simtools naming convention
549
+ Examples are North-LST-1, North-MST-NectarCam-D, or South-SST-Structure-D.
433
550
 
434
551
  Parameters
435
552
  ----------
@@ -437,8 +554,8 @@ def simtools_instrument_name(site, telescope_class_name, sub_system_name, telesc
437
554
  South or North.
438
555
  telescope_class_name: str
439
556
  LST, MST, ...
440
- sub_system_name: str
441
- FlashCam, NectarCam
557
+ sub_system_name: str or None
558
+ FlashCam, NectarCam, Structure
442
559
  telescope_id_name: str
443
560
  telescope ID (e.g., D, numerical value)
444
561
 
@@ -451,9 +568,8 @@ def simtools_instrument_name(site, telescope_class_name, sub_system_name, telesc
451
568
  return (
452
569
  validate_site_name(site)
453
570
  + "-"
454
- + validate_name(telescope_class_name, all_telescope_class_names)
455
- + "-"
456
- + validate_sub_system_name(sub_system_name)
571
+ + _validate_name(telescope_class_name, all_telescope_class_names)
572
+ + ("" if sub_system_name is None else "-" + validate_sub_system_name(sub_system_name))
457
573
  + "-"
458
574
  + validate_telescope_id_name(telescope_id_name)
459
575
  )
@@ -490,7 +606,7 @@ def simtel_telescope_config_file_name(
490
606
  return name
491
607
 
492
608
 
493
- def simtel_array_config_file_name(array_name, site, version, label):
609
+ def simtel_array_config_file_name(array_name, site, model_version, label):
494
610
  """
495
611
  sim_telarray config file name for an array.
496
612
 
@@ -500,7 +616,7 @@ def simtel_array_config_file_name(array_name, site, version, label):
500
616
  Prod5, ...
501
617
  site: str
502
618
  South or North.
503
- version: str
619
+ model_version: str
504
620
  Version of the model.
505
621
  label: str
506
622
  Instance label.
@@ -510,7 +626,7 @@ def simtel_array_config_file_name(array_name, site, version, label):
510
626
  str
511
627
  File name.
512
628
  """
513
- name = f"CTA-{array_name}-{site}-{version}"
629
+ name = f"CTA-{array_name}-{site}-{model_version}"
514
630
  name += f"_{label}" if label is not None else ""
515
631
  name += ".cfg"
516
632
  return name
@@ -679,7 +795,9 @@ def ray_tracing_plot_file_name(
679
795
  return name
680
796
 
681
797
 
682
- def camera_efficiency_results_file_name(site, telescope_model_name, zenith_angle, label):
798
+ def camera_efficiency_results_file_name(
799
+ site, telescope_model_name, zenith_angle, azimuth_angle, label
800
+ ):
683
801
  """
684
802
  Camera efficiency results file name.
685
803
 
@@ -691,6 +809,8 @@ def camera_efficiency_results_file_name(site, telescope_model_name, zenith_angle
691
809
  LST-1, MST-FlashCam, ...
692
810
  zenith_angle: float
693
811
  Zenith angle (deg).
812
+ azimuth_angle: float
813
+ Azimuth angle (deg).
694
814
  label: str
695
815
  Instance label.
696
816
 
@@ -699,13 +819,18 @@ def camera_efficiency_results_file_name(site, telescope_model_name, zenith_angle
699
819
  str
700
820
  File name.
701
821
  """
702
- name = f"camera-efficiency-{site}-{telescope_model_name}-za{zenith_angle:.1f}"
703
- name += f"_{label}" if label is not None else ""
704
- name += ".ecsv"
822
+ _label = f"_{label}" if label is not None else ""
823
+ name = (
824
+ f"camera-efficiency-table-{site}-{telescope_model_name}-"
825
+ f"za{round(zenith_angle):03}deg_azm{round(azimuth_angle):03}deg"
826
+ f"{_label}.ecsv"
827
+ )
705
828
  return name
706
829
 
707
830
 
708
- def camera_efficiency_simtel_file_name(site, telescope_model_name, zenith_angle, label):
831
+ def camera_efficiency_simtel_file_name(
832
+ site, telescope_model_name, zenith_angle, azimuth_angle, label
833
+ ):
709
834
  """
710
835
  Camera efficiency simtel output file name.
711
836
 
@@ -717,6 +842,8 @@ def camera_efficiency_simtel_file_name(site, telescope_model_name, zenith_angle,
717
842
  LST-1, MST-FlashCam-D, ...
718
843
  zenith_angle: float
719
844
  Zenith angle (deg).
845
+ azimuth_angle: float
846
+ Azimuth angle (deg).
720
847
  label: str
721
848
  Instance label.
722
849
 
@@ -725,13 +852,16 @@ def camera_efficiency_simtel_file_name(site, telescope_model_name, zenith_angle,
725
852
  str
726
853
  File name.
727
854
  """
728
- name = f"camera-efficiency-{site}-{telescope_model_name}-za{zenith_angle:.1f}"
729
- name += f"_{label}" if label is not None else ""
730
- name += ".dat"
855
+ _label = f"_{label}" if label is not None else ""
856
+ name = (
857
+ f"camera-efficiency-{site}-{telescope_model_name}-"
858
+ f"za{round(zenith_angle):03}deg_azm{round(azimuth_angle):03}deg"
859
+ f"{_label}.dat"
860
+ )
731
861
  return name
732
862
 
733
863
 
734
- def camera_efficiency_log_file_name(site, telescope_model_name, zenith_angle, label):
864
+ def camera_efficiency_log_file_name(site, telescope_model_name, zenith_angle, azimuth_angle, label):
735
865
  """
736
866
  Camera efficiency log file name.
737
867
 
@@ -743,6 +873,8 @@ def camera_efficiency_log_file_name(site, telescope_model_name, zenith_angle, la
743
873
  LST-1, MST-FlashCam-D, ...
744
874
  zenith_angle: float
745
875
  Zenith angle (deg).
876
+ azimuth_angle: float
877
+ Azimuth angle (deg).
746
878
  label: str
747
879
  Instance label.
748
880
 
@@ -751,15 +883,18 @@ def camera_efficiency_log_file_name(site, telescope_model_name, zenith_angle, la
751
883
  str
752
884
  File name.
753
885
  """
754
- name = f"camera-efficiency-{site}-{telescope_model_name}-za{zenith_angle:.1f}"
755
- name += f"_{label}" if label is not None else ""
756
- name += ".log"
886
+ _label = f"_{label}" if label is not None else ""
887
+ name = (
888
+ f"camera-efficiency-{site}-{telescope_model_name}"
889
+ f"-za{round(zenith_angle):03}deg_azm{round(azimuth_angle):03}deg"
890
+ f"{_label}.log"
891
+ )
757
892
  return name
758
893
 
759
894
 
760
- def get_telescope_type(telescope_name):
895
+ def get_telescope_class(telescope_name):
761
896
  """
762
- Guess telescope type from name, e.g. "LST", "MST", ...
897
+ Guess telescope class from name, e.g. "LST", "MST", ...
763
898
 
764
899
  Parameters
765
900
  ----------
@@ -772,47 +907,24 @@ def get_telescope_type(telescope_name):
772
907
  Telescope type.
773
908
  """
774
909
 
775
- _class, _ = split_telescope_model_name(telescope_name)
776
- try:
777
- if _class[0:3] in all_telescope_class_names:
778
- return _class[0:3]
779
-
780
- except IndexError:
781
- pass
782
-
783
- return ""
784
-
785
-
786
- def translate_corsika_to_simtools(corsika_par):
787
- """
788
- Translate the name of a CORSIKA parameter to the name used in simtools.
789
-
790
- Parameters
791
- ----------
792
- corsika_par: str
793
- Name of the corsika parameter to be translated.
794
-
795
- """
796
-
797
- try:
798
- return corsika_to_simtools_names[corsika_par]
799
- except KeyError:
800
- msg = f"Translation not found. We will proceed with the original parameter name:\
801
- {corsika_par}."
802
- _logger.debug(msg)
803
- return corsika_par
910
+ _tel_class, _, _ = split_telescope_model_name(telescope_name)
911
+ return _tel_class
804
912
 
805
913
 
806
914
  def translate_simtools_to_corsika(simtools_par):
807
915
  """
808
916
  Translate the name of a simtools parameter to the name used in CORSIKA.
809
917
 
918
+ TODO - this will go with the new simulation model
919
+
810
920
  Parameters
811
921
  ----------
812
922
  simtools_par: str
813
923
  Name of the simtools parameter to be translated.
814
924
  """
815
925
 
926
+ corsika_to_simtools_names = {"OBSLEV": "corsika_obs_level"}
927
+
816
928
  simtools_to_corsika_names = {
817
929
  new_key: new_value for new_value, new_key in corsika_to_simtools_names.items()
818
930
  }
@@ -823,3 +935,43 @@ def translate_simtools_to_corsika(simtools_par):
823
935
  {simtools_par}."
824
936
  _logger.debug(msg)
825
937
  return simtools_par
938
+
939
+
940
+ def sanitize_name(name):
941
+ """
942
+ Sanitize name to be a valid Python identifier.
943
+
944
+ - Replaces spaces with underscores
945
+ - Converts to lowercase
946
+ - Removes characters that are not alphanumerics or underscores
947
+ - If the name starts with a number, prepend an underscore
948
+
949
+ Parameters
950
+ ----------
951
+ name: str
952
+ name to be sanitized.
953
+
954
+ Returns
955
+ -------
956
+ str:
957
+ Sanitized name.
958
+
959
+ Raises
960
+ ------
961
+ ValueError:
962
+ if the string `name` can not be sanitized.
963
+ """
964
+
965
+ # Convert to lowercase
966
+ sanitized = name.lower()
967
+
968
+ # Replace spaces with underscores
969
+ sanitized = sanitized.replace(" ", "_")
970
+
971
+ # Remove characters that are not alphanumerics or underscores
972
+ sanitized = re.sub(r"\W|^(?=\d)", "_", sanitized)
973
+ if not sanitized.isidentifier():
974
+ msg = f"The string {name} could not be sanitized."
975
+ _logger.error(msg)
976
+ raise ValueError
977
+ return sanitized