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
@@ -5,16 +5,14 @@ import os
5
5
  import re
6
6
  from pathlib import Path
7
7
 
8
- import jsonschema
9
8
  import numpy as np
10
9
  from astropy import units as u
11
10
  from astropy.table import Column, Table, unique
12
11
  from astropy.utils.diff import report_diff_values
13
12
 
14
13
  import simtools.utils.general as gen
15
- from simtools.constants import MODEL_PARAMETER_SCHEMA_PATH
16
- from simtools.data_model import format_checkers
17
- from simtools.utils import value_conversion
14
+ from simtools.data_model import schema
15
+ from simtools.utils import names, value_conversion
18
16
 
19
17
  __all__ = ["DataValidator"]
20
18
 
@@ -81,7 +79,7 @@ class DataValidator:
81
79
 
82
80
  """
83
81
  if self.data_file_name:
84
- self.validate_data_file()
82
+ self.validate_data_file(is_model_parameter)
85
83
  if isinstance(self.data_dict, dict):
86
84
  return self._validate_data_dict(is_model_parameter, lists_as_strings)
87
85
  if isinstance(self.data_table, Table):
@@ -89,11 +87,16 @@ class DataValidator:
89
87
  self._logger.error("No data or data table to validate")
90
88
  raise TypeError
91
89
 
92
- def validate_data_file(self):
90
+ def validate_data_file(self, is_model_parameter=None):
93
91
  """
94
92
  Open data file and read data from file.
95
93
 
96
94
  Doing this successfully is understood as file validation.
95
+
96
+ Parameters
97
+ ----------
98
+ is_model_parameter: bool
99
+ This is a model parameter file.
97
100
  """
98
101
  try:
99
102
  if Path(self.data_file_name).suffix in (".yml", ".yaml", ".json"):
@@ -104,14 +107,30 @@ class DataValidator:
104
107
  self._logger.info(f"Validating tabled data from: {self.data_file_name}")
105
108
  except (AttributeError, TypeError):
106
109
  pass
110
+ if is_model_parameter:
111
+ self.validate_parameter_and_file_name()
107
112
 
108
113
  def validate_parameter_and_file_name(self):
109
- """Validate that file name and key 'parameter_name' in data dict are the same."""
110
- if not str(Path(self.data_file_name).stem).startswith(self.data_dict.get("parameter")):
111
- raise ValueError(
112
- f"Parameter name in data dict {self.data_dict.get('parameter')} and "
113
- f"file name {Path(self.data_file_name).stem} do not match."
114
- )
114
+ """
115
+ Validate model parameter file name.
116
+
117
+ Expect that the following convention is used:
118
+
119
+ - file name starts with the parameter name
120
+ - file name ends with parameter version string
121
+
122
+ """
123
+ file_stem = Path(self.data_file_name).stem
124
+ param = self.data_dict.get("parameter")
125
+ param_version = self.data_dict.get("parameter_version")
126
+ if not file_stem.startswith(param):
127
+ raise ValueError(f"Mismatch: parameter '{param}' vs. file '{file_stem}'.")
128
+
129
+ if param_version and not file_stem.endswith(param_version):
130
+ raise ValueError(f"Mismatch: version '{param_version}' vs. file '{file_stem}'.")
131
+
132
+ if param_version is None:
133
+ self._logger.warning(f"File '{file_stem}' has no parameter version defined.")
115
134
 
116
135
  @staticmethod
117
136
  def validate_model_parameter(par_dict):
@@ -129,7 +148,7 @@ class DataValidator:
129
148
  Validated data dictionary
130
149
  """
131
150
  data_validator = DataValidator(
132
- schema_file=MODEL_PARAMETER_SCHEMA_PATH / "f{par_dict['parameter']}.schema.yml",
151
+ schema_file=schema.get_model_parameter_schema_file(f"{par_dict['parameter']}"),
133
152
  data_dict=par_dict,
134
153
  check_exact_data_type=False,
135
154
  )
@@ -158,9 +177,7 @@ class DataValidator:
158
177
  if is_model_parameter:
159
178
  self._prepare_model_parameter()
160
179
 
161
- if not (_name := self.data_dict.get("name") or self.data_dict.get("parameter")):
162
- raise KeyError("Data dict does not contain a 'name' or 'parameter' key.")
163
- self._data_description = self._read_validation_schema(self.schema_file_name, _name)
180
+ self._data_description = self._read_validation_schema(self.schema_file_name)
164
181
 
165
182
  value_as_list, unit_as_list = self._get_value_and_units_as_lists()
166
183
 
@@ -174,7 +191,17 @@ class DataValidator:
174
191
  else:
175
192
  self.data_dict["value"], self.data_dict["unit"] = value_as_list, unit_as_list
176
193
 
177
- self._check_version_string(self.data_dict.get("version"))
194
+ if self.data_dict.get("instrument"):
195
+ if self.data_dict["instrument"] == self.data_dict["site"]: # site parameters
196
+ names.validate_site_name(self.data_dict["site"])
197
+ else:
198
+ names.validate_array_element_name(self.data_dict["instrument"])
199
+ self._check_site_and_array_element_consistency(
200
+ self.data_dict.get("instrument"), self.data_dict.get("site")
201
+ )
202
+
203
+ for version_string in ("version", "parameter_version", "model_version"):
204
+ self._check_version_string(self.data_dict.get(version_string))
178
205
 
179
206
  if lists_as_strings:
180
207
  self._convert_results_to_model_format()
@@ -188,8 +215,9 @@ class DataValidator:
188
215
  Take into account different data types and allow to use json_schema for testing.
189
216
  """
190
217
  if self._get_data_description(index).get("type", None) == "dict":
191
- self._validate_data_dict_using_json_schema(
192
- self.data_dict["value"], self._get_data_description(index).get("json_schema")
218
+ schema.validate_dict_using_schema(
219
+ data=self.data_dict["value"],
220
+ json_schema=self._get_data_description(index).get("json_schema"),
193
221
  )
194
222
  else:
195
223
  self._check_data_type(np.array(value).dtype, index)
@@ -235,27 +263,6 @@ class DataValidator:
235
263
  except TypeError:
236
264
  return [None], target_unit
237
265
 
238
- def _validate_data_dict_using_json_schema(self, data, json_schema):
239
- """
240
- Validate a dictionary using a json schema.
241
-
242
- Parameters
243
- ----------
244
- data: dict
245
- Data dictionary
246
- json_schema: dict
247
- JSON schema
248
- """
249
- if json_schema is None:
250
- self._logger.debug("Skipping validation of dict type")
251
- return
252
- self._logger.debug("Validation of dict type using JSON schema")
253
- try:
254
- jsonschema.validate(data, json_schema, format_checker=format_checkers.format_checker)
255
- except jsonschema.exceptions.ValidationError as exc:
256
- self._logger.error(f"Validation error: {exc}")
257
- raise exc
258
-
259
266
  def _validate_data_table(self):
260
267
  """Validate tabulated data."""
261
268
  try:
@@ -692,7 +699,7 @@ class DataValidator:
692
699
 
693
700
  return False
694
701
 
695
- def _read_validation_schema(self, schema_file, parameter=None):
702
+ def _read_validation_schema(self, schema_file):
696
703
  """
697
704
  Read validation schema from file.
698
705
 
@@ -700,11 +707,6 @@ class DataValidator:
700
707
  ----------
701
708
  schema_file: Path
702
709
  Schema file describing input data.
703
- If this is a directory, a filename of
704
- '<par>.schema.yml' is assumed.
705
- parameter: str
706
- Parameter name of required schema
707
- (if None, return first schema in file)
708
710
 
709
711
  Returns
710
712
  -------
@@ -715,17 +717,11 @@ class DataValidator:
715
717
  ------
716
718
  KeyError
717
719
  if 'data' can not be read from dict in schema file
718
-
719
720
  """
720
721
  try:
721
- if Path(schema_file).is_dir():
722
- return gen.collect_data_from_file(
723
- file_name=Path(schema_file) / (parameter + ".schema.yml"),
724
- )["data"]
725
722
  return gen.collect_data_from_file(file_name=schema_file)["data"]
726
- except KeyError:
727
- self._logger.error(f"Error reading validation schema from {schema_file}")
728
- raise
723
+ except KeyError as exc:
724
+ raise KeyError(f"Error reading validation schema from {schema_file}") from exc
729
725
 
730
726
  def _get_data_description(self, column_name=None, status_test=False):
731
727
  """
@@ -801,20 +797,14 @@ class DataValidator:
801
797
  Converts strings to numerical values or lists of values, if required.
802
798
 
803
799
  """
804
- value = self.data_dict["value"]
805
- if not isinstance(value, str):
806
- return
807
-
808
- # assume float value if type is not defined
809
- _is_float = self.data_dict.get("type", "float").startswith(("float", "double"))
810
-
811
- if value.isnumeric():
812
- self.data_dict["value"] = float(value) if _is_float else int(value)
813
- else:
814
- self.data_dict["value"] = gen.convert_string_to_list(value, is_float=_is_float)
815
-
816
- if self.data_dict["unit"] is not None:
817
- self.data_dict["unit"] = gen.convert_string_to_list(self.data_dict["unit"])
800
+ self.data_dict["value"], _ = value_conversion.split_value_and_unit(
801
+ self.data_dict["value"],
802
+ "int" in self.data_dict.get("type", "float"),
803
+ )
804
+ if isinstance(self.data_dict["unit"], str):
805
+ self.data_dict["unit"] = gen.convert_string_to_list(
806
+ self.data_dict["unit"], force_comma_separation=True
807
+ )
818
808
 
819
809
  def _convert_results_to_model_format(self):
820
810
  """
@@ -849,3 +839,24 @@ class DataValidator:
849
839
  if not re.match(semver_regex, version):
850
840
  raise ValueError(f"Invalid version string '{version}'")
851
841
  self._logger.debug(f"Valid version string '{version}'")
842
+
843
+ def _check_site_and_array_element_consistency(self, instrument, site):
844
+ """
845
+ Check that site and array element names are consistent.
846
+
847
+ An example for an inconsistency is 'LSTN' at site 'South'
848
+ """
849
+ if not all([instrument, site]) or "OBS" in instrument:
850
+ return
851
+
852
+ def to_sorted_list(value):
853
+ """Return value as sorted list."""
854
+ return [value] if isinstance(value, str) else sorted(value)
855
+
856
+ instrument_site = to_sorted_list(names.get_site_from_array_element_name(instrument))
857
+ site = to_sorted_list(site)
858
+
859
+ if instrument_site != site:
860
+ raise ValueError(
861
+ f"Site '{site}' and instrument site '{instrument_site}' are inconsistent."
862
+ )