gammasimtools 0.6.0__py3-none-any.whl → 0.8.1__py3-none-any.whl

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