gammasimtools 0.6.1__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.1.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 +325 -537
  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 -493
  63. simtools/model/mirrors.py +61 -44
  64. simtools/model/model_parameter.py +602 -0
  65. simtools/model/model_utils.py +7 -35
  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 +258 -644
  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.1.dist-info/METADATA +0 -180
  331. gammasimtools-0.6.1.dist-info/RECORD +0 -91
  332. gammasimtools-0.6.1.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 -1480
  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.1.dist-info → gammasimtools-0.8.1.dist-info}/LICENSE +0 -0
  352. {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.1.dist-info}/top_level.txt +0 -0
  353. /simtools/{corsika_simtel → db}/__init__.py +0 -0
@@ -1,5 +1,6 @@
1
1
  """
2
2
  Definition of metadata model for input to and output of simtools.
3
+
3
4
  Follows CTAO top-level data model definition.
4
5
 
5
6
  * data products submitted to SimPipe ('input')
@@ -14,6 +15,8 @@ import jsonschema
14
15
 
15
16
  import simtools.constants
16
17
  import simtools.utils.general as gen
18
+ from simtools.data_model import format_checkers
19
+ from simtools.utils import names
17
20
 
18
21
  _logger = logging.getLogger(__name__)
19
22
 
@@ -35,11 +38,10 @@ def validate_schema(data, schema_file):
35
38
  if validation fails
36
39
 
37
40
  """
38
-
39
41
  schema, schema_file = _load_schema(schema_file)
40
42
 
41
43
  try:
42
- jsonschema.validate(data, schema=schema)
44
+ jsonschema.validate(data, schema=schema, format_checker=format_checkers.format_checker)
43
45
  except jsonschema.exceptions.ValidationError:
44
46
  _logger.error(f"Failed using {schema}")
45
47
  raise
@@ -48,7 +50,8 @@ def validate_schema(data, schema_file):
48
50
 
49
51
  def get_default_metadata_dict(schema_file=None, observatory="CTA"):
50
52
  """
51
- Returns metadata schema with default values.
53
+ Return metadata schema with default values.
54
+
52
55
  Follows the CTA Top-Level Data Model.
53
56
 
54
57
  Parameters
@@ -65,7 +68,6 @@ def get_default_metadata_dict(schema_file=None, observatory="CTA"):
65
68
 
66
69
 
67
70
  """
68
-
69
71
  schema, _ = _load_schema(schema_file)
70
72
  return _fill_defaults(schema["definitions"], observatory)
71
73
 
@@ -88,16 +90,58 @@ def _load_schema(schema_file=None):
88
90
  if schema file is not found
89
91
 
90
92
  """
91
-
92
93
  if schema_file is None:
93
94
  schema_file = files("simtools").joinpath(simtools.constants.METADATA_JSON_SCHEMA)
94
95
 
95
- schema = gen.collect_data_from_file_or_dict(file_name=schema_file, in_dict=None)
96
+ try:
97
+ schema = gen.collect_data_from_file(file_name=schema_file)
98
+ except FileNotFoundError:
99
+ schema_file = files("simtools").joinpath("schemas") / schema_file
100
+ schema = gen.collect_data_from_file(file_name=schema_file)
96
101
  _logger.debug(f"Loading schema from {schema_file}")
102
+ _add_array_elements("InstrumentTypeElement", schema)
97
103
 
98
104
  return schema, schema_file
99
105
 
100
106
 
107
+ def _add_array_elements(key, schema):
108
+ """
109
+ Add list of array elements to schema.
110
+
111
+ This assumes an element [key]['enum'] is a list of elements.
112
+
113
+ Parameters
114
+ ----------
115
+ key: str
116
+ Key in schema dictionary
117
+ schema: dict
118
+ Schema dictionary
119
+
120
+ Returns
121
+ -------
122
+ dict
123
+ Schema dictionary with added array elements.
124
+
125
+ """
126
+ _list_of_array_elements = sorted(names.array_elements().keys())
127
+
128
+ def recursive_search(sub_schema, key):
129
+ if key in sub_schema:
130
+ if "enum" in sub_schema[key] and isinstance(sub_schema[key]["enum"], list):
131
+ sub_schema[key]["enum"] = list(
132
+ set(sub_schema[key]["enum"] + _list_of_array_elements)
133
+ )
134
+ else:
135
+ sub_schema[key]["enum"] = _list_of_array_elements
136
+ else:
137
+ for _, v in sub_schema.items():
138
+ if isinstance(v, dict):
139
+ recursive_search(v, key)
140
+
141
+ recursive_search(schema, key)
142
+ return schema
143
+
144
+
101
145
  def _resolve_references(yaml_data, observatory="CTA"):
102
146
  """
103
147
  Resolve references in yaml data and expand the received dictionary accordingly.
@@ -126,17 +170,23 @@ def _resolve_references(yaml_data, observatory="CTA"):
126
170
  ref_data = ref_data.get(part, {})
127
171
  return ref_data
128
172
 
173
+ def resolve_dict(data):
174
+ if "$ref" in data:
175
+ ref = data["$ref"]
176
+ resolved_data = expand_ref(ref)
177
+ if isinstance(resolved_data, dict) and len(resolved_data) > 1:
178
+ return _resolve_references_recursive(resolved_data)
179
+ return resolved_data
180
+ return {k: _resolve_references_recursive(v) for k, v in data.items()}
181
+
182
+ def resolve_list(data):
183
+ return [_resolve_references_recursive(item) for item in data]
184
+
129
185
  def _resolve_references_recursive(data):
130
186
  if isinstance(data, dict):
131
- if "$ref" in data:
132
- ref = data["$ref"]
133
- resolved_data = expand_ref(ref)
134
- if isinstance(resolved_data, dict) and len(resolved_data) > 1:
135
- return _resolve_references_recursive(resolved_data)
136
- return resolved_data
137
- return {k: _resolve_references_recursive(v) for k, v in data.items()}
187
+ return resolve_dict(data)
138
188
  if isinstance(data, list):
139
- return [_resolve_references_recursive(item) for item in data]
189
+ return resolve_list(data)
140
190
  return data
141
191
 
142
192
  return _resolve_references_recursive(yaml_data)
@@ -157,30 +207,58 @@ def _fill_defaults(schema, observatory="CTA"):
157
207
  -------
158
208
  dict
159
209
  Dictionary with default values.
210
+ """
211
+ defaults = {observatory: {}}
212
+ resolved_schema = _resolve_references(schema[observatory])
213
+ _fill_defaults_recursive(resolved_schema, defaults[observatory])
214
+ return defaults
215
+
160
216
 
217
+ def _fill_defaults_recursive(subschema, current_dict):
161
218
  """
219
+ Recursively fill default values from the subschema into the current dictionary.
162
220
 
163
- defaults = {observatory: {}}
221
+ Parameters
222
+ ----------
223
+ subschema: dict
224
+ Subschema describing part of the input data.
225
+ current_dict: dict
226
+ Current dictionary to fill with default values.
227
+ """
228
+ if "properties" not in subschema:
229
+ _raise_missing_properties_error()
164
230
 
165
- schema = _resolve_references(schema[observatory])
166
-
167
- def _fill_defaults_recursive(subschema, current_dict):
168
- try:
169
- for prop, prop_schema in subschema["properties"].items():
170
- if "default" in prop_schema:
171
- current_dict[prop] = prop_schema["default"]
172
- elif "type" in prop_schema:
173
- if prop_schema["type"] == "object":
174
- current_dict[prop] = {}
175
- _fill_defaults_recursive(prop_schema, current_dict[prop])
176
- elif prop_schema["type"] == "array":
177
- current_dict[prop] = [{}]
178
- if "items" in prop_schema and isinstance(prop_schema["items"], dict):
179
- _fill_defaults_recursive(prop_schema["items"], current_dict[prop][0])
180
- except KeyError:
181
- msg = "Missing 'properties' key in schema."
182
- _logger.error(msg)
183
- raise
184
-
185
- _fill_defaults_recursive(schema, defaults[observatory])
186
- return defaults
231
+ for prop, prop_schema in subschema["properties"].items():
232
+ _process_property(prop, prop_schema, current_dict)
233
+
234
+
235
+ def _process_property(prop, prop_schema, current_dict):
236
+ """
237
+ Process each property and fill the default values accordingly.
238
+
239
+ Parameters
240
+ ----------
241
+ prop: str
242
+ Property name.
243
+ prop_schema: dict
244
+ Schema of the property.
245
+ current_dict: dict
246
+ Current dictionary to fill with default values.
247
+ """
248
+ if "default" in prop_schema:
249
+ current_dict[prop] = prop_schema["default"]
250
+ elif "type" in prop_schema:
251
+ if prop_schema["type"] == "object":
252
+ current_dict[prop] = {}
253
+ _fill_defaults_recursive(prop_schema, current_dict[prop])
254
+ elif prop_schema["type"] == "array":
255
+ current_dict[prop] = [{}]
256
+ if "items" in prop_schema and isinstance(prop_schema["items"], dict):
257
+ _fill_defaults_recursive(prop_schema["items"], current_dict[prop][0])
258
+
259
+
260
+ def _raise_missing_properties_error():
261
+ """Raise an error when the 'properties' key is missing in the schema."""
262
+ msg = "Missing 'properties' key in schema."
263
+ _logger.error(msg)
264
+ raise KeyError(msg)
@@ -1,16 +1,41 @@
1
+ """Model data writer module."""
2
+
3
+ import json
1
4
  import logging
2
5
  from pathlib import Path
3
6
 
4
- import astropy
7
+ import astropy.units as u
8
+ import numpy as np
5
9
  import yaml
10
+ from astropy.io.registry.base import IORegistryError
6
11
 
7
12
  import simtools.utils.general as gen
13
+ from simtools.constants import MODEL_PARAMETER_SCHEMA_PATH
8
14
  from simtools.data_model import validate_data
15
+ from simtools.data_model.metadata_collector import MetadataCollector
9
16
  from simtools.io_operations import io_handler
17
+ from simtools.utils import names, value_conversion
10
18
 
11
19
  __all__ = ["ModelDataWriter"]
12
20
 
13
21
 
22
+ class JsonNumpyEncoder(json.JSONEncoder):
23
+ """Convert numpy to python types as accepted by json.dump."""
24
+
25
+ def default(self, o):
26
+ if isinstance(o, np.floating):
27
+ return float(o)
28
+ if isinstance(o, np.integer):
29
+ return int(o)
30
+ if isinstance(o, np.ndarray):
31
+ return o.tolist()
32
+ if isinstance(o, u.core.CompositeUnit | u.core.IrreducibleUnit | u.core.Unit):
33
+ return str(o) if o != u.dimensionless_unscaled else None
34
+ if np.issubdtype(type(o), np.bool_):
35
+ return bool(o)
36
+ return super().default(o)
37
+
38
+
14
39
  class ModelDataWriter:
15
40
  """
16
41
  Writer for simulation model data and metadata.
@@ -23,24 +48,36 @@ class ModelDataWriter:
23
48
  Format of output file.
24
49
  args_dict: Dictionary
25
50
  Dictionary with configuration parameters.
26
- """
51
+ output_path: str or Path
52
+ Path to output file.
53
+ use_plain_output_path: bool
54
+ Use plain output path.
55
+ args_dict: dict
56
+ Dictionary with configuration parameters.
27
57
 
28
- def __init__(self, product_data_file=None, product_data_format=None, args_dict=None):
29
- """
30
- Initialize model data writer.
31
- """
58
+ """
32
59
 
60
+ def __init__(
61
+ self,
62
+ product_data_file=None,
63
+ product_data_format=None,
64
+ output_path=None,
65
+ use_plain_output_path=True,
66
+ args_dict=None,
67
+ ):
68
+ """Initialize model data writer."""
33
69
  self._logger = logging.getLogger(__name__)
34
70
  self.io_handler = io_handler.IOHandler()
71
+ self.schema_dict = {}
35
72
  if args_dict is not None:
73
+ output_path = args_dict.get("output_path", output_path)
74
+ use_plain_output_path = args_dict.get("use_plain_output_path", use_plain_output_path)
75
+ if output_path is not None:
36
76
  self.io_handler.set_paths(
37
- output_path=args_dict.get("output_path", None),
38
- use_plain_output_path=args_dict.get("use_plain_output_path", False),
77
+ output_path=output_path, use_plain_output_path=use_plain_output_path
39
78
  )
40
79
  try:
41
- self.product_data_file = self.io_handler.get_output_file(
42
- file_name=product_data_file, dir_type="simtools-result"
43
- )
80
+ self.product_data_file = self.io_handler.get_output_file(file_name=product_data_file)
44
81
  except TypeError:
45
82
  self.product_data_file = None
46
83
  self.product_data_format = self._astropy_data_format(product_data_format)
@@ -66,7 +103,6 @@ class ModelDataWriter:
66
103
  Schema file used in validation of output data.
67
104
 
68
105
  """
69
-
70
106
  writer = ModelDataWriter(
71
107
  product_data_file=(
72
108
  args_dict.get("output_file", None) if output_file is None else output_file
@@ -76,34 +112,249 @@ class ModelDataWriter:
76
112
  )
77
113
  if validate_schema_file is not None and not args_dict.get("skip_output_validation", True):
78
114
  product_data = writer.validate_and_transform(
79
- product_data=product_data,
115
+ product_data_table=product_data,
80
116
  validate_schema_file=validate_schema_file,
81
117
  )
82
118
  writer.write(metadata=metadata, product_data=product_data)
83
119
 
84
- def validate_and_transform(self, product_data=None, validate_schema_file=None):
120
+ @staticmethod
121
+ def dump_model_parameter(
122
+ parameter_name,
123
+ value,
124
+ instrument,
125
+ model_version,
126
+ output_file,
127
+ output_path=None,
128
+ use_plain_output_path=False,
129
+ metadata_input_dict=None,
130
+ ):
131
+ """
132
+ Generate DB-style model parameter dict and write it to json file.
133
+
134
+ Parameters
135
+ ----------
136
+ parameter_name: str
137
+ Name of the parameter.
138
+ value: any
139
+ Value of the parameter.
140
+ instrument: str
141
+ Name of the instrument.
142
+ model_version: str
143
+ Version of the model.
144
+ output_file: str
145
+ Name of output file.
146
+ output_path: str or Path
147
+ Path to output file.
148
+ use_plain_output_path: bool
149
+ Use plain output path.
150
+ metadata_input_dict: dict
151
+ Input to metadata collector.
152
+
153
+ Returns
154
+ -------
155
+ dict
156
+ Validated parameter dictionary.
157
+ """
158
+ writer = ModelDataWriter(
159
+ product_data_file=output_file,
160
+ product_data_format="json",
161
+ args_dict=None,
162
+ output_path=output_path,
163
+ use_plain_output_path=use_plain_output_path,
164
+ )
165
+ _json_dict = writer.get_validated_parameter_dict(
166
+ parameter_name, value, instrument, model_version
167
+ )
168
+ writer.write_dict_to_model_parameter_json(output_file, _json_dict)
169
+ if metadata_input_dict is not None:
170
+ metadata_input_dict["output_file"] = output_file
171
+ metadata_input_dict["output_file_format"] = Path(output_file).suffix.lstrip(".")
172
+ writer.write_metadata_to_yml(
173
+ metadata=MetadataCollector(args_dict=metadata_input_dict).top_level_meta,
174
+ yml_file=output_path / f"{Path(output_file).stem}",
175
+ )
176
+ return _json_dict
177
+
178
+ def get_validated_parameter_dict(self, parameter_name, value, instrument, model_version):
179
+ """
180
+ Get validated parameter dictionary.
181
+
182
+ Parameters
183
+ ----------
184
+ parameter_name: str
185
+ Name of the parameter.
186
+ value: any
187
+ Value of the parameter.
188
+ instrument: str
189
+ Name of the instrument.
190
+ model_version: str
191
+ Version of the model.
192
+
193
+ Returns
194
+ -------
195
+ dict
196
+ Validated parameter dictionary.
197
+ """
198
+ self._logger.debug(f"Getting validated parameter dictionary for {instrument}")
199
+ schema_file = self._read_model_parameter_schema(parameter_name)
200
+
201
+ try: # e.g. instrument is 'North"
202
+ site = names.validate_site_name(instrument)
203
+ except ValueError: # e.g. instrument is 'LSTN-01'
204
+ site = names.get_site_from_array_element_name(instrument)
205
+
206
+ try:
207
+ applicable = self._get_parameter_applicability(instrument)
208
+ except ValueError:
209
+ applicable = True # Default to True (expect that this field goes in future)
210
+
211
+ value, unit = value_conversion.split_value_and_unit(value)
212
+
213
+ data_dict = {
214
+ "parameter": parameter_name,
215
+ "instrument": instrument,
216
+ "site": site,
217
+ "version": model_version,
218
+ "value": value,
219
+ "unit": unit,
220
+ "type": self._get_parameter_type(),
221
+ "applicable": applicable,
222
+ "file": self._parameter_is_a_file(),
223
+ }
224
+ return self.validate_and_transform(
225
+ product_data_dict=data_dict,
226
+ validate_schema_file=schema_file,
227
+ is_model_parameter=True,
228
+ )
229
+
230
+ def _read_model_parameter_schema(self, parameter_name):
231
+ """
232
+ Read model parameter schema.
233
+
234
+ Parameters
235
+ ----------
236
+ parameter_name: str
237
+ Name of the parameter.
238
+ """
239
+ schema_file = MODEL_PARAMETER_SCHEMA_PATH / f"{parameter_name}.schema.yml"
240
+ try:
241
+ self.schema_dict = gen.collect_data_from_file(file_name=schema_file)
242
+ except FileNotFoundError as exc:
243
+ raise FileNotFoundError(f"Schema file not found: {schema_file}") from exc
244
+ return schema_file
245
+
246
+ def _get_parameter_type(self):
247
+ """
248
+ Return parameter type from schema.
249
+
250
+ Returns
251
+ -------
252
+ str
253
+ Parameter type
254
+ """
255
+ _parameter_type = []
256
+ for data in self.schema_dict["data"]:
257
+ _parameter_type.append(data["type"])
258
+ return _parameter_type if len(_parameter_type) > 1 else _parameter_type[0]
259
+
260
+ def _parameter_is_a_file(self):
261
+ """
262
+ Check if parameter is a file.
263
+
264
+ Returns
265
+ -------
266
+ bool
267
+ True if parameter is a file.
268
+
269
+ """
270
+ try:
271
+ return self.schema_dict["data"][0]["type"] == "file"
272
+ except (KeyError, IndexError):
273
+ pass
274
+ return False
275
+
276
+ def _get_parameter_applicability(self, telescope_name):
277
+ """
278
+ Check if a parameter is applicable for a given telescope using schema files.
279
+
280
+ First check for exact telescope name (e.g., LSTN-01), if not listed in the schema
281
+ use telescope type (LSTN).
282
+
283
+ Parameters
284
+ ----------
285
+ telescope_name: str
286
+ Telescope name (e.g., LSTN-01)
287
+
288
+ Returns
289
+ -------
290
+ bool
291
+ True if parameter is applicable to telescope.
292
+
293
+ """
294
+ try:
295
+ if telescope_name in self.schema_dict["instrument"]["type"]:
296
+ return True
297
+ except KeyError as exc:
298
+ self._logger.error("Schema file does not contain 'instrument:type' key.")
299
+ raise exc
300
+
301
+ return (
302
+ names.get_array_element_type_from_name(telescope_name)
303
+ in self.schema_dict["instrument"]["type"]
304
+ )
305
+
306
+ def _get_unit_from_schema(self):
307
+ """
308
+ Return unit(s) from schema dict.
309
+
310
+ Returns
311
+ -------
312
+ str or list
313
+ Parameter unit(s)
314
+ """
315
+ try:
316
+ unit_list = []
317
+ for data in self.schema_dict["data"]:
318
+ unit_list.append(data["unit"] if data["unit"] != "dimensionless" else None)
319
+ return unit_list if len(unit_list) > 1 else unit_list[0]
320
+ except (KeyError, IndexError):
321
+ pass
322
+ return None
323
+
324
+ def validate_and_transform(
325
+ self,
326
+ product_data_table=None,
327
+ product_data_dict=None,
328
+ validate_schema_file=None,
329
+ is_model_parameter=False,
330
+ ):
85
331
  """
86
332
  Validate product data using jsonschema given in metadata.
333
+
87
334
  If necessary, transform product data to match schema.
88
335
 
89
336
  Parameters
90
337
  ----------
91
- product_data: astropy Table
92
- Model data to be validated
338
+ product_data_table: astropy Table
339
+ Model data to be validated.
340
+ product_data_dict: dict
341
+ Model data to be validated.
93
342
  validate_schema_file: str
94
343
  Schema file used in validation of output data.
95
-
344
+ is_model_parameter: bool
345
+ True if data describes a model parameter.
96
346
  """
97
-
98
347
  _validator = validate_data.DataValidator(
99
348
  schema_file=validate_schema_file,
100
- data_table=product_data,
349
+ data_table=product_data_table,
350
+ data_dict=product_data_dict,
351
+ check_exact_data_type=False,
101
352
  )
102
- return _validator.validate_and_transform()
353
+ return _validator.validate_and_transform(is_model_parameter)
103
354
 
104
355
  def write(self, product_data=None, metadata=None):
105
356
  """
106
- Write model data and metadata
357
+ Write model data and metadata.
107
358
 
108
359
  Parameters
109
360
  ----------
@@ -118,22 +369,82 @@ class ModelDataWriter:
118
369
  if data writing was not successful.
119
370
 
120
371
  """
121
-
122
372
  if product_data is None:
123
373
  return
124
374
 
125
375
  if metadata is not None:
126
376
  product_data.meta.update(gen.change_dict_keys_case(metadata, False))
127
377
 
378
+ self._logger.info(f"Writing data to {self.product_data_file}")
379
+ if isinstance(product_data, dict) and Path(self.product_data_file).suffix == ".json":
380
+ self.write_dict_to_model_parameter_json(self.product_data_file, product_data)
381
+ return
128
382
  try:
129
- self._logger.info(f"Writing data to {self.product_data_file}")
130
383
  product_data.write(
131
384
  self.product_data_file, format=self.product_data_format, overwrite=True
132
385
  )
133
- except astropy.io.registry.base.IORegistryError:
386
+ except IORegistryError:
134
387
  self._logger.error(f"Error writing model data to {self.product_data_file}.")
135
388
  raise
136
389
 
390
+ def write_dict_to_model_parameter_json(self, file_name, data_dict):
391
+ """
392
+ Write dictionary to model-parameter-style json file.
393
+
394
+ Parameters
395
+ ----------
396
+ file_name : str
397
+ Name of output file.
398
+ data_dict : dict
399
+ Data dictionary.
400
+
401
+ Raises
402
+ ------
403
+ FileNotFoundError
404
+ if data writing was not successful.
405
+ """
406
+ data_dict = ModelDataWriter.prepare_data_dict_for_writing(data_dict)
407
+ try:
408
+ self._logger.info(f"Writing data to {self.io_handler.get_output_file(file_name)}")
409
+ with open(self.io_handler.get_output_file(file_name), "w", encoding="UTF-8") as file:
410
+ json.dump(data_dict, file, indent=4, sort_keys=False, cls=JsonNumpyEncoder)
411
+ file.write("\n")
412
+ except FileNotFoundError as exc:
413
+ raise FileNotFoundError(
414
+ f"Error writing model data to {self.io_handler.get_output_file(file_name)}"
415
+ ) from exc
416
+
417
+ @staticmethod
418
+ def prepare_data_dict_for_writing(data_dict):
419
+ """
420
+ Prepare data dictionary for writing to json file.
421
+
422
+ Ensure sim_telarray style lists as strings.
423
+ Replace "None" with "null" for unit field.
424
+
425
+ Parameters
426
+ ----------
427
+ data_dict: dict
428
+ Dictionary with lists.
429
+
430
+ Returns
431
+ -------
432
+ dict
433
+ Dictionary with lists converted to strings.
434
+
435
+ """
436
+ try:
437
+ data_dict["value"] = gen.convert_list_to_string(data_dict["value"])
438
+ data_dict["unit"] = gen.convert_list_to_string(data_dict["unit"], comma_separated=True)
439
+ data_dict["type"] = gen.convert_list_to_string(
440
+ data_dict["type"], comma_separated=True, collapse_list=True
441
+ )
442
+ if isinstance(data_dict["unit"], str):
443
+ data_dict["unit"] = data_dict["unit"].replace("None", "null")
444
+ except KeyError:
445
+ pass
446
+ return data_dict
447
+
137
448
  def write_metadata_to_yml(self, metadata, yml_file=None, keys_lower_case=False):
138
449
  """
139
450
  Write model metadata file (yaml file format).
@@ -159,7 +470,6 @@ class ModelDataWriter:
159
470
  TypeError
160
471
  If yml_file is not defined.
161
472
  """
162
-
163
473
  try:
164
474
  yml_file = Path(yml_file or self.product_data_file).with_suffix(".metadata.yml")
165
475
  with open(yml_file, "w", encoding="UTF-8") as file:
@@ -191,7 +501,6 @@ class ModelDataWriter:
191
501
  format identifier
192
502
 
193
503
  """
194
-
195
504
  if product_data_format == "ecsv":
196
505
  product_data_format = "ascii.ecsv"
197
506
  return product_data_format