gammasimtools 0.9.0__py3-none-any.whl → 0.11.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.
Files changed (135) hide show
  1. {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/METADATA +4 -2
  2. {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/RECORD +133 -117
  3. {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/entry_points.txt +6 -1
  5. simtools/_version.py +9 -4
  6. simtools/applications/calculate_trigger_rate.py +15 -38
  7. simtools/applications/convert_all_model_parameters_from_simtel.py +9 -29
  8. simtools/applications/convert_geo_coordinates_of_array_elements.py +47 -45
  9. simtools/applications/convert_model_parameter_from_simtel.py +2 -3
  10. simtools/applications/db_add_file_to_db.py +1 -3
  11. simtools/applications/db_add_simulation_model_from_repository_to_db.py +110 -0
  12. simtools/applications/db_add_value_from_json_to_db.py +1 -2
  13. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +6 -6
  14. simtools/applications/db_get_file_from_db.py +11 -12
  15. simtools/applications/db_get_parameter_from_db.py +26 -35
  16. simtools/applications/derive_mirror_rnda.py +1 -2
  17. simtools/applications/derive_photon_electron_spectrum.py +99 -0
  18. simtools/applications/derive_psf_parameters.py +1 -0
  19. simtools/applications/docs_produce_array_element_report.py +71 -0
  20. simtools/applications/docs_produce_model_parameter_reports.py +63 -0
  21. simtools/applications/generate_array_config.py +17 -17
  22. simtools/applications/generate_corsika_histograms.py +2 -2
  23. simtools/applications/generate_regular_arrays.py +19 -17
  24. simtools/applications/generate_simtel_array_histograms.py +11 -48
  25. simtools/applications/production_derive_limits.py +95 -0
  26. simtools/applications/production_generate_simulation_config.py +37 -33
  27. simtools/applications/production_scale_events.py +4 -9
  28. simtools/applications/run_application.py +165 -0
  29. simtools/applications/simulate_light_emission.py +0 -4
  30. simtools/applications/simulate_prod.py +1 -1
  31. simtools/applications/simulate_prod_htcondor_generator.py +26 -26
  32. simtools/applications/submit_data_from_external.py +12 -4
  33. simtools/applications/submit_model_parameter_from_external.py +18 -11
  34. simtools/applications/validate_camera_efficiency.py +2 -2
  35. simtools/applications/validate_file_using_schema.py +26 -22
  36. simtools/camera/single_photon_electron_spectrum.py +168 -0
  37. simtools/configuration/commandline_parser.py +37 -1
  38. simtools/configuration/configurator.py +8 -10
  39. simtools/constants.py +10 -3
  40. simtools/corsika/corsika_config.py +19 -17
  41. simtools/corsika/corsika_histograms.py +5 -7
  42. simtools/corsika/corsika_histograms_visualize.py +2 -4
  43. simtools/data_model/data_reader.py +0 -3
  44. simtools/data_model/metadata_collector.py +20 -12
  45. simtools/data_model/metadata_model.py +8 -124
  46. simtools/data_model/model_data_writer.py +81 -75
  47. simtools/data_model/schema.py +220 -0
  48. simtools/data_model/validate_data.py +79 -68
  49. simtools/db/db_handler.py +350 -492
  50. simtools/db/db_model_upload.py +139 -0
  51. simtools/dependencies.py +112 -0
  52. simtools/io_operations/hdf5_handler.py +54 -24
  53. simtools/layout/array_layout.py +38 -32
  54. simtools/model/array_model.py +13 -7
  55. simtools/model/model_parameter.py +55 -54
  56. simtools/model/site_model.py +2 -2
  57. simtools/production_configuration/calculate_statistical_errors_grid_point.py +119 -145
  58. simtools/production_configuration/event_scaler.py +9 -35
  59. simtools/production_configuration/generate_simulation_config.py +9 -44
  60. simtools/production_configuration/interpolation_handler.py +9 -15
  61. simtools/production_configuration/limits_calculation.py +202 -0
  62. simtools/reporting/docs_read_parameters.py +310 -0
  63. simtools/runners/corsika_simtel_runner.py +4 -4
  64. simtools/schemas/{integration_tests_config.metaschema.yml → application_workflow.metaschema.yml} +61 -27
  65. simtools/schemas/array_elements.yml +8 -0
  66. simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +39 -0
  67. simtools/schemas/input/single_pe_spectrum.schema.yml +38 -0
  68. simtools/schemas/model_parameter.metaschema.yml +103 -2
  69. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +4 -1
  70. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
  71. simtools/schemas/model_parameters/array_window.schema.yml +37 -0
  72. simtools/schemas/model_parameters/asum_clipping.schema.yml +0 -4
  73. simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
  74. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +1 -1
  75. simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +2 -0
  76. simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +2 -0
  77. simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +2 -0
  78. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +4 -2
  79. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +2 -0
  80. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +2 -0
  81. simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +2 -0
  82. simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +2 -0
  83. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +2 -0
  84. simtools/schemas/model_parameters/dsum_clipping.schema.yml +0 -2
  85. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +0 -2
  86. simtools/schemas/model_parameters/dsum_offset.schema.yml +0 -2
  87. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +0 -2
  88. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +0 -2
  89. simtools/schemas/model_parameters/dsum_prescale.schema.yml +0 -2
  90. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +0 -2
  91. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +0 -2
  92. simtools/schemas/model_parameters/dsum_shaping.schema.yml +0 -2
  93. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +0 -2
  94. simtools/schemas/model_parameters/dsum_threshold.schema.yml +0 -2
  95. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +0 -2
  96. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
  97. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
  98. simtools/schemas/model_parameters/fadc_noise.schema.yml +3 -3
  99. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +33 -0
  100. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
  101. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
  102. simtools/schemas/model_parameters/laser_photons.schema.yml +2 -2
  103. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
  104. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +1 -1
  105. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
  106. simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
  107. simtools/schemas/model_parameters/random_generator.schema.yml +1 -1
  108. simtools/schemas/model_parameters/sampled_output.schema.yml +1 -1
  109. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +1 -1
  110. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
  111. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
  112. simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
  113. simtools/schemas/production_configuration_metrics.schema.yml +68 -0
  114. simtools/schemas/production_tables.schema.yml +41 -0
  115. simtools/simtel/simtel_config_reader.py +1 -2
  116. simtools/simtel/simtel_config_writer.py +6 -8
  117. simtools/simtel/simtel_io_histogram.py +32 -68
  118. simtools/simtel/simtel_io_histograms.py +17 -34
  119. simtools/simtel/simulator_array.py +2 -1
  120. simtools/simtel/simulator_camera_efficiency.py +6 -3
  121. simtools/simtel/simulator_light_emission.py +5 -6
  122. simtools/simtel/simulator_ray_tracing.py +3 -4
  123. simtools/testing/configuration.py +2 -1
  124. simtools/testing/helpers.py +6 -13
  125. simtools/testing/validate_output.py +141 -47
  126. simtools/utils/general.py +114 -14
  127. simtools/utils/names.py +299 -157
  128. simtools/utils/value_conversion.py +17 -13
  129. simtools/version.py +2 -2
  130. simtools/visualization/legend_handlers.py +2 -0
  131. simtools/applications/db_add_model_parameters_from_repository_to_db.py +0 -176
  132. simtools/db/db_array_elements.py +0 -130
  133. {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/LICENSE +0 -0
  134. {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/top_level.txt +0 -0
  135. /simtools/{camera_efficiency.py → camera/camera_efficiency.py} +0 -0
@@ -0,0 +1,139 @@
1
+ """Upload a simulation model (parameters and production tables) to the database."""
2
+
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import simtools.utils.general as gen
7
+ from simtools.utils import names
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ def add_values_from_json_to_db(file, collection, db, db_name, file_prefix):
13
+ """
14
+ Upload new model parameter from json files to db.
15
+
16
+ Parameters
17
+ ----------
18
+ file : list
19
+ Json file to be uploaded to the DB.
20
+ collection : str
21
+ The DB collection to which to add the file.
22
+ db : DatabaseHandler
23
+ Database handler object.
24
+ db_name : str
25
+ Name of the database to be created.
26
+ file_prefix : str
27
+ Path to location of all additional files to be uploaded.
28
+ """
29
+ par_dict = gen.collect_data_from_file(file_name=file)
30
+ logger.info(
31
+ f"Adding the following parameter to the DB: {par_dict['parameter']} "
32
+ f"version {par_dict['parameter_version']} "
33
+ f"(collection {collection} in database {db_name})"
34
+ )
35
+
36
+ db.add_new_parameter(
37
+ db_name=db_name,
38
+ par_dict=par_dict,
39
+ collection_name=collection,
40
+ file_prefix=file_prefix,
41
+ )
42
+
43
+
44
+ def add_model_parameters_to_db(args_dict, db):
45
+ """
46
+ Read model parameters from a directory and upload them to the database.
47
+
48
+ Parameters
49
+ ----------
50
+ args_dict : dict
51
+ Command line arguments.
52
+ db : DatabaseHandler
53
+ Database handler object.
54
+ """
55
+ input_path = Path(args_dict["input_path"])
56
+ logger.info(f"Reading model parameters from repository path {input_path}")
57
+ array_elements = [d for d in input_path.iterdir() if d.is_dir()]
58
+ for element in array_elements:
59
+ collection = names.get_collection_name_from_array_element_name(element.name, False)
60
+ if collection == "Files":
61
+ logger.info("Files (tables) are uploaded with the corresponding model parameters")
62
+ continue
63
+ logger.info(f"Reading model parameters for {element.name} into collection {collection}")
64
+ files_to_insert = list(Path(element).rglob("*json"))
65
+ for file in files_to_insert:
66
+ add_values_from_json_to_db(
67
+ file=file,
68
+ collection=collection,
69
+ db=db,
70
+ db_name=args_dict["db_name"],
71
+ file_prefix=input_path / "Files",
72
+ )
73
+
74
+
75
+ def add_production_tables_to_db(args_dict, db):
76
+ """
77
+ Read production tables from a directory and upload them to the database.
78
+
79
+ One dictionary per collection is prepared for each model version, containing
80
+ tables of all array elements, sites, and configuration parameters.
81
+
82
+ Parameters
83
+ ----------
84
+ args_dict : dict
85
+ Command line arguments.
86
+ db : DatabaseHandler
87
+ Database handler object.
88
+ """
89
+ input_path = Path(args_dict["input_path"])
90
+ logger.info(f"Reading production tables from repository path {input_path}")
91
+
92
+ for model in filter(Path.is_dir, input_path.iterdir()):
93
+ logger.info(f"Reading production tables for model version {model.name}")
94
+ model_dict = {}
95
+ for file in sorted(model.rglob("*json")):
96
+ _read_production_table(model_dict, file, model.name)
97
+
98
+ for collection, data in model_dict.items():
99
+ if not data["parameters"]:
100
+ logger.info(f"No production table for {collection} in model version {model.name}")
101
+ continue
102
+ logger.info(f"Adding production table for {collection} to the database")
103
+ db.add_production_table(
104
+ db_name=args_dict["db_name"],
105
+ production_table=data,
106
+ )
107
+
108
+
109
+ def _read_production_table(model_dict, file, model_name):
110
+ """Read a single production table from file."""
111
+ array_element = file.stem
112
+ collection = names.get_collection_name_from_array_element_name(array_element, False)
113
+ model_dict.setdefault(
114
+ collection,
115
+ {
116
+ "collection": collection,
117
+ "model_version": model_name,
118
+ "parameters": {},
119
+ "design_model": {},
120
+ },
121
+ )
122
+ parameter_dict = gen.collect_data_from_file(file_name=file)
123
+ logger.info(f"Reading production table for {array_element} (collection {collection})")
124
+ try:
125
+ if array_element in ("configuration_corsika", "configuration_sim_telarray"):
126
+ model_dict[collection]["parameters"] = parameter_dict["parameters"]
127
+ else:
128
+ model_dict[collection]["parameters"][array_element] = parameter_dict["parameters"][
129
+ array_element
130
+ ]
131
+ except KeyError as exc:
132
+ logger.error(f"KeyError: {exc}")
133
+ raise
134
+ try:
135
+ model_dict[collection]["design_model"][array_element] = parameter_dict["design_model"][
136
+ array_element
137
+ ]
138
+ except KeyError:
139
+ pass
@@ -0,0 +1,112 @@
1
+ """
2
+ Simtools dependencies version management.
3
+
4
+ This modules provides two main functionalities:
5
+
6
+ - retrieve the versions of simtools dependencies (e.g., databases, sim_telarray, CORSIKA)
7
+ - provide space for future implementations of version management
8
+
9
+ """
10
+
11
+ import logging
12
+ import os
13
+ import re
14
+ import subprocess
15
+ from pathlib import Path
16
+
17
+ import simtools.utils.general as gen
18
+ from simtools.db.db_handler import DatabaseHandler
19
+
20
+ _logger = logging.getLogger(__name__)
21
+
22
+
23
+ def get_version_string(db_config=None):
24
+ """Print the versions of the dependencies."""
25
+ return (
26
+ f"Database version: {get_database_version(db_config)}\n"
27
+ f"sim_telarray version: {get_sim_telarray_version()}\n"
28
+ f"CORSIKA version: {get_corsika_version()}\n"
29
+ )
30
+
31
+
32
+ def get_database_version(db_config):
33
+ """
34
+ Get the version of the simulation model data base used.
35
+
36
+ Parameters
37
+ ----------
38
+ db_config : dict
39
+ Dictionary containing the database configuration.
40
+
41
+ Returns
42
+ -------
43
+ str
44
+ Version of the simulation model data base used.
45
+
46
+ """
47
+ if db_config is None:
48
+ return None
49
+ db = DatabaseHandler(db_config)
50
+ return db.mongo_db_config.get("db_simulation_model")
51
+
52
+
53
+ def get_sim_telarray_version():
54
+ """
55
+ Get the version of the sim_telarray package using 'sim_telarray --version'.
56
+
57
+ Returns
58
+ -------
59
+ str
60
+ Version of the sim_telarray package.
61
+ """
62
+ sim_telarray_path = os.getenv("SIMTOOLS_SIMTEL_PATH")
63
+ if sim_telarray_path is None:
64
+ _logger.warning("Environment variable SIMTOOLS_SIMTEL_PATH is not set.")
65
+ return None
66
+ sim_telarray_path = Path(sim_telarray_path) / "sim_telarray" / "bin" / "sim_telarray"
67
+
68
+ # expect stdout with e.g. a line 'Release: 2024.271.0 from 2024-09-27'
69
+ result = subprocess.run(
70
+ [sim_telarray_path, "--version"],
71
+ capture_output=True,
72
+ text=True,
73
+ check=False,
74
+ )
75
+ match = re.search(r"^Release:\s+(.+)", result.stdout, re.MULTILINE)
76
+
77
+ if match:
78
+ return match.group(1).split()[0]
79
+ raise ValueError(f"sim_telarray release not found in {result.stdout}")
80
+
81
+
82
+ def get_corsika_version():
83
+ """
84
+ Get the version of the corsika package.
85
+
86
+ Returns
87
+ -------
88
+ str
89
+ Version of the corsika package.
90
+ """
91
+ try:
92
+ build_opts = get_build_options()
93
+ except (FileNotFoundError, TypeError):
94
+ _logger.warning("CORSIKA version not implemented yet.")
95
+ return None
96
+ return build_opts.get("corsika_version")
97
+
98
+
99
+ def get_build_options():
100
+ """
101
+ Return CORSIKA / sim_telarray build options.
102
+
103
+ Expects a build_opts.yml file in the sim_telarray directory.
104
+ """
105
+ try:
106
+ return gen.collect_data_from_file(
107
+ Path(os.getenv("SIMTOOLS_SIMTEL_PATH")) / "build_opts.yml"
108
+ )
109
+ except FileNotFoundError as exc:
110
+ raise FileNotFoundError("No build_opts.yml file found.") from exc
111
+ except TypeError as exc:
112
+ raise TypeError("SIMTOOLS_SIMTEL_PATH not defined.") from exc
@@ -41,40 +41,26 @@ def fill_hdf5_table(hist, x_bin_edges, y_bin_edges, x_label, y_label, meta_data)
41
41
  meta_data: dict
42
42
  Dictionary with the histogram metadata.
43
43
  """
44
- # Complement metadata
45
- if x_label is not None:
46
- meta_data["x_bin_edges"] = sanitize_name(x_label)
44
+ validate_histogram(hist, y_bin_edges)
45
+
46
+ meta_data["x_bin_edges"] = x_bin_edges
47
47
  meta_data["x_bin_edges_unit"] = (
48
48
  x_bin_edges.unit if isinstance(x_bin_edges, u.Quantity) else u.dimensionless_unscaled
49
49
  )
50
-
51
50
  if y_bin_edges is not None:
52
- if y_label is not None:
53
- meta_data["y_bin_edges"] = sanitize_name(y_label)
54
- names = [
55
- f"{meta_data['y_bin_edges'].split('__')[0]}_{i}"
56
- for i in range(len(y_bin_edges[:-1]))
57
- ]
58
- else:
59
- names = [
60
- f"{meta_data['Title'].split('__')[0]}_{i}" for i in range(len(y_bin_edges[:-1]))
61
- ]
51
+ meta_data["y_bin_edges"] = y_bin_edges
62
52
  meta_data["y_bin_edges_unit"] = (
63
53
  y_bin_edges.unit if isinstance(y_bin_edges, u.Quantity) else u.dimensionless_unscaled
64
54
  )
65
55
 
66
- table = Table(
67
- [hist[i, :] for i in range(len(y_bin_edges[:-1]))],
68
- names=names,
69
- meta=meta_data,
70
- )
71
-
72
- else:
56
+ if hist.ndim == 1:
73
57
  if x_label is not None:
74
- meta_data["x_bin_edges"] = sanitize_name(x_label)
75
- names = meta_data["x_bin_edges"]
76
- else:
58
+ names = sanitize_name(x_label)
59
+ try:
77
60
  names = meta_data["Title"]
61
+ except KeyError:
62
+ _logger.warning("Title not found in metadata.")
63
+
78
64
  table = Table(
79
65
  [
80
66
  x_bin_edges[:-1],
@@ -83,9 +69,53 @@ def fill_hdf5_table(hist, x_bin_edges, y_bin_edges, x_label, y_label, meta_data)
83
69
  names=(names, sanitize_name("Values")),
84
70
  meta=meta_data,
85
71
  )
72
+ else:
73
+ if y_label is not None:
74
+ names = [
75
+ f"{sanitize_name(y_label).split('__')[0]}_{i}" for i in range(len(y_bin_edges[:-1]))
76
+ ]
77
+ try:
78
+ names = [
79
+ f"{(meta_data['Title']).split('__')[0]}_{sanitize_name(y_label)}_{i}"
80
+ for i in range(len(y_bin_edges[:-1]))
81
+ ]
82
+ except KeyError:
83
+ _logger.warning("Title not found in metadata.")
84
+ names = [
85
+ f"{sanitize_name(y_label).split('__')[0]}_{i}" for i in range(len(y_bin_edges[:-1]))
86
+ ]
87
+
88
+ table = Table(
89
+ [hist[i, :] for i in range(len(y_bin_edges[:-1]))],
90
+ names=names,
91
+ meta=meta_data,
92
+ )
93
+
86
94
  return table
87
95
 
88
96
 
97
+ def validate_histogram(hist, y_bin_edges):
98
+ """Validate histogram dimensions and y_bin_edges consistency.
99
+
100
+ Parameters
101
+ ----------
102
+ hist (np.ndarray): The histogram array, expected to be 1D or 2D.
103
+ y_bin_edges (array-like or None): Bin edges for the second dimension (if applicable).
104
+
105
+ Raises
106
+ ------
107
+ ValueError: If histogram dimensions are invalid or inconsistent with y_bin_edges.
108
+ """
109
+ if hist.ndim not in (1, 2):
110
+ raise ValueError("Histogram must be either 1D or 2D.")
111
+
112
+ if hist.ndim == 1 and y_bin_edges is not None:
113
+ raise ValueError("y_bin_edges should be None for 1D histograms.")
114
+
115
+ if hist.ndim == 2 and y_bin_edges is None:
116
+ raise ValueError("y_bin_edges should not be None for 2D histograms.")
117
+
118
+
89
119
  def read_hdf5(hdf5_file_name):
90
120
  """
91
121
  Read a hdf5 output file.
@@ -9,7 +9,7 @@ import numpy as np
9
9
  from astropy.table import QTable
10
10
 
11
11
  import simtools.utils.general as gen
12
- from simtools.data_model import data_reader
12
+ from simtools.data_model import data_reader, schema
13
13
  from simtools.io_operations import io_handler
14
14
  from simtools.layout.geo_coordinates import GeoCoordinates
15
15
  from simtools.layout.telescope_position import TelescopePosition
@@ -386,7 +386,9 @@ class ArrayLayout:
386
386
  with Path(file_name).open("r", encoding="utf-8") as file:
387
387
  data = json.load(file)
388
388
 
389
- position = gen.convert_string_to_list(data["value"])
389
+ position = data["value"]
390
+ if isinstance(position, str):
391
+ position = gen.convert_string_to_list(position)
390
392
  self.site = data.get("site", None)
391
393
 
392
394
  table = QTable()
@@ -443,9 +445,11 @@ class ArrayLayout:
443
445
  )
444
446
  try:
445
447
  tel_model = self._get_telescope_model(telescope_name)
446
- except ValueError:
448
+ except ValueError: # telescope not found in the database revert to design model
447
449
  tel_model = self._get_telescope_model(
448
- names.get_array_element_type_from_name(telescope_name) + "-design",
450
+ names.array_element_design_types(
451
+ names.get_array_element_type_from_name(telescope_name)
452
+ )[0]
449
453
  )
450
454
 
451
455
  for para in ("telescope_axis_height", "telescope_sphere_radius"):
@@ -579,7 +583,12 @@ class ArrayLayout:
579
583
 
580
584
  return table
581
585
 
582
- def export_one_telescope_as_json(self, crs_name):
586
+ def export_one_telescope_as_json(
587
+ self,
588
+ crs_name,
589
+ parameter_version=None,
590
+ schema_version=None,
591
+ ):
583
592
  """
584
593
  Return a list containing a single telescope in simtools-DB-style json.
585
594
 
@@ -587,6 +596,8 @@ class ArrayLayout:
587
596
  ----------
588
597
  crs_name: str
589
598
  Name of coordinate system to be used for export.
599
+ schema_version: str
600
+ Version of the schema.
590
601
 
591
602
  Returns
592
603
  -------
@@ -596,43 +607,39 @@ class ArrayLayout:
596
607
  table = self.export_telescope_list_table(crs_name)
597
608
  if len(table) != 1:
598
609
  raise ValueError("Only one telescope can be exported to json")
599
- parameter_name = value_string = None
610
+ parameter_name = value = None
600
611
  if crs_name == "ground":
601
612
  parameter_name = "array_element_position_ground"
602
- value_string = gen.convert_list_to_string(
603
- [
604
- table["position_x"][0].value,
605
- table["position_y"][0].value,
606
- table["position_z"][0].value,
607
- ]
608
- )
613
+ value = [
614
+ table["position_x"][0].value,
615
+ table["position_y"][0].value,
616
+ table["position_z"][0].value,
617
+ ]
609
618
  elif crs_name == "utm":
610
619
  parameter_name = "array_element_position_utm"
611
- value_string = gen.convert_list_to_string(
612
- [
613
- table["utm_east"][0].value,
614
- table["utm_north"][0].value,
615
- table["altitude"][0].value,
616
- ]
617
- )
620
+ value = [
621
+ table["utm_east"][0].value,
622
+ table["utm_north"][0].value,
623
+ table["altitude"][0].value,
624
+ ]
618
625
  elif crs_name == "mercator":
619
626
  parameter_name = "array_element_position_mercator"
620
- value_string = gen.convert_list_to_string(
621
- [
622
- table["latitude"][0].value,
623
- table["longitude"][0].value,
624
- table["altitude"][0].value,
625
- ]
626
- )
627
+ value = [
628
+ table["latitude"][0].value,
629
+ table["longitude"][0].value,
630
+ table["altitude"][0].value,
631
+ ]
632
+
627
633
  return {
634
+ "schema_version": schema.get_model_parameter_schema_version(schema_version),
628
635
  "parameter": parameter_name,
629
636
  "instrument": table["telescope_name"][0],
630
637
  "site": self.site,
631
- "version": self.model_version,
632
- "value": value_string,
638
+ "parameter_version": parameter_version,
639
+ "unique_id": None,
640
+ "value": value,
633
641
  "unit": "m",
634
642
  "type": "float64",
635
- "applicable": True,
636
643
  "file": False,
637
644
  }
638
645
 
@@ -711,8 +718,7 @@ class ArrayLayout:
711
718
  set(_telescope_list_from_name + _telescope_list_from_type)
712
719
  )
713
720
  self._logger.info(
714
- f"Selected {len(self._telescope_list)} telescopes"
715
- f" (from originally {_n_telescopes})"
721
+ f"Selected {len(self._telescope_list)} telescopes (from originally {_n_telescopes})"
716
722
  )
717
723
  except TypeError:
718
724
  self._logger.info("No asset list provided, keeping all telescopes")
@@ -6,8 +6,8 @@ from pathlib import Path
6
6
  import astropy.units as u
7
7
  from astropy.table import QTable
8
8
 
9
- from simtools.data_model import data_reader
10
- from simtools.db import db_array_elements, db_handler
9
+ from simtools.data_model import data_reader, schema
10
+ from simtools.db import db_handler
11
11
  from simtools.io_operations import io_handler
12
12
  from simtools.model.site_model import SiteModel
13
13
  from simtools.model.telescope_model import TelescopeModel
@@ -290,7 +290,13 @@ class ArrayModel:
290
290
  }
291
291
 
292
292
  def _get_telescope_position_parameter(
293
- self, telescope_name: str, site: str, x: u.Quantity, y: u.Quantity, z: u.Quantity
293
+ self,
294
+ telescope_name: str,
295
+ site: str,
296
+ x: u.Quantity,
297
+ y: u.Quantity,
298
+ z: u.Quantity,
299
+ parameter_version: str | None = None,
294
300
  ) -> dict:
295
301
  """
296
302
  Return dictionary with telescope position parameters (following DB model database format).
@@ -314,16 +320,17 @@ class ArrayModel:
314
320
  Dict with telescope position parameters.
315
321
  """
316
322
  return {
323
+ "schema_version": schema.get_model_parameter_schema_version(),
317
324
  "parameter": "array_element_position_ground",
318
325
  "instrument": telescope_name,
319
326
  "site": site,
320
- "version": self.model_version,
327
+ "parameter_version": parameter_version,
328
+ "unique_id": None,
321
329
  "value": general.convert_list_to_string(
322
330
  [x.to("m").value, y.to("m").value, z.to("m").value]
323
331
  ),
324
332
  "unit": "m",
325
333
  "type": "float64",
326
- "applicable": True,
327
334
  "file": False,
328
335
  }
329
336
 
@@ -367,9 +374,8 @@ class ArrayModel:
367
374
  dict
368
375
  Dict with array elements.
369
376
  """
370
- all_elements = db_array_elements.get_array_elements_of_type(
377
+ all_elements = self.db.get_array_elements_of_type(
371
378
  array_element_type=array_element_type,
372
- db=self.db,
373
379
  model_version=self.model_version,
374
380
  collection="telescopes",
375
381
  )