gammasimtools 0.6.1__py3-none-any.whl → 0.8.2__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 (355) hide show
  1. gammasimtools-0.8.2.dist-info/METADATA +173 -0
  2. gammasimtools-0.8.2.dist-info/RECORD +345 -0
  3. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/WHEEL +1 -1
  4. gammasimtools-0.8.2.dist-info/entry_points.txt +31 -0
  5. simtools/_dev_version/__init__.py +9 -0
  6. simtools/_version.py +2 -2
  7. simtools/applications/calculate_trigger_rate.py +210 -0
  8. simtools/applications/convert_all_model_parameters_from_simtel.py +372 -0
  9. simtools/applications/{print_array_elements.py → convert_geo_coordinates_of_array_elements.py} +58 -63
  10. simtools/applications/convert_model_parameter_from_simtel.py +119 -0
  11. simtools/applications/{add_file_to_db.py → db_add_file_to_db.py} +70 -60
  12. simtools/applications/db_add_model_parameters_from_repository_to_db.py +184 -0
  13. simtools/applications/db_add_value_from_json_to_db.py +105 -0
  14. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +180 -0
  15. simtools/applications/db_get_array_layouts_from_db.py +162 -0
  16. simtools/applications/{get_file_from_db.py → db_get_file_from_db.py} +30 -34
  17. simtools/applications/db_get_parameter_from_db.py +131 -0
  18. simtools/applications/db_inspect_databases.py +52 -0
  19. simtools/applications/derive_mirror_rnda.py +39 -255
  20. simtools/applications/derive_psf_parameters.py +441 -0
  21. simtools/applications/generate_array_config.py +82 -0
  22. simtools/applications/generate_corsika_histograms.py +52 -52
  23. simtools/applications/generate_default_metadata.py +5 -8
  24. simtools/applications/generate_regular_arrays.py +117 -0
  25. simtools/applications/generate_simtel_array_histograms.py +97 -56
  26. simtools/applications/plot_array_layout.py +345 -115
  27. simtools/applications/production_generate_simulation_config.py +158 -0
  28. simtools/applications/production_scale_events.py +168 -0
  29. simtools/applications/simulate_light_emission.py +478 -0
  30. simtools/applications/simulate_prod.py +97 -175
  31. simtools/applications/submit_data_from_external.py +9 -12
  32. simtools/applications/submit_model_parameter_from_external.py +122 -0
  33. simtools/applications/validate_camera_efficiency.py +35 -102
  34. simtools/applications/validate_camera_fov.py +20 -19
  35. simtools/applications/{compare_cumulative_psf.py → validate_cumulative_psf.py} +45 -44
  36. simtools/applications/validate_file_using_schema.py +111 -47
  37. simtools/applications/validate_optics.py +17 -22
  38. simtools/camera_efficiency.py +193 -202
  39. simtools/configuration/commandline_parser.py +384 -96
  40. simtools/configuration/configurator.py +55 -71
  41. simtools/constants.py +5 -5
  42. simtools/corsika/corsika_config.py +482 -342
  43. simtools/corsika/corsika_histograms.py +226 -204
  44. simtools/corsika/corsika_histograms_visualize.py +23 -24
  45. simtools/corsika/primary_particle.py +159 -0
  46. simtools/data_model/data_reader.py +25 -20
  47. simtools/data_model/format_checkers.py +52 -0
  48. simtools/data_model/metadata_collector.py +211 -185
  49. simtools/data_model/metadata_model.py +115 -37
  50. simtools/data_model/model_data_writer.py +335 -26
  51. simtools/data_model/validate_data.py +366 -154
  52. simtools/db/db_array_elements.py +130 -0
  53. simtools/db/db_from_repo_handler.py +106 -0
  54. simtools/db/db_handler.py +1246 -0
  55. simtools/io_operations/hdf5_handler.py +3 -1
  56. simtools/io_operations/io_handler.py +32 -57
  57. simtools/job_execution/job_manager.py +82 -69
  58. simtools/layout/array_layout.py +325 -537
  59. simtools/layout/geo_coordinates.py +8 -11
  60. simtools/layout/telescope_position.py +163 -86
  61. simtools/model/array_model.py +312 -259
  62. simtools/model/calibration_model.py +50 -0
  63. simtools/model/camera.py +277 -523
  64. simtools/model/mirrors.py +68 -49
  65. simtools/model/model_parameter.py +602 -0
  66. simtools/model/model_utils.py +11 -39
  67. simtools/model/site_model.py +161 -0
  68. simtools/model/telescope_model.py +143 -633
  69. simtools/production_configuration/calculate_statistical_errors_grid_point.py +454 -0
  70. simtools/production_configuration/event_scaler.py +146 -0
  71. simtools/production_configuration/generate_simulation_config.py +193 -0
  72. simtools/production_configuration/interpolation_handler.py +197 -0
  73. simtools/ray_tracing/__init__.py +0 -0
  74. simtools/ray_tracing/mirror_panel_psf.py +280 -0
  75. simtools/{psf_analysis.py → ray_tracing/psf_analysis.py} +133 -47
  76. simtools/ray_tracing/ray_tracing.py +646 -0
  77. simtools/runners/__init__.py +0 -0
  78. simtools/runners/corsika_runner.py +240 -0
  79. simtools/runners/corsika_simtel_runner.py +225 -0
  80. simtools/runners/runner_services.py +307 -0
  81. simtools/runners/simtel_runner.py +224 -0
  82. simtools/schemas/array_elements.yml +137 -0
  83. simtools/schemas/integration_tests_config.metaschema.yml +93 -0
  84. simtools/schemas/metadata.metaschema.yml +6 -0
  85. simtools/schemas/model_parameter.metaschema.yml +78 -0
  86. simtools/schemas/{data.metaschema.yml → model_parameter_and_data_schema.metaschema.yml} +27 -44
  87. simtools/schemas/model_parameters/adjust_gain.schema.yml +37 -0
  88. simtools/schemas/model_parameters/altitude.schema.yml +37 -0
  89. simtools/schemas/model_parameters/array_coordinates.schema.yml +33 -0
  90. simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +77 -0
  91. simtools/schemas/model_parameters/array_element_position_ground.schema.yml +39 -0
  92. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +39 -0
  93. simtools/schemas/model_parameters/array_layouts.schema.yml +48 -0
  94. simtools/schemas/model_parameters/array_triggers.schema.yml +93 -0
  95. simtools/schemas/model_parameters/asum_clipping.schema.yml +38 -0
  96. simtools/schemas/model_parameters/asum_offset.schema.yml +35 -0
  97. simtools/schemas/model_parameters/asum_shaping.schema.yml +35 -0
  98. simtools/schemas/model_parameters/asum_threshold.schema.yml +38 -0
  99. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +32 -0
  100. simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +35 -0
  101. simtools/schemas/model_parameters/axes_offsets.schema.yml +53 -0
  102. simtools/schemas/model_parameters/camera_body_diameter.schema.yml +40 -0
  103. simtools/schemas/model_parameters/camera_body_shape.schema.yml +45 -0
  104. simtools/schemas/model_parameters/camera_config_file.schema.yml +40 -0
  105. simtools/schemas/model_parameters/camera_config_rotate.schema.yml +36 -0
  106. simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +43 -0
  107. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +42 -0
  108. simtools/schemas/model_parameters/camera_depth.schema.yml +42 -0
  109. simtools/schemas/model_parameters/camera_filter.schema.yml +45 -0
  110. simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +29 -0
  111. simtools/schemas/model_parameters/camera_pixels.schema.yml +36 -0
  112. simtools/schemas/model_parameters/camera_transmission.schema.yml +41 -0
  113. simtools/schemas/model_parameters/channels_per_chip.schema.yml +36 -0
  114. simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +35 -0
  115. simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +27 -0
  116. simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +38 -0
  117. simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +28 -0
  118. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +23 -0
  119. simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +27 -0
  120. simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +28 -0
  121. simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +27 -0
  122. simtools/schemas/model_parameters/corsika_observation_level.schema.yml +38 -0
  123. simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +52 -0
  124. simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +27 -0
  125. simtools/schemas/model_parameters/dark_events.schema.yml +32 -0
  126. simtools/schemas/model_parameters/default_trigger.schema.yml +35 -0
  127. simtools/schemas/model_parameters/design_model.schema.yml +31 -0
  128. simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +32 -0
  129. simtools/schemas/model_parameters/disc_bins.schema.yml +39 -0
  130. simtools/schemas/model_parameters/disc_start.schema.yml +41 -0
  131. simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +42 -0
  132. simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +41 -0
  133. simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +41 -0
  134. simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +39 -0
  135. simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +40 -0
  136. simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +41 -0
  137. simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +33 -0
  138. simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +42 -0
  139. simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +37 -0
  140. simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +44 -0
  141. simtools/schemas/model_parameters/discriminator_threshold.schema.yml +36 -0
  142. simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +45 -0
  143. simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +40 -0
  144. simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +41 -0
  145. simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +38 -0
  146. simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +38 -0
  147. simtools/schemas/model_parameters/dish_shape_length.schema.yml +41 -0
  148. simtools/schemas/model_parameters/dsum_clipping.schema.yml +38 -0
  149. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +38 -0
  150. simtools/schemas/model_parameters/dsum_offset.schema.yml +37 -0
  151. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +33 -0
  152. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +39 -0
  153. simtools/schemas/model_parameters/dsum_prescale.schema.yml +44 -0
  154. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +38 -0
  155. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +45 -0
  156. simtools/schemas/model_parameters/dsum_shaping.schema.yml +44 -0
  157. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +32 -0
  158. simtools/schemas/model_parameters/dsum_threshold.schema.yml +43 -0
  159. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +42 -0
  160. simtools/schemas/model_parameters/effective_focal_length.schema.yml +61 -0
  161. simtools/schemas/model_parameters/epsg_code.schema.yml +37 -0
  162. simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +35 -0
  163. simtools/schemas/model_parameters/fadc_amplitude.schema.yml +46 -0
  164. simtools/schemas/model_parameters/fadc_bins.schema.yml +40 -0
  165. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +50 -0
  166. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +38 -0
  167. simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +42 -0
  168. simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +49 -0
  169. simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +47 -0
  170. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +51 -0
  171. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +37 -0
  172. simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +43 -0
  173. simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +49 -0
  174. simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +43 -0
  175. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +39 -0
  176. simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +42 -0
  177. simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +40 -0
  178. simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +50 -0
  179. simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +42 -0
  180. simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +41 -0
  181. simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +42 -0
  182. simtools/schemas/model_parameters/fadc_max_signal.schema.yml +43 -0
  183. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +39 -0
  184. simtools/schemas/model_parameters/fadc_mhz.schema.yml +31 -0
  185. simtools/schemas/model_parameters/fadc_noise.schema.yml +41 -0
  186. simtools/schemas/model_parameters/fadc_pedestal.schema.yml +40 -0
  187. simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +39 -0
  188. simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +50 -0
  189. simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +43 -0
  190. simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +43 -0
  191. simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +42 -0
  192. simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +41 -0
  193. simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +42 -0
  194. simtools/schemas/model_parameters/flatfielding.schema.yml +37 -0
  195. simtools/schemas/model_parameters/focal_length.schema.yml +45 -0
  196. simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +158 -0
  197. simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +29 -0
  198. simtools/schemas/model_parameters/focus_offset.schema.yml +66 -0
  199. simtools/schemas/model_parameters/gain_variation.schema.yml +43 -0
  200. simtools/schemas/model_parameters/geomag_horizontal.schema.yml +34 -0
  201. simtools/schemas/model_parameters/geomag_rotation.schema.yml +37 -0
  202. simtools/schemas/model_parameters/geomag_vertical.schema.yml +34 -0
  203. simtools/schemas/model_parameters/hg_lg_variation.schema.yml +36 -0
  204. simtools/schemas/model_parameters/iobuf_maximum.schema.yml +34 -0
  205. simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +34 -0
  206. simtools/schemas/model_parameters/laser_events.schema.yml +36 -0
  207. simtools/schemas/model_parameters/laser_external_trigger.schema.yml +35 -0
  208. simtools/schemas/model_parameters/laser_photons.schema.yml +32 -0
  209. simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +34 -0
  210. simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +34 -0
  211. simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +33 -0
  212. simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +33 -0
  213. simtools/schemas/model_parameters/laser_var_photons.schema.yml +33 -0
  214. simtools/schemas/model_parameters/laser_wavelength.schema.yml +33 -0
  215. simtools/schemas/model_parameters/led_events.schema.yml +34 -0
  216. simtools/schemas/model_parameters/led_photons.schema.yml +34 -0
  217. simtools/schemas/model_parameters/led_pulse_offset.schema.yml +32 -0
  218. simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +33 -0
  219. simtools/schemas/model_parameters/led_var_photons.schema.yml +34 -0
  220. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +41 -0
  221. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +43 -0
  222. simtools/schemas/model_parameters/min_photoelectrons.schema.yml +35 -0
  223. simtools/schemas/model_parameters/min_photons.schema.yml +32 -0
  224. simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +36 -0
  225. simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +64 -0
  226. simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +64 -0
  227. simtools/schemas/model_parameters/mirror_class.schema.yml +41 -0
  228. simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +51 -0
  229. simtools/schemas/model_parameters/mirror_focal_length.schema.yml +42 -0
  230. simtools/schemas/model_parameters/mirror_list.schema.yml +38 -0
  231. simtools/schemas/model_parameters/mirror_offset.schema.yml +41 -0
  232. simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +39 -0
  233. simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +61 -0
  234. simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +40 -0
  235. simtools/schemas/model_parameters/multiplicity_offset.schema.yml +46 -0
  236. simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +51 -0
  237. simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +37 -0
  238. simtools/schemas/model_parameters/nsb_offaxis.schema.yml +79 -0
  239. simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +47 -0
  240. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +34 -0
  241. simtools/schemas/model_parameters/nsb_reference_value.schema.yml +33 -0
  242. simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +35 -0
  243. simtools/schemas/model_parameters/nsb_skymap.schema.yml +39 -0
  244. simtools/schemas/model_parameters/nsb_spectrum.schema.yml +50 -0
  245. simtools/schemas/model_parameters/num_gains.schema.yml +34 -0
  246. simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +33 -0
  247. simtools/schemas/model_parameters/optics_properties.schema.yml +31 -0
  248. simtools/schemas/model_parameters/parabolic_dish.schema.yml +32 -0
  249. simtools/schemas/model_parameters/pedestal_events.schema.yml +32 -0
  250. simtools/schemas/model_parameters/photon_delay.schema.yml +38 -0
  251. simtools/schemas/model_parameters/photons_per_run.schema.yml +33 -0
  252. simtools/schemas/model_parameters/pixel_cells.schema.yml +35 -0
  253. simtools/schemas/model_parameters/pixels_parallel.schema.yml +54 -0
  254. simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +40 -0
  255. simtools/schemas/model_parameters/pm_average_gain.schema.yml +34 -0
  256. simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +40 -0
  257. simtools/schemas/model_parameters/pm_gain_index.schema.yml +36 -0
  258. simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +41 -0
  259. simtools/schemas/model_parameters/pm_transit_time.schema.yml +63 -0
  260. simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +39 -0
  261. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +42 -0
  262. simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +33 -0
  263. simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +33 -0
  264. simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +29 -0
  265. simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +168 -0
  266. simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +36 -0
  267. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +34 -0
  268. simtools/schemas/model_parameters/qe_variation.schema.yml +43 -0
  269. simtools/schemas/model_parameters/quantum_efficiency.schema.yml +42 -0
  270. simtools/schemas/model_parameters/random_focal_length.schema.yml +45 -0
  271. simtools/schemas/model_parameters/random_generator.schema.yml +36 -0
  272. simtools/schemas/model_parameters/reference_point_altitude.schema.yml +35 -0
  273. simtools/schemas/model_parameters/reference_point_latitude.schema.yml +36 -0
  274. simtools/schemas/model_parameters/reference_point_longitude.schema.yml +36 -0
  275. simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +34 -0
  276. simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +34 -0
  277. simtools/schemas/model_parameters/sampled_output.schema.yml +31 -0
  278. simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +34 -0
  279. simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +79 -0
  280. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +42 -0
  281. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +41 -0
  282. simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +33 -0
  283. simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +36 -0
  284. simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +29 -0
  285. simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +168 -0
  286. simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +36 -0
  287. simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +35 -0
  288. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +37 -0
  289. simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +40 -0
  290. simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +40 -0
  291. simtools/schemas/model_parameters/store_photoelectrons.schema.yml +41 -0
  292. simtools/schemas/model_parameters/tailcut_scale.schema.yml +40 -0
  293. simtools/schemas/model_parameters/telescope_axis_height.schema.yml +31 -0
  294. simtools/schemas/model_parameters/telescope_random_angle.schema.yml +35 -0
  295. simtools/schemas/model_parameters/telescope_random_error.schema.yml +34 -0
  296. simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +37 -0
  297. simtools/schemas/model_parameters/telescope_transmission.schema.yml +113 -0
  298. simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +41 -0
  299. simtools/schemas/model_parameters/teltrig_min_time.schema.yml +36 -0
  300. simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +36 -0
  301. simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +37 -0
  302. simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +38 -0
  303. simtools/schemas/model_parameters/transit_time_error.schema.yml +45 -0
  304. simtools/schemas/model_parameters/transit_time_jitter.schema.yml +36 -0
  305. simtools/schemas/model_parameters/trigger_current_limit.schema.yml +32 -0
  306. simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +53 -0
  307. simtools/schemas/model_parameters/trigger_pixels.schema.yml +40 -0
  308. simtools/simtel/simtel_config_reader.py +353 -0
  309. simtools/simtel/simtel_config_writer.py +244 -63
  310. simtools/simtel/{simtel_events.py → simtel_io_events.py} +26 -25
  311. simtools/simtel/simtel_io_histogram.py +661 -0
  312. simtools/simtel/simtel_io_histograms.py +569 -0
  313. simtools/simtel/simulator_array.py +145 -0
  314. simtools/simtel/{simtel_runner_camera_efficiency.py → simulator_camera_efficiency.py} +76 -52
  315. simtools/simtel/simulator_light_emission.py +473 -0
  316. simtools/simtel/simulator_ray_tracing.py +262 -0
  317. simtools/simulator.py +220 -446
  318. simtools/testing/__init__.py +0 -0
  319. simtools/testing/assertions.py +151 -0
  320. simtools/testing/configuration.py +226 -0
  321. simtools/testing/helpers.py +42 -0
  322. simtools/testing/validate_output.py +240 -0
  323. simtools/utils/general.py +340 -437
  324. simtools/utils/geometry.py +12 -12
  325. simtools/utils/names.py +257 -644
  326. simtools/utils/value_conversion.py +176 -0
  327. simtools/version.py +3 -1
  328. simtools/visualization/legend_handlers.py +135 -152
  329. simtools/visualization/plot_camera.py +379 -0
  330. simtools/visualization/visualize.py +346 -167
  331. gammasimtools-0.6.1.dist-info/METADATA +0 -180
  332. gammasimtools-0.6.1.dist-info/RECORD +0 -91
  333. gammasimtools-0.6.1.dist-info/entry_points.txt +0 -23
  334. simtools/_dev_version/scm_version.py +0 -10
  335. simtools/applications/db_development_tools/add_new_parameter_to_db.py +0 -81
  336. simtools/applications/db_development_tools/add_unit_to_parameter_in_db.py +0 -59
  337. simtools/applications/db_development_tools/mark_non_optics_parameters_non_applicable.py +0 -102
  338. simtools/applications/get_parameter.py +0 -92
  339. simtools/applications/make_regular_arrays.py +0 -160
  340. simtools/applications/produce_array_config.py +0 -136
  341. simtools/applications/production.py +0 -313
  342. simtools/applications/sim_showers_for_trigger_rates.py +0 -187
  343. simtools/applications/tune_psf.py +0 -334
  344. simtools/corsika/corsika_default_config.py +0 -282
  345. simtools/corsika/corsika_runner.py +0 -450
  346. simtools/corsika_simtel/corsika_simtel_runner.py +0 -197
  347. simtools/db_handler.py +0 -1480
  348. simtools/ray_tracing.py +0 -525
  349. simtools/simtel/simtel_histograms.py +0 -414
  350. simtools/simtel/simtel_runner.py +0 -244
  351. simtools/simtel/simtel_runner_array.py +0 -293
  352. simtools/simtel/simtel_runner_ray_tracing.py +0 -277
  353. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/LICENSE +0 -0
  354. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/top_level.txt +0 -0
  355. /simtools/{corsika_simtel → db}/__init__.py +0 -0
@@ -1,3 +1,6 @@
1
+ """Prepare layout for coordinate transformations."""
2
+
3
+ import json
1
4
  import logging
2
5
  from pathlib import Path
3
6
 
@@ -5,22 +8,23 @@ import astropy.units as u
5
8
  import numpy as np
6
9
  from astropy.table import QTable
7
10
 
8
- from simtools import db_handler
11
+ import simtools.utils.general as gen
9
12
  from simtools.data_model import data_reader
10
13
  from simtools.io_operations import io_handler
11
14
  from simtools.layout.geo_coordinates import GeoCoordinates
12
15
  from simtools.layout.telescope_position import TelescopePosition
13
- from simtools.utils import names
14
- from simtools.utils.general import collect_data_from_file_or_dict
16
+ from simtools.model.site_model import SiteModel
17
+ from simtools.model.telescope_model import TelescopeModel
18
+ from simtools.utils import names, value_conversion
15
19
 
16
- __all__ = ["InvalidTelescopeListFile", "ArrayLayout"]
20
+ __all__ = ["ArrayLayout", "InvalidTelescopeListFileError"]
17
21
 
18
22
 
19
- class InvalidTelescopeListFile(Exception):
23
+ class InvalidTelescopeListFileError(Exception):
20
24
  """Exception for invalid telescope list file."""
21
25
 
22
26
 
23
- class InvalidCoordinateDataType(Exception):
27
+ class InvalidCoordinateDataTypeError(Exception):
24
28
  """Exception for low-precision coordinate data type."""
25
29
 
26
30
 
@@ -34,334 +38,139 @@ class ArrayLayout:
34
38
  MongoDB configuration.
35
39
  site: str
36
40
  Site name or location (e.g., North/South or LaPalma/Paranal)
41
+ model_version: str
42
+ Version of the model (e.g., 6.0.0).
37
43
  label: str
38
44
  Instance label.
39
45
  name: str
40
46
  Name of the layout.
41
- layout_center_data: dict
42
- Dict describing array center coordinates.
43
- corsika_telescope_data: dict
44
- Dict describing CORSIKA telescope parameters.
45
47
  telescope_list_file: str or Path
46
48
  Path to the telescope list file.
49
+ telescope_list_metadata_file: str or Path
50
+ Path to telescope list metadata (if not part of telescope_list_file)
51
+ validate: bool
52
+ Validate input file list.
47
53
  """
48
54
 
49
55
  def __init__(
50
56
  self,
51
- mongo_db_config=None,
52
- site=None,
57
+ mongo_db_config,
58
+ site,
59
+ model_version,
53
60
  label=None,
54
61
  name=None,
55
- layout_center_data=None,
56
- corsika_telescope_data=None,
57
62
  telescope_list_file=None,
58
63
  telescope_list_metadata_file=None,
59
64
  validate=False,
60
65
  ):
61
- """
62
- Initialize ArrayLayout.
63
- """
64
-
66
+ """Initialize ArrayLayout."""
65
67
  self._logger = logging.getLogger(__name__)
66
68
 
67
- self.mongo_db_config = mongo_db_config
69
+ self.model_version = model_version
68
70
  self.label = label
69
71
  self.name = name
72
+ self.mongo_db_config = mongo_db_config
70
73
  self.site = None if site is None else names.validate_site_name(site)
74
+ self.site_model = None
71
75
  self.io_handler = io_handler.IOHandler()
72
76
  self.geo_coordinates = GeoCoordinates()
73
77
 
74
- self.telescope_list_file = None
75
78
  self._telescope_list = []
76
- self._epsg = None
79
+ self._corsika_observation_level = None
80
+ self._reference_position_dict = {}
81
+ self._array_center = None
77
82
 
78
- if telescope_list_file is None:
79
- self._initialize_coordinate_systems(layout_center_data)
80
- self._initialize_corsika_telescope(corsika_telescope_data)
81
- else:
82
- self.initialize_array_layout_from_telescope_file(
83
- telescope_list_file=telescope_list_file,
84
- telescope_list_metadata_file=telescope_list_metadata_file,
85
- validate=validate,
86
- )
87
-
88
- @classmethod
89
- def from_array_layout_name(cls, mongo_db_config, array_layout_name, label=None):
90
- """
91
- Read telescope list from file for given layout name (e.g. South-4LST, North-Prod5, ...).
92
- Layout definitions are given in the `data/layout` path.
93
-
94
- Parameters
95
- ----------
96
- mongo_db_config: dict
97
- MongoDB configuration.
98
- array_layout_name: str
99
- e.g. South-4LST, North-Prod5 ...
100
- label: str
101
- Instance label. Important for output file naming.
102
-
103
- Returns
104
- -------
105
- ArrayLayout
106
- Instance of the ArrayLayout.
107
- """
108
-
109
- split_name = array_layout_name.split("-")
110
- site_name = names.validate_site_name(split_name[0])
111
- array_name = names.validate_array_layout_name(split_name[1])
112
- valid_array_layout_name = site_name + "-" + array_name
113
-
114
- layout = cls(
115
- site=site_name,
116
- mongo_db_config=mongo_db_config,
117
- name=valid_array_layout_name,
118
- label=label,
119
- )
120
-
121
- telescope_list_file = layout.io_handler.get_input_data_file(
122
- "layout", f"telescope_positions-{valid_array_layout_name}.ecsv"
83
+ self._initialize_array_layout(
84
+ telescope_list_file=telescope_list_file,
85
+ telescope_list_metadata_file=telescope_list_metadata_file,
86
+ validate=validate,
123
87
  )
124
- layout.initialize_array_layout_from_telescope_file(telescope_list_file)
125
-
126
- return layout
127
88
 
128
89
  def __len__(self):
129
- """
130
- Return number of telescopes in the layout.
131
- """
90
+ """Return number of telescopes in the layout."""
132
91
  return len(self._telescope_list)
133
92
 
134
93
  def __getitem__(self, i):
135
- """
136
- Return telescope at list position i.
137
-
138
- """
94
+ """Return telescope at list position i."""
139
95
  return self._telescope_list[i]
140
96
 
141
- def _initialize_corsika_telescope(self, corsika_dict=None):
142
- """
143
- Initialize Dictionary for CORSIKA telescope parameters. Allow input from different sources
144
- (dictionary, yaml, ecsv header), which require checks to handle units correctly.
145
-
146
- Parameters
147
- ----------
148
- corsika_dict dict
149
- dictionary with CORSIKA telescope parameters
150
-
151
- """
152
- self._corsika_telescope = {}
153
-
154
- if corsika_dict is None:
155
- self._logger.debug("Initialize CORSIKA telescope parameters from file")
156
- corsika_dict = self._from_corsika_file_to_dict()
157
- else:
158
- self._logger.debug(f"Initialize CORSIKA telescope parameters from dict: {corsika_dict}")
159
-
160
- self._initialize_corsika_telescope_from_dict(corsika_dict)
161
-
162
- def _from_corsika_file_to_dict(self, file_name=None):
163
- """
164
- Get the corsika parameter file and return a dictionary with the keys necessary to
165
- initialize this class.
166
-
167
- Parameters
168
- ----------
169
- file_name: str or Path
170
- File from which to extract the corsika parameters. Default is
171
- data/parameters/corsika_parameters.yml
172
-
173
- Returns
174
- ------
175
- corsika_dict:
176
- Dictionary with corsika telescopes information.
177
-
178
- Raises
179
- ------
180
- FileNotFoundError:
181
- If file_name does not exist.
182
- """
183
- if file_name is None:
184
- try:
185
- corsika_parameters_dict = collect_data_from_file_or_dict(
186
- self.io_handler.get_input_data_file("parameters", "corsika_parameters.yml"),
187
- None,
188
- )
189
- except io_handler.IncompleteIOHandlerInit:
190
- self._logger.info("Error reading CORSIKA parameters from file")
191
- return {}
192
- else:
193
- if not isinstance(file_name, Path):
194
- file_name = Path(file_name)
195
- if file_name.exists():
196
- corsika_parameters_dict = collect_data_from_file_or_dict(file_name, None)
197
- else:
198
- raise FileNotFoundError
199
-
200
- corsika_dict = {}
201
- corsika_pars = ["corsika_sphere_radius", "corsika_sphere_center"]
202
- for simtools_par in corsika_pars:
203
- corsika_par = names.translate_simtools_to_corsika(simtools_par)
204
- corsika_dict[simtools_par] = {}
205
- for key, value in corsika_parameters_dict[corsika_par].items():
206
- corsika_dict[simtools_par][key] = value["value"]
207
- try:
208
- unit = value["unit"]
209
- corsika_dict[simtools_par][key] = corsika_dict[simtools_par][key] * u.Unit(unit)
210
- except KeyError:
211
- self._logger.warning(
212
- "Key not valid. Dictionary does not have a key 'unit'. Continuing without "
213
- "the unit."
214
- )
215
-
97
+ def _initialize_site_parameters_from_db(self):
98
+ """Initialize site parameters required for transformations using the database."""
99
+ self._logger.debug("Initialize parameters from DB")
216
100
  if self.mongo_db_config is None:
217
- self._logger.error("DB connection info was not provided, cannot set site altitude")
218
- raise ValueError
219
- if self.site is None:
220
- self._logger.error("Site was not provided, cannot set site altitude")
221
- raise ValueError
222
-
223
- db = db_handler.DatabaseHandler(mongo_db_config=self.mongo_db_config)
224
- self._logger.debug("Reading site parameters from DB")
225
- _site_pars = db.get_site_parameters(self.site, "Released", only_applicable=True)
226
- corsika_dict["corsika_obs_level"] = _site_pars["altitude"]["Value"] * u.Unit(
227
- _site_pars["altitude"]["units"]
228
- )
229
-
230
- return corsika_dict
231
-
232
- def _initialize_sphere_parameters(self, sphere_dict):
233
- """
234
- Set CORSIKA sphere parameters from dictionary. Type of input varies and depend on data \
235
- source for these parameters.
236
-
237
- Example for sphere_dict: {LST: 12.5 m, MST: 9.15 m, SST: 3 m}
238
-
239
- Parameters
240
- ----------
241
- sphere_dict: dict
242
- dictionary with sphere parameters
243
-
244
- Returns
245
- -------
246
- dict
247
- dictionary with sphere parameters.
248
-
249
- """
250
-
251
- _sphere_dict_cleaned = {}
252
- try:
253
- for key, value in sphere_dict.items():
254
- if isinstance(value, (str, u.Quantity)):
255
- _sphere_dict_cleaned[key] = u.Quantity(value)
256
- else:
257
- _sphere_dict_cleaned[key] = value["value"] * u.Unit(value["unit"])
258
- except (TypeError, KeyError) as exc:
259
- self._logger.error(f"Error setting CORSIKA sphere parameters from {sphere_dict}")
260
- raise exc
261
-
262
- return _sphere_dict_cleaned
101
+ raise ValueError("No database configuration provided")
263
102
 
264
- def _initialize_corsika_telescope_from_dict(self, corsika_dict):
265
- """
266
- Initialize CORSIKA telescope parameters from a dictionary.
267
-
268
- Parameters
269
- ----------
270
- corsika_dict dict
271
- dictionary with CORSIKA telescope parameters
272
-
273
- """
274
-
275
- try:
276
- self._corsika_telescope["corsika_obs_level"] = u.Quantity(
277
- corsika_dict["corsika_obs_level"]
278
- )
279
- except (TypeError, KeyError):
280
- self._corsika_telescope["corsika_obs_level"] = np.nan * u.m
281
-
282
- for key in ["corsika_sphere_center", "corsika_sphere_radius"]:
283
- try:
284
- self._corsika_telescope[key] = self._initialize_sphere_parameters(corsika_dict[key])
285
- except (TypeError, KeyError):
286
- pass
103
+ self.site_model = SiteModel(
104
+ site=self.site,
105
+ model_version=self.model_version,
106
+ mongo_db_config=self.mongo_db_config,
107
+ )
108
+ self._corsika_observation_level = self.site_model.get_corsika_site_parameters().get(
109
+ "corsika_observation_level", None
110
+ )
111
+ self._reference_position_dict = self.site_model.get_reference_point()
112
+ self._logger.debug(f"Reference point: {self._reference_position_dict}")
287
113
 
288
- def _initialize_coordinate_systems(self, center_dict=None):
114
+ def _initialize_coordinate_systems(self):
289
115
  """
290
116
  Initialize array center and coordinate systems.
117
+
291
118
  By definition, the array center is at (0,0) in
292
119
  the ground coordinate system.
293
120
 
294
- Parameters
295
- ----------
296
- center_dict: dict
297
- dictionary with coordinates of array center.
298
-
299
121
  Raises
300
122
  ------
301
123
  TypeError
302
124
  invalid array center definition.
303
125
 
304
126
  """
305
-
306
- center_dict = {} if center_dict is None else center_dict
307
-
308
127
  self._array_center = TelescopePosition()
309
128
  self._array_center.name = "array_center"
310
- self._array_center.set_coordinates("ground", 0.0 * u.m, 0.0 * u.m, 0.0 * u.m)
311
- self._set_array_center_mercator(center_dict)
312
- self._set_array_center_utm(center_dict)
313
- self._array_center.set_altitude(u.Quantity(center_dict.get("center_alt", np.nan * u.m)))
314
- _name = center_dict.get("array_name")
129
+ self._array_center.set_coordinates("ground", 0.0 * u.m, 0.0 * u.m)
130
+ self._set_array_center_utm()
131
+ self._array_center.set_altitude(
132
+ u.Quantity(self._reference_position_dict.get("center_altitude", np.nan * u.m))
133
+ )
134
+ _name = self._reference_position_dict.get("array_name")
315
135
  self.name = _name if _name is not None else self.name
316
136
 
137
+ self._logger.debug(f"Initialized array center at UTM {self._reference_position_dict}")
317
138
  self._array_center.convert_all(
318
139
  crs_local=self.geo_coordinates.crs_local(self._array_center),
319
140
  crs_wgs84=self.geo_coordinates.crs_wgs84(),
320
- crs_utm=self.geo_coordinates.crs_utm(self._epsg),
141
+ crs_utm=self.geo_coordinates.crs_utm(
142
+ self._reference_position_dict.get("epsg_code", None)
143
+ ),
321
144
  )
322
145
 
323
- def _set_array_center_mercator(self, center_dict):
324
- """
325
- Set array center coordinates in mercator system.
326
-
327
- """
328
-
329
- try:
330
- self._array_center.set_coordinates(
331
- "mercator",
332
- u.Quantity(center_dict.get("center_lat", np.nan * u.deg)),
333
- u.Quantity(center_dict.get("center_lon", np.nan * u.deg)),
334
- )
335
- except TypeError:
336
- pass
337
-
338
- def _set_array_center_utm(self, center_dict):
146
+ def _set_array_center_utm(self):
339
147
  """
340
148
  Set array center coordinates in UTM system.
149
+
341
150
  Convert array center position to WGS84 system
342
151
  (as latitudes are required for the definition
343
152
  for the definition of the ground coordinate system)
344
153
 
345
154
  """
346
- try:
347
- self._epsg = center_dict.get("EPSG", None)
348
- self._array_center.set_coordinates(
349
- "utm",
350
- u.Quantity(center_dict.get("center_easting", np.nan * u.m)),
351
- u.Quantity(center_dict.get("center_northing", np.nan * u.m)),
352
- )
353
- self._array_center.convert_all(
354
- crs_local=None,
355
- crs_wgs84=self.geo_coordinates.crs_wgs84(),
356
- crs_utm=self.geo_coordinates.crs_utm(self._epsg),
357
- )
358
- except TypeError:
359
- pass
155
+ self._array_center.set_coordinates(
156
+ "utm",
157
+ u.Quantity(self._reference_position_dict.get("center_easting", np.nan * u.m)),
158
+ u.Quantity(self._reference_position_dict.get("center_northing", np.nan * u.m)),
159
+ )
160
+ self._array_center.convert_all(
161
+ crs_local=None,
162
+ crs_wgs84=self.geo_coordinates.crs_wgs84(),
163
+ crs_utm=self.geo_coordinates.crs_utm(
164
+ self._reference_position_dict.get("epsg_code", None)
165
+ ),
166
+ )
360
167
 
361
- def _altitude_from_corsika_z(self, pos_z=None, altitude=None, tel_name=None):
168
+ def _altitude_from_corsika_z(self, pos_z=None, altitude=None, telescope_axis_height=None):
362
169
  """
363
- Calculate altitude from CORSIKA z-coordinate (if pos_z is given) or CORSIKA z-coordinate \
364
- from altitude (if altitude is given).
170
+ Calculate altitude.
171
+
172
+ The value is calculated from CORSIKA z-coordinate (if pos_z is given) or CORSIKA
173
+ z-coordinate from altitude (if altitude is given).
365
174
 
366
175
  Parameters
367
176
  ----------
@@ -369,8 +178,8 @@ class ArrayLayout:
369
178
  CORSIKA z-coordinate of telescope in equivalent units of meter.
370
179
  altitude: astropy.Quantity
371
180
  Telescope altitude in equivalent units of meter.
372
- tel_name: str
373
- Telescope Name.
181
+ tel_axis_height: astropy.Quantity
182
+ Telescope axis height in equivalent units of meter.
374
183
 
375
184
  Returns
376
185
  -------
@@ -378,58 +187,27 @@ class ArrayLayout:
378
187
  Altitude or CORSIKA z-coordinate (np.nan in case of ill-defined value).
379
188
 
380
189
  """
190
+ self._logger.debug(
191
+ f"pos_z: {pos_z}, altitude: {altitude}, "
192
+ f"axis_height: {telescope_axis_height}, "
193
+ f"obs_level: {self._corsika_observation_level}"
194
+ )
195
+
381
196
  if pos_z is not None and altitude is None:
382
197
  return TelescopePosition.convert_telescope_altitude_from_corsika_system(
383
198
  pos_z,
384
- self._corsika_telescope["corsika_obs_level"],
385
- self._get_corsika_sphere_center(tel_name),
199
+ self._corsika_observation_level,
200
+ telescope_axis_height,
386
201
  )
387
202
 
388
203
  if altitude is not None and pos_z is None:
389
204
  return TelescopePosition.convert_telescope_altitude_to_corsika_system(
390
205
  altitude,
391
- self._corsika_telescope["corsika_obs_level"],
392
- self._get_corsika_sphere_center(tel_name),
206
+ self._corsika_observation_level,
207
+ telescope_axis_height,
393
208
  )
394
209
  return np.nan
395
210
 
396
- def _get_corsika_sphere_center(self, tel_name):
397
- """
398
- Return CORSIKA sphere center value for given telescope.
399
-
400
- Parameters
401
- ----------
402
- tel_name: str
403
- Telescope Name.
404
-
405
- Returns
406
- -------
407
- astropy.Quantity
408
- Telescope sphere center value (0.0*u.m if sphere center is not defined).
409
-
410
- Raises
411
- ------
412
- KeyError
413
- if Missing definition of CORSIKA sphere center for this telescope type.
414
-
415
- """
416
-
417
- try:
418
- return self._corsika_telescope["corsika_sphere_center"][
419
- names.get_telescope_class(tel_name)
420
- ]
421
- except KeyError:
422
- self._logger.warning(
423
- "Missing definition of CORSIKA sphere center for telescope "
424
- f"{tel_name} of type {names.get_telescope_class(tel_name)}"
425
- )
426
- except ValueError:
427
- self._logger.warning(
428
- f"Missing definition of CORSIKA sphere center for telescope {tel_name}"
429
- )
430
-
431
- return 0.0 * u.m
432
-
433
211
  def _load_telescope_names(self, row):
434
212
  """
435
213
  Read and set telescope names.
@@ -446,17 +224,16 @@ class ArrayLayout:
446
224
 
447
225
  Raises
448
226
  ------
449
- InvalidTelescopeListFile
227
+ InvalidTelescopeListFileError
450
228
  in case neither telescope name or asset_code / sequence number are given.
451
229
 
452
230
  """
453
-
454
231
  tel = TelescopePosition()
455
232
  try:
456
233
  tel.name = row["telescope_name"]
457
234
  if "asset_code" not in row:
458
235
  try:
459
- tel.asset_code = names.get_telescope_class(tel.name)
236
+ tel.asset_code = names.get_array_element_type_from_name(tel.name)
460
237
  # asset code is not a valid telescope name; possibly a calibration device
461
238
  except ValueError:
462
239
  tel.asset_code = tel.name.split("-")[0]
@@ -476,39 +253,13 @@ class ArrayLayout:
476
253
  if tel.name is None:
477
254
  msg = "Missing required row with telescope_name or asset_code/sequence_number"
478
255
  self._logger.error(msg)
479
- raise InvalidTelescopeListFile(msg)
256
+ raise InvalidTelescopeListFileError(msg)
480
257
 
481
258
  return tel
482
259
 
483
- def _assign_unit_to_quantity(self, value, unit):
484
- """
485
- Assign unit to quantity.
486
-
487
- Parameters
488
- ----------
489
- value:
490
- value to get a unit. It can be a float, int, or a Quantity (convertible to 'unit').
491
- unit: astropy.units.Unit
492
- Unit to apply to 'quantity'.
493
-
494
- Returns
495
- -------
496
- astropy.units.Quantity
497
- Quantity of value 'quantity' and unit 'unit'.
498
- """
499
- if isinstance(value, u.Quantity):
500
- if isinstance(value.unit, type(unit)):
501
- return value
502
- try:
503
- value = value.to(unit)
504
- return value
505
- except u.UnitConversionError:
506
- self._logger.error(f"Cannot convert {value.unit} to {unit}.")
507
- raise
508
- return value * unit
509
-
510
260
  def _try_set_coordinate(self, row, tel, table, crs_name, key1, key2):
511
- """Function auxiliary to self._load_telescope_list. It sets the coordinates.
261
+ """
262
+ Try and set coordinates for all coordinate systems.
512
263
 
513
264
  Parameters
514
265
  ----------
@@ -528,16 +279,17 @@ class ArrayLayout:
528
279
  try:
529
280
  tel.set_coordinates(
530
281
  crs_name,
531
- self._assign_unit_to_quantity(row[key1], table[key1].unit),
532
- self._assign_unit_to_quantity(row[key2], table[key2].unit),
282
+ value_conversion.get_value_as_quantity(row[key1], table[key1].unit),
283
+ value_conversion.get_value_as_quantity(row[key2], table[key2].unit),
533
284
  )
534
285
  except KeyError:
535
286
  pass
536
287
 
537
288
  def _try_set_altitude(self, row, tel, table):
538
289
  """
539
- Function auxiliary to self._load_telescope_list. It sets the altitude of the
540
- TelescopePosition instance.
290
+ Try and set altitude.
291
+
292
+ It sets the altitude of the TelescopePosition instance.
541
293
 
542
294
  Parameters
543
295
  ----------
@@ -551,70 +303,159 @@ class ArrayLayout:
551
303
  try:
552
304
  tel.set_altitude(
553
305
  self._altitude_from_corsika_z(
554
- pos_z=self._assign_unit_to_quantity(
306
+ pos_z=value_conversion.get_value_as_quantity(
555
307
  row["position_z"], table["position_z"].unit
556
308
  ),
557
- tel_name=tel.name,
309
+ telescope_axis_height=tel.get_axis_height(),
558
310
  )
559
311
  )
560
312
  except KeyError:
561
313
  pass
562
314
  try:
563
- tel.set_altitude(self._assign_unit_to_quantity(row["altitude"], table["altitude"].unit))
315
+ tel.set_altitude(
316
+ value_conversion.get_value_as_quantity(row["altitude"], table["altitude"].unit)
317
+ )
564
318
  except KeyError:
565
319
  pass
566
320
 
567
- def _load_telescope_list(self, table):
321
+ def _initialize_array_layout(
322
+ self, telescope_list_file, telescope_list_metadata_file=None, validate=False
323
+ ):
568
324
  """
569
- Load list of telescope from an astropy table (support both QTable and Table)
325
+ Initialize the Layout array including site and telescope parameters.
326
+
327
+ Read array list if telescope_list_file is given.
570
328
 
571
329
  Parameters
572
330
  ----------
573
- table: astropy.table.Table or astropy.table.QTable
574
- data table with array element coordinates
331
+ telescope_list_file: str or Path
332
+ Path to the telescope list file.
333
+ telescope_list_metadata_file: str or Path
334
+ Path to the telescope list metadata file.
335
+ validate: bool
336
+ Validate telescope list file against schema.
575
337
 
338
+ Returns
339
+ -------
340
+ astropy.table.QTable
341
+ Table with the telescope layout information.
576
342
  """
343
+ self._logger.debug("Initializing array (site and telescope parameters)")
344
+ self._initialize_site_parameters_from_db()
345
+ self._initialize_coordinate_systems()
346
+
347
+ if telescope_list_file is None:
348
+ return None
349
+
350
+ self._logger.debug(f"Reading telescope list from {telescope_list_file}")
351
+ if Path(telescope_list_file).suffix == ".json":
352
+ table = self._read_table_from_json_file(file_name=telescope_list_file)
353
+ else:
354
+ table = data_reader.read_table_from_file(
355
+ file_name=telescope_list_file,
356
+ validate=validate,
357
+ metadata_file=telescope_list_metadata_file,
358
+ )
359
+
577
360
  for row in table:
578
361
  tel = self._load_telescope_names(row)
362
+ if names.get_collection_name_from_array_element_name(tel.name) == "telescopes":
363
+ self._set_telescope_auxiliary_parameters(tel)
579
364
  self._try_set_coordinate(row, tel, table, "ground", "position_x", "position_y")
580
365
  self._try_set_coordinate(row, tel, table, "utm", "utm_east", "utm_north")
581
366
  self._try_set_coordinate(row, tel, table, "mercator", "latitude", "longitude")
582
367
  self._try_set_altitude(row, tel, table)
583
-
584
368
  self._telescope_list.append(tel)
585
369
 
586
- def initialize_array_layout_from_telescope_file(
587
- self, telescope_list_file, telescope_list_metadata_file=None, validate=False
588
- ):
370
+ return table
371
+
372
+ def _read_table_from_json_file(self, file_name):
589
373
  """
590
- Initialize the Layout array from a telescope list file.
374
+ Read a telescope position from a json file and return as astropy table.
591
375
 
592
376
  Parameters
593
377
  ----------
594
- telescope_list_file: str or Path
595
- Path to the telescope list file.
596
- telescope_list_metadata_file: str or Path
597
- Path to the telescope list metadata file.
598
- validate: bool
599
- Validate the telescope list file.
378
+ file_name: str or Path
379
+ Path to the json file.
600
380
 
601
381
  Returns
602
382
  -------
603
383
  astropy.table.QTable
604
384
  Table with the telescope layout information.
605
385
  """
606
- table = data_reader.read_table_from_file(
607
- file_name=telescope_list_file,
608
- validate=validate,
609
- metadata_file=telescope_list_metadata_file,
610
- )
611
- self._initialize_corsika_telescope(table.meta)
612
- self._initialize_coordinate_systems(table.meta)
613
- self._load_telescope_list(table)
386
+ with Path(file_name).open("r", encoding="utf-8") as file:
387
+ data = json.load(file)
614
388
 
389
+ position = gen.convert_string_to_list(data["value"])
390
+ self.site = data.get("site", None)
391
+
392
+ table = QTable()
393
+ table["telescope_name"] = [data["instrument"]]
394
+ if "utm" in data["parameter"]:
395
+ table["utm_east"] = [position[0]] * u.Unit(data["unit"])
396
+ table["utm_north"] = [position[1]] * u.Unit(data["unit"])
397
+ table["altitude"] = [position[2]] * u.Unit(data["unit"])
398
+ else:
399
+ table["position_x"] = [position[0]] * u.Unit(data["unit"])
400
+ table["position_y"] = [position[1]] * u.Unit(data["unit"])
401
+ table["position_z"] = [position[2]] * u.Unit(data["unit"])
615
402
  return table
616
403
 
617
- def add_telescope(self, telescope_name, crs_name, xx, yy, altitude=None, tel_corsika_z=None):
404
+ def _get_telescope_model(self, telescope_name):
405
+ """
406
+ Get telescope model from the database.
407
+
408
+ Parameters
409
+ ----------
410
+ telescope_name: str
411
+ Name of the telescope.
412
+
413
+ Returns
414
+ -------
415
+ TelescopeModel
416
+ Telescope model instance.
417
+ """
418
+ return TelescopeModel(
419
+ site=self.site,
420
+ telescope_name=telescope_name,
421
+ model_version=self.model_version,
422
+ mongo_db_config=self.mongo_db_config,
423
+ label=self.label,
424
+ )
425
+
426
+ def _set_telescope_auxiliary_parameters(self, telescope, telescope_name=None):
427
+ """
428
+ Set auxiliary CORSIKA parameters for a telescope.
429
+
430
+ Uses as default the design model if telescope is not found in the database.
431
+
432
+ Parameters
433
+ ----------
434
+ telescope: TelescopePosition
435
+ Instance of TelescopePosition.
436
+
437
+ """
438
+ telescope_name = telescope_name if telescope_name is not None else telescope.name
439
+ if names.get_collection_name_from_array_element_name(telescope_name) == "telescopes":
440
+ self._logger.debug(
441
+ f"Reading auxiliary telescope parameters for {telescope_name}"
442
+ f" (model version {self.model_version})"
443
+ )
444
+ try:
445
+ tel_model = self._get_telescope_model(telescope_name)
446
+ except ValueError:
447
+ tel_model = self._get_telescope_model(
448
+ names.get_array_element_type_from_name(telescope_name) + "-design",
449
+ )
450
+
451
+ for para in ("telescope_axis_height", "telescope_sphere_radius"):
452
+ telescope.set_auxiliary_parameter(
453
+ para, tel_model.get_parameter_value_with_unit(para)
454
+ )
455
+
456
+ def add_telescope(
457
+ self, telescope_name, crs_name, xx, yy, altitude=None, tel_corsika_z=None, design_model=None
458
+ ):
618
459
  """
619
460
  Add an individual telescope to the telescope list.
620
461
 
@@ -633,25 +474,28 @@ class ArrayLayout:
633
474
  tel_corsika_z: astropy.units.quantity.Quantity
634
475
  CORSIKA z-position (requires setting of CORSIKA observation level and telescope sphere\
635
476
  center).
477
+ design_model: str
478
+ Name of the design model (optional).
479
+ If none, telescope type + "-design" is used.
636
480
  """
637
-
638
481
  tel = TelescopePosition(name=telescope_name)
482
+ self._set_telescope_auxiliary_parameters(tel, design_model)
639
483
  tel.set_coordinates(crs_name, xx, yy)
640
484
  if altitude is not None:
641
485
  tel.set_altitude(altitude)
642
486
  elif tel_corsika_z is not None:
643
- tel.set_altitude(self._altitude_from_corsika_z(pos_z=tel_corsika_z, tel_name=tel.name))
487
+ tel.set_altitude(
488
+ self._altitude_from_corsika_z(
489
+ pos_z=tel_corsika_z, telescope_axis_height=tel.get_axis_height()
490
+ )
491
+ )
644
492
  self._telescope_list.append(tel)
645
493
 
646
- def _get_export_metadata(self, export_corsika_meta=False):
494
+ def _get_export_metadata(self):
647
495
  """
648
- File metadata for export of array element list to file. Included array center definition,\
649
- CORSIKA telescope parameters, and EPSG center
496
+ File metadata for export of array element list to file.
650
497
 
651
- Parameters
652
- ----------
653
- export_corsika_meta: bool
654
- write CORSIKA metadata.
498
+ Included array center definition, CORSIKA telescope parameters, and EPSG code.
655
499
 
656
500
  Returns
657
501
  -------
@@ -659,31 +503,19 @@ class ArrayLayout:
659
503
  Metadata header for array element list export.
660
504
 
661
505
  """
662
-
663
- _meta = {
664
- "center_lon": None,
665
- "center_lat": None,
666
- "center_northing": None,
667
- "center_easting": None,
668
- "center_alt": None,
669
- }
506
+ _meta = {}
670
507
  if self._array_center:
671
- _meta["center_lat"], _meta["center_lon"], _ = self._array_center.get_coordinates(
672
- "mercator"
673
- )
674
508
  (
675
509
  _meta["center_easting"],
676
510
  _meta["center_northing"],
677
- _meta["center_alt"],
511
+ _meta["center_altitude"],
678
512
  ) = self._array_center.get_coordinates("utm")
679
- if export_corsika_meta:
680
- _meta.update(self._corsika_telescope)
681
- _meta["EPSG"] = self._epsg
513
+ _meta["epsg_code"] = self._reference_position_dict.get("epsg_code", None)
682
514
  _meta["array_name"] = self.name
683
515
 
684
516
  return _meta
685
517
 
686
- def export_telescope_list_table(self, crs_name, corsika_z=False):
518
+ def export_telescope_list_table(self, crs_name):
687
519
  """
688
520
  Export array elements positions to astropy table.
689
521
 
@@ -691,31 +523,31 @@ class ArrayLayout:
691
523
  ----------
692
524
  crs_name: str
693
525
  Name of coordinate system to be used for export.
694
- corsika_z: bool
695
- Write telescope height in CORSIKA coordinates (for CORSIKA system).
696
526
 
697
527
  Returns
698
528
  -------
699
529
  astropy.table.QTable
700
530
  Astropy table with the telescope layout information.
701
-
702
531
  """
703
-
704
- table = QTable(meta=self._get_export_metadata(crs_name == "ground"))
532
+ table = QTable(meta=self._get_export_metadata())
705
533
 
706
534
  tel_names, asset_code, sequence_number, geo_code = [], [], [], []
707
- pos_x, pos_y, pos_z = [], [], []
535
+ pos_x, pos_y, pos_z, pos_t, tel_r = [], [], [], [], []
708
536
  for tel in self._telescope_list:
709
537
  tel_names.append(tel.name)
710
538
  asset_code.append(tel.asset_code)
711
539
  sequence_number.append(tel.sequence_number)
712
540
  geo_code.append(tel.geo_code)
713
541
  x, y, z = tel.get_coordinates(crs_name)
714
- if corsika_z:
715
- z = self._altitude_from_corsika_z(altitude=z, tel_name=tel.name)
542
+ if crs_name == "ground":
543
+ z = self._altitude_from_corsika_z(
544
+ altitude=z, telescope_axis_height=tel.get_axis_height()
545
+ )
546
+ pos_t.append(tel.get_axis_height())
716
547
  pos_x.append(x)
717
548
  pos_y.append(y)
718
549
  pos_z.append(z)
550
+ tel_r.append(tel.get_sphere_radius())
719
551
 
720
552
  # prefer asset_code / sequence_number of telescope_name
721
553
  if all(v is not None for v in asset_code) and all(v is not None for v in sequence_number):
@@ -732,137 +564,115 @@ class ArrayLayout:
732
564
  )
733
565
  table[_name_x] = pos_x
734
566
  table[_name_y] = pos_y
735
- if corsika_z:
736
- table["position_z"] = pos_z
737
- else:
738
- table[_name_z] = pos_z
567
+ table[_name_z] = pos_z
568
+ if len(pos_t) > 0:
569
+ table["telescope_axis_height"] = pos_t
570
+ if len(tel_r) > 0:
571
+ table["sphere_radius"] = tel_r
739
572
  except IndexError:
740
573
  pass
741
574
 
575
+ if "telescope_name" in table.colnames:
576
+ table.sort("telescope_name")
577
+ if "asset_code" in table.colnames:
578
+ table.sort(["asset_code", "sequence_number"])
579
+
742
580
  return table
743
581
 
744
- def get_number_of_telescopes(self):
582
+ def export_one_telescope_as_json(self, crs_name):
745
583
  """
746
- Return the number of telescopes in the list.
584
+ Return a list containing a single telescope in simtools-DB-style json.
585
+
586
+ Parameters
587
+ ----------
588
+ crs_name: str
589
+ Name of coordinate system to be used for export.
747
590
 
748
591
  Returns
749
592
  -------
750
- int
751
- Number of telescopes.
752
- """
753
- return len(self._telescope_list)
593
+ dict
594
+ Dictionary with array element information.
595
+ """
596
+ table = self.export_telescope_list_table(crs_name)
597
+ if len(table) != 1:
598
+ raise ValueError("Only one telescope can be exported to json")
599
+ parameter_name = value_string = None
600
+ if crs_name == "ground":
601
+ 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
+ )
609
+ elif crs_name == "utm":
610
+ 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
+ )
618
+ elif crs_name == "mercator":
619
+ 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
+ return {
628
+ "parameter": parameter_name,
629
+ "instrument": table["telescope_name"][0],
630
+ "site": self.site,
631
+ "version": self.model_version,
632
+ "value": value_string,
633
+ "unit": "m",
634
+ "type": "float64",
635
+ "applicable": True,
636
+ "file": False,
637
+ }
754
638
 
755
- def get_corsika_input_list(self):
639
+ def get_number_of_telescopes(self):
756
640
  """
757
- Get a string with the piece of text to be added to the CORSIKA input file.
641
+ Return the number of telescopes in the list.
758
642
 
759
643
  Returns
760
644
  -------
761
- str
762
- Piece of text to be added to the CORSIKA input file.
763
-
764
- Raises
765
- ------
766
- KeyError
767
- if Missing definition of CORSIKA sphere radius or obs_level.
768
- """
769
-
770
- corsika_list = ""
771
- for tel in self._telescope_list:
772
- pos_x, pos_y, pos_z = tel.get_coordinates("ground")
773
- try:
774
- sphere_radius = self._corsika_telescope["corsika_sphere_radius"][
775
- names.get_telescope_class(tel.name)
776
- ]
777
- except KeyError:
778
- self._logger.error("Missing definition of CORSIKA sphere radius")
779
- raise
780
- try:
781
- pos_z = tel.convert_telescope_altitude_to_corsika_system(
782
- pos_z,
783
- self._corsika_telescope["corsika_obs_level"],
784
- self._get_corsika_sphere_center(tel.name),
785
- )
786
- except KeyError:
787
- self._logger.error("Missing definition of CORSIKA sphere center / obs_level")
788
- raise
789
-
790
- corsika_list += "TELESCOPE"
791
- for pos in [pos_x, pos_y, pos_z]:
792
- corsika_list += f"\t {pos.value:.3f}E2"
793
- corsika_list += f"\t {sphere_radius.value:.3f}E2"
794
- corsika_list += f"\t # {tel.name}\n"
795
-
796
- return corsika_list
797
-
798
- def _print_all(self):
799
- """ "
800
- Print all columns for all coordinate systems.
801
-
645
+ int
646
+ Number of telescopes.
802
647
  """
648
+ return len(self._telescope_list)
803
649
 
804
- print(f"ArrayLayout: {self.name}")
805
- print("ArrayCenter")
806
- print(self._array_center)
807
- print("Telescopes")
808
- for tel in self._telescope_list:
809
- print(tel)
810
-
811
- def _print_compact(self, compact_printing, corsika_z=False):
650
+ def print_telescope_list(self, crs_name):
812
651
  """
813
- Compact printing of list of telescopes.
814
-
652
+ Print list of telescopes.
815
653
 
816
654
  Parameters
817
655
  ----------
818
- compact_printing: str
819
- Compact printout for a single coordinate system. Coordinates in all systems are \
820
- printed, if compact_printing is None.
821
- corsika_z: bool
822
- Print telescope height in CORSIKA coordinates (for CORSIKA system)
656
+ crs_name: str
657
+ Name of coordinate system to be used for export.
823
658
 
824
659
  """
825
-
826
660
  for tel in self._telescope_list:
827
- if corsika_z:
828
- _corsika_obs_level = self._corsika_telescope["corsika_obs_level"]
829
- _corsika_sphere_center = self._get_corsika_sphere_center(tel.name)
830
- else:
831
- _corsika_obs_level = None
832
- _corsika_sphere_center = None
833
-
834
661
  tel.print_compact_format(
835
- crs_name=compact_printing,
662
+ crs_name=crs_name,
836
663
  print_header=(tel == self._telescope_list[0]),
837
- corsika_obs_level=_corsika_obs_level,
838
- corsika_sphere_center=_corsika_sphere_center,
664
+ corsika_observation_level=(
665
+ self._corsika_observation_level if crs_name == "ground" else None
666
+ ),
839
667
  )
840
668
 
841
- def print_telescope_list(self, compact_printing="", corsika_z=False):
842
- """
843
- Print list of telescopes in latest released layout.
844
-
845
- Parameters
846
- ----------
847
- compact_printing: str
848
- Compact printout for a single coordinate system.
849
- corsika_z: bool
850
- Print telescope height in CORSIKA coordinates (for CORSIKA system).
851
- """
852
-
853
- if len(compact_printing) == 0:
854
- self._print_all()
855
- else:
856
- self._print_compact(compact_printing, corsika_z)
857
-
858
669
  def convert_coordinates(self):
859
670
  """Perform all the possible conversions the coordinates of the tel positions."""
860
-
861
671
  self._logger.info("Converting telescope coordinates")
862
672
 
863
673
  crs_wgs84 = self.geo_coordinates.crs_wgs84()
864
674
  crs_local = self.geo_coordinates.crs_local(self._array_center)
865
- crs_utm = self.geo_coordinates.crs_utm(self._epsg)
675
+ crs_utm = self.geo_coordinates.crs_utm(self._reference_position_dict.get("epsg_code", None))
866
676
 
867
677
  for tel in self._telescope_list:
868
678
  tel.convert_all(
@@ -871,35 +681,6 @@ class ArrayLayout:
871
681
  crs_utm=crs_utm,
872
682
  )
873
683
 
874
- @staticmethod
875
- def include_radius_into_telescope_table(telescope_table):
876
- """
877
- Include the radius of the telescopes types into the astropy.table.QTable telescopes_table
878
-
879
- Parameters
880
- ----------
881
- telescope_table: astropy.QTable
882
- Astropy QTable with telescope information.
883
-
884
- Returns
885
- -------
886
- astropy.QTable
887
- Astropy QTable with telescope information updated with the radius.
888
- """
889
-
890
- telescope_table["radius"] = [
891
- u.Quantity(
892
- telescope_table.meta["corsika_sphere_radius"][
893
- names.get_telescope_class(tel_name_now)
894
- ]
895
- )
896
- .to("m")
897
- .value
898
- for tel_name_now in telescope_table["telescope_name"]
899
- ]
900
- telescope_table["radius"] = telescope_table["radius"].quantity * u.m
901
- return telescope_table
902
-
903
684
  def select_assets(self, asset_list=None):
904
685
  """
905
686
  Select a subsets of telescopes / assets from the layout.
@@ -907,7 +688,7 @@ class ArrayLayout:
907
688
  Parameters
908
689
  ----------
909
690
  asset_list: list
910
- List of assets to be selected.
691
+ List of assets to be selected (telescope names or types)
911
692
 
912
693
  Raises
913
694
  ------
@@ -915,13 +696,20 @@ class ArrayLayout:
915
696
  If the asset list is empty.
916
697
 
917
698
  """
918
-
919
699
  _n_telescopes = len(self._telescope_list)
920
700
  try:
921
701
  if len(asset_list) > 0:
922
- self._telescope_list = [
702
+ _telescope_list_from_name = [
923
703
  tel for tel in self._telescope_list if tel.asset_code in asset_list
924
704
  ]
705
+ _telescope_list_from_type = [
706
+ tel
707
+ for tel in self._telescope_list
708
+ if names.get_array_element_type_from_name(tel.asset_code) in asset_list
709
+ ]
710
+ self._telescope_list = list(
711
+ set(_telescope_list_from_name + _telescope_list_from_type)
712
+ )
925
713
  self._logger.info(
926
714
  f"Selected {len(self._telescope_list)} telescopes"
927
715
  f" (from originally {_n_telescopes})"