gammasimtools 0.18.0__py3-none-any.whl → 0.20.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/METADATA +24 -69
- gammasimtools-0.20.0.dist-info/RECORD +395 -0
- {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/entry_points.txt +11 -4
- {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/licenses/LICENSE +1 -1
- simtools/_version.py +16 -3
- simtools/applications/calculate_incident_angles.py +182 -0
- simtools/applications/convert_all_model_parameters_from_simtel.py +4 -3
- simtools/applications/convert_geo_coordinates_of_array_elements.py +3 -3
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +17 -14
- simtools/applications/db_add_value_from_json_to_db.py +8 -10
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +8 -13
- simtools/applications/db_generate_compound_indexes.py +65 -0
- simtools/applications/db_get_file_from_db.py +12 -24
- simtools/applications/db_get_parameter_from_db.py +4 -4
- simtools/applications/db_inspect_databases.py +20 -10
- simtools/applications/derive_mirror_rnda.py +17 -11
- simtools/applications/derive_psf_parameters.py +59 -309
- simtools/applications/derive_trigger_rates.py +91 -0
- simtools/applications/docs_produce_array_element_report.py +1 -1
- simtools/applications/docs_produce_calibration_reports.py +1 -1
- simtools/applications/docs_produce_model_parameter_reports.py +1 -1
- simtools/applications/docs_produce_simulation_configuration_report.py +1 -1
- simtools/applications/generate_corsika_histograms.py +1 -1
- simtools/applications/generate_default_metadata.py +8 -24
- simtools/applications/generate_simtel_event_data.py +11 -11
- simtools/applications/maintain_simulation_model_add_production_table.py +71 -0
- simtools/applications/maintain_simulation_model_compare_productions.py +98 -0
- simtools/applications/{verify_simulation_model_production_tables.py → maintain_simulation_model_verify_production_tables.py} +9 -1
- simtools/applications/merge_tables.py +2 -2
- simtools/applications/plot_array_layout.py +3 -3
- simtools/applications/plot_simtel_events.py +421 -0
- simtools/applications/plot_tabular_data.py +9 -2
- simtools/applications/plot_tabular_data_for_model_parameter.py +2 -1
- simtools/applications/print_version.py +8 -9
- simtools/applications/production_derive_corsika_limits.py +6 -7
- simtools/applications/production_derive_statistics.py +1 -1
- simtools/applications/production_generate_grid.py +2 -2
- simtools/applications/production_merge_corsika_limits.py +214 -0
- simtools/applications/run_application.py +47 -113
- simtools/applications/simulate_calibration_events.py +166 -0
- simtools/applications/simulate_flasher.py +141 -0
- simtools/applications/{simulate_light_emission.py → simulate_illuminator.py} +35 -99
- simtools/applications/simulate_prod.py +6 -24
- simtools/applications/simulate_prod_htcondor_generator.py +7 -0
- simtools/applications/submit_array_layouts.py +2 -1
- simtools/applications/submit_model_parameter_from_external.py +1 -1
- simtools/applications/validate_camera_efficiency.py +30 -12
- simtools/applications/validate_camera_fov.py +1 -1
- simtools/applications/validate_cumulative_psf.py +1 -1
- simtools/applications/validate_file_using_schema.py +9 -5
- simtools/applications/validate_optics.py +1 -1
- simtools/camera/camera_efficiency.py +61 -45
- simtools/camera/single_photon_electron_spectrum.py +1 -1
- simtools/configuration/commandline_parser.py +46 -11
- simtools/configuration/configurator.py +4 -4
- simtools/corsika/corsika_config.py +45 -25
- simtools/corsika/corsika_histograms.py +6 -5
- simtools/data_model/data_reader.py +2 -3
- simtools/data_model/metadata_collector.py +32 -36
- simtools/data_model/metadata_model.py +15 -12
- simtools/data_model/model_data_writer.py +13 -32
- simtools/data_model/schema.py +74 -24
- simtools/data_model/validate_data.py +42 -12
- simtools/db/db_handler.py +125 -62
- simtools/db/db_model_upload.py +14 -19
- simtools/dependencies.py +98 -30
- simtools/io/ascii_handler.py +279 -0
- simtools/{io_operations → io}/io_handler.py +25 -3
- simtools/job_execution/htcondor_script_generator.py +15 -4
- simtools/layout/array_layout.py +1 -1
- simtools/layout/array_layout_utils.py +51 -12
- simtools/model/array_model.py +41 -5
- simtools/model/flasher_model.py +106 -0
- simtools/model/model_parameter.py +4 -4
- simtools/model/model_repository.py +197 -2
- simtools/model/site_model.py +25 -0
- simtools/model/telescope_model.py +3 -1
- simtools/production_configuration/derive_corsika_limits.py +336 -427
- simtools/production_configuration/derive_production_statistics_handler.py +7 -6
- simtools/production_configuration/generate_production_grid.py +9 -11
- simtools/production_configuration/merge_corsika_limits.py +528 -0
- simtools/ray_tracing/incident_angles.py +706 -0
- simtools/ray_tracing/mirror_panel_psf.py +1 -0
- simtools/ray_tracing/psf_parameter_optimisation.py +792 -0
- simtools/ray_tracing/ray_tracing.py +6 -2
- simtools/reporting/docs_read_parameters.py +150 -62
- simtools/runners/corsika_runner.py +1 -1
- simtools/runners/corsika_simtel_runner.py +14 -5
- simtools/runners/runner_services.py +10 -5
- simtools/runners/simtools_runner.py +267 -0
- simtools/schemas/application_workflow.metaschema.yml +101 -68
- simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +1 -1
- simtools/schemas/input/single_pe_spectrum.schema.yml +1 -1
- simtools/schemas/metadata.metaschema.yml +577 -3
- simtools/schemas/model_parameter.metaschema.yml +6 -6
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +4 -4
- simtools/schemas/model_parameters/adjust_gain.schema.yml +1 -1
- simtools/schemas/model_parameters/altitude.schema.yml +1 -1
- simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
- simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +1 -1
- simtools/schemas/model_parameters/array_element_position_ground.schema.yml +1 -1
- simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
- simtools/schemas/model_parameters/array_layouts.schema.yml +1 -1
- simtools/schemas/model_parameters/array_triggers.schema.yml +1 -1
- simtools/schemas/model_parameters/array_window.schema.yml +1 -1
- simtools/schemas/model_parameters/asum_clipping.schema.yml +1 -1
- simtools/schemas/model_parameters/asum_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
- simtools/schemas/model_parameters/asum_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/atmospheric_profile.schema.yml +1 -1
- simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +1 -1
- simtools/schemas/model_parameters/axes_offsets.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_body_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_body_shape.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_config_rotate.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_depth.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_filter.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_pixels.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_transmission.schema.yml +1 -1
- simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
- simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_observation_level.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +3 -3
- simtools/schemas/model_parameters/dark_events.schema.yml +1 -1
- simtools/schemas/model_parameters/default_trigger.schema.yml +1 -1
- simtools/schemas/model_parameters/design_model.schema.yml +1 -1
- simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +1 -1
- simtools/schemas/model_parameters/disc_bins.schema.yml +1 -1
- simtools/schemas/model_parameters/disc_start.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/dish_shape_length.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_pedsub.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_prescale.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_presum_max.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +2 -2
- simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +1 -1
- simtools/schemas/model_parameters/effective_focal_length.schema.yml +1 -1
- simtools/schemas/model_parameters/epsg_code.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_bins.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_long_event_threshold.schema.yml +35 -0
- simtools/schemas/model_parameters/fadc_long_sum_bins.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_long_sum_offset.schema.yml +38 -0
- simtools/schemas/model_parameters/fadc_max_signal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_max_sum.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_mhz.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_noise.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +1 -1
- simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
- simtools/schemas/model_parameters/flatfielding.schema.yml +1 -1
- simtools/schemas/model_parameters/focal_length.schema.yml +1 -1
- simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +1 -1
- simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +1 -1
- simtools/schemas/model_parameters/focus_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/gain_variation.schema.yml +1 -1
- simtools/schemas/model_parameters/geomag_horizontal.schema.yml +1 -1
- simtools/schemas/model_parameters/geomag_rotation.schema.yml +1 -1
- simtools/schemas/model_parameters/geomag_vertical.schema.yml +1 -1
- simtools/schemas/model_parameters/hg_lg_variation.schema.yml +1 -1
- simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
- simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_events.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_external_trigger.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_var_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_wavelength.schema.yml +1 -1
- simtools/schemas/model_parameters/led_events.schema.yml +1 -1
- simtools/schemas/model_parameters/led_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/led_pulse_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +1 -1
- simtools/schemas/model_parameters/led_var_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
- simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +50 -1
- simtools/schemas/model_parameters/min_photoelectrons.schema.yml +1 -1
- simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_class.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_focal_length.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +1 -1
- simtools/schemas/model_parameters/multiplicity_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_offaxis.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +2 -2
- simtools/schemas/model_parameters/nsb_reference_value.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_sky_map.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_spectrum.schema.yml +23 -30
- simtools/schemas/model_parameters/num_gains.schema.yml +1 -1
- simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +1 -1
- simtools/schemas/model_parameters/optics_properties.schema.yml +1 -1
- simtools/schemas/model_parameters/parabolic_dish.schema.yml +1 -1
- simtools/schemas/model_parameters/pedestal_events.schema.yml +1 -1
- simtools/schemas/model_parameters/photon_delay.schema.yml +1 -1
- simtools/schemas/model_parameters/photons_per_run.schema.yml +1 -1
- simtools/schemas/model_parameters/pixel_cells.schema.yml +1 -1
- simtools/schemas/model_parameters/pixels_parallel.schema.yml +1 -1
- simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_average_gain.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_gain_index.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_transit_time.schema.yml +1 -1
- simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +11 -1
- simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
- simtools/schemas/model_parameters/qe_variation.schema.yml +1 -1
- simtools/schemas/model_parameters/quantum_efficiency.schema.yml +1 -1
- simtools/schemas/model_parameters/random_focal_length.schema.yml +1 -1
- simtools/schemas/model_parameters/random_generator.schema.yml +1 -1
- simtools/schemas/model_parameters/random_mono_probability.schema.yml +1 -1
- simtools/schemas/model_parameters/reference_point_altitude.schema.yml +1 -1
- simtools/schemas/model_parameters/reference_point_latitude.schema.yml +1 -1
- simtools/schemas/model_parameters/reference_point_longitude.schema.yml +1 -1
- simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +1 -1
- simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +1 -1
- simtools/schemas/model_parameters/sampled_output.schema.yml +1 -1
- simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +11 -1
- simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +11 -1
- simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +1 -1
- simtools/schemas/model_parameters/stars.schema.yml +2 -2
- simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
- simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_axis_height.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_random_angle.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_random_error.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +1 -1
- simtools/schemas/model_parameters/telescope_transmission.schema.yml +1 -1
- simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +1 -1
- simtools/schemas/model_parameters/teltrig_min_time.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_error.schema.yml +1 -1
- simtools/schemas/model_parameters/transit_time_jitter.schema.yml +1 -1
- simtools/schemas/model_parameters/trigger_current_limit.schema.yml +1 -1
- simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +1 -1
- simtools/schemas/model_parameters/trigger_pixels.schema.yml +1 -1
- simtools/schemas/plot_configuration.metaschema.yml +5 -2
- simtools/schemas/production_configuration_metrics.schema.yml +12 -2
- simtools/schemas/production_tables.schema.yml +7 -2
- simtools/simtel/simtel_config_reader.py +2 -2
- simtools/simtel/simtel_config_writer.py +33 -23
- simtools/simtel/simtel_io_event_histograms.py +483 -0
- simtools/simtel/simtel_io_event_reader.py +65 -43
- simtools/simtel/simtel_io_event_writer.py +40 -20
- simtools/simtel/simtel_io_metadata.py +1 -1
- simtools/simtel/simtel_table_reader.py +95 -13
- simtools/simtel/simulator_array.py +138 -10
- simtools/simtel/simulator_camera_efficiency.py +32 -23
- simtools/simtel/simulator_light_emission.py +437 -271
- simtools/simtel/simulator_ray_tracing.py +1 -1
- simtools/simulator.py +105 -147
- simtools/telescope_trigger_rates.py +119 -0
- simtools/testing/configuration.py +24 -26
- simtools/testing/helpers.py +2 -2
- simtools/testing/log_inspector.py +52 -0
- simtools/testing/validate_output.py +87 -37
- simtools/utils/general.py +125 -255
- simtools/utils/geometry.py +56 -0
- simtools/utils/names.py +1 -1
- simtools/visualization/legend_handlers.py +180 -264
- simtools/visualization/plot_array_layout.py +20 -8
- simtools/visualization/plot_incident_angles.py +431 -0
- simtools/visualization/plot_pixels.py +1 -1
- simtools/visualization/plot_simtel_event_histograms.py +376 -0
- simtools/visualization/plot_simtel_events.py +816 -0
- simtools/visualization/plot_tables.py +133 -37
- simtools/visualization/visualize.py +1 -100
- gammasimtools-0.18.0.dist-info/RECORD +0 -376
- simtools/applications/calculate_trigger_rate.py +0 -187
- simtools/applications/generate_sim_telarray_histograms.py +0 -196
- simtools/production_configuration/derive_corsika_limits_grid.py +0 -232
- simtools/simtel/simtel_io_histogram.py +0 -621
- simtools/simtel/simtel_io_histograms.py +0 -552
- {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.18.0.dist-info → gammasimtools-0.20.0.dist-info}/top_level.txt +0 -0
- /simtools/{io_operations → io}/hdf5_handler.py +0 -0
- /simtools/{io_operations → io}/legacy_data_handler.py +0 -0
- /simtools/{io_operations/io_table_handler.py → io/table_handler.py} +0 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
"""Histograms for shower and triggered events."""
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
import astropy.units as u
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from simtools.simtel.simtel_io_event_reader import SimtelIOEventDataReader
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SimtelIOEventHistograms:
|
|
13
|
+
"""
|
|
14
|
+
Generate and fill histograms for shower and triggered events.
|
|
15
|
+
|
|
16
|
+
Event data is read from the reduced MC event data file.
|
|
17
|
+
Calculate cumulative and relative (efficiency) distributions.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
event_data_file : str
|
|
22
|
+
Path to the event-data file.
|
|
23
|
+
array_name : str, optional
|
|
24
|
+
Name of the telescope array configuration (default is None).
|
|
25
|
+
telescope_list : list, optional
|
|
26
|
+
List of telescope IDs to filter the events (default is None).
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, event_data_file, array_name=None, telescope_list=None):
|
|
30
|
+
"""Initialize."""
|
|
31
|
+
self._logger = logging.getLogger(__name__)
|
|
32
|
+
self.event_data_file = event_data_file
|
|
33
|
+
self.array_name = array_name
|
|
34
|
+
|
|
35
|
+
self.histograms = {}
|
|
36
|
+
self.file_info = {}
|
|
37
|
+
|
|
38
|
+
self.reader = SimtelIOEventDataReader(event_data_file, telescope_list=telescope_list)
|
|
39
|
+
|
|
40
|
+
def fill(self):
|
|
41
|
+
"""
|
|
42
|
+
Fill histograms with event data.
|
|
43
|
+
|
|
44
|
+
Involves looping over all event data, and therefore is the slowest part of the
|
|
45
|
+
histogram module. Adds the histograms to the histogram dictionary.
|
|
46
|
+
|
|
47
|
+
Assume that all event data files are generated with similar configurations
|
|
48
|
+
(self.file_info contains the file info of the last file).
|
|
49
|
+
"""
|
|
50
|
+
for data_set in self.reader.data_sets:
|
|
51
|
+
self._logger.info(f"Reading event data from {self.event_data_file} for {data_set}")
|
|
52
|
+
_file_info_table, shower_data, event_data, triggered_data = self.reader.read_event_data(
|
|
53
|
+
self.event_data_file, table_name_map=data_set
|
|
54
|
+
)
|
|
55
|
+
_file_info_table = self.reader.get_reduced_simulation_file_info(_file_info_table)
|
|
56
|
+
self.file_info = {
|
|
57
|
+
"energy_min": _file_info_table["energy_min"].to("TeV"),
|
|
58
|
+
"core_scatter_max": _file_info_table["core_scatter_max"].to("m"),
|
|
59
|
+
"viewcone_max": _file_info_table["viewcone_max"].to("deg"),
|
|
60
|
+
"solid_angle": _file_info_table["solid_angle"].to("sr"),
|
|
61
|
+
"scatter_area": _file_info_table["scatter_area"].to("cm2"),
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
self.histograms = self._define_histograms(event_data, triggered_data, shower_data)
|
|
65
|
+
|
|
66
|
+
for name, data in self.histograms.items():
|
|
67
|
+
self._logger.debug(f"Filling histogram {name}")
|
|
68
|
+
self._fill_histogram_and_bin_edges(data)
|
|
69
|
+
|
|
70
|
+
self.print_summary()
|
|
71
|
+
|
|
72
|
+
self.calculate_efficiency_data()
|
|
73
|
+
self.calculate_cumulative_data()
|
|
74
|
+
|
|
75
|
+
def _define_histograms(self, event_data, triggered_data, shower_data):
|
|
76
|
+
"""
|
|
77
|
+
Define histograms including event data, binning, naming, and labels.
|
|
78
|
+
|
|
79
|
+
All histograms are defined for simulated and triggered events (note
|
|
80
|
+
the subtlety of triggered events being read from event_data and triggered_data).
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
event_data : EventData
|
|
85
|
+
The event data to use for filling the histograms.
|
|
86
|
+
triggered_data : TriggeredData
|
|
87
|
+
The triggered data to use for filling the histograms.
|
|
88
|
+
shower_data : ShowerData
|
|
89
|
+
The shower data to use for filling the histograms.
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
dict
|
|
94
|
+
Dictionary with histogram definitions.
|
|
95
|
+
"""
|
|
96
|
+
xy_bins = np.linspace(
|
|
97
|
+
-1.0 * self.core_distance_bins.max(),
|
|
98
|
+
self.core_distance_bins.max(),
|
|
99
|
+
len(self.core_distance_bins),
|
|
100
|
+
)
|
|
101
|
+
hists = {}
|
|
102
|
+
|
|
103
|
+
energy_axis_title = "Energy (TeV)"
|
|
104
|
+
event_count_axis_title = "Event Count"
|
|
105
|
+
|
|
106
|
+
definitions = {
|
|
107
|
+
"energy": {
|
|
108
|
+
"event_data_column": "simulated_energy",
|
|
109
|
+
"event_data": event_data,
|
|
110
|
+
"bin_edges": self.energy_bins,
|
|
111
|
+
"axis_titles": [energy_axis_title, event_count_axis_title],
|
|
112
|
+
"plot_scales": {"x": "log", "y": "log"},
|
|
113
|
+
},
|
|
114
|
+
"core_distance": {
|
|
115
|
+
"event_data_column": "core_distance_shower",
|
|
116
|
+
"event_data": event_data,
|
|
117
|
+
"bin_edges": self.core_distance_bins,
|
|
118
|
+
"axis_titles": ["Core Distance (m)", event_count_axis_title],
|
|
119
|
+
},
|
|
120
|
+
"angular_distance": {
|
|
121
|
+
"event_data_column": "angular_distance",
|
|
122
|
+
"event_data": triggered_data,
|
|
123
|
+
"bin_edges": self.view_cone_bins,
|
|
124
|
+
"axis_titles": ["Angular Distance (deg)", event_count_axis_title],
|
|
125
|
+
},
|
|
126
|
+
"x_core_shower_vs_y_core_shower": {
|
|
127
|
+
"event_data_column": ("x_core_shower", "y_core_shower"),
|
|
128
|
+
"event_data": (event_data, event_data),
|
|
129
|
+
"bin_edges": (xy_bins, xy_bins),
|
|
130
|
+
"is_1d": False,
|
|
131
|
+
"axis_titles": ["Core X (m)", "Core Y (m)", event_count_axis_title],
|
|
132
|
+
},
|
|
133
|
+
"core_vs_energy": {
|
|
134
|
+
"event_data_column": ("core_distance_shower", "simulated_energy"),
|
|
135
|
+
"event_data": (event_data, event_data),
|
|
136
|
+
"bin_edges": (self.core_distance_bins, self.energy_bins),
|
|
137
|
+
"is_1d": False,
|
|
138
|
+
"axis_titles": ["Core Distance (m)", energy_axis_title, event_count_axis_title],
|
|
139
|
+
"plot_scales": {"y": "log"},
|
|
140
|
+
},
|
|
141
|
+
"angular_distance_vs_energy": {
|
|
142
|
+
"event_data_column": ("angular_distance", "simulated_energy"),
|
|
143
|
+
"event_data": (triggered_data, event_data),
|
|
144
|
+
"bin_edges": (self.view_cone_bins, self.energy_bins),
|
|
145
|
+
"is_1d": False,
|
|
146
|
+
"axis_titles": [
|
|
147
|
+
"Angular Distance (deg)",
|
|
148
|
+
energy_axis_title,
|
|
149
|
+
event_count_axis_title,
|
|
150
|
+
],
|
|
151
|
+
"plot_scales": {"y": "log"},
|
|
152
|
+
},
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
hists = {
|
|
156
|
+
name: self.get_histogram_definition(**cfg) | {"suffix": "", "title": "Triggered Events"}
|
|
157
|
+
for name, cfg in definitions.items()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
hists_mc = {}
|
|
161
|
+
for key, hist in hists.items():
|
|
162
|
+
key_mc = f"{key}_mc"
|
|
163
|
+
hists_mc[key_mc] = copy.copy(hist)
|
|
164
|
+
hists_mc[key_mc]["suffix"] = "_mc"
|
|
165
|
+
hists_mc[key_mc]["title"] = "Simulated Events"
|
|
166
|
+
hists_mc[key_mc]["event_data"] = (
|
|
167
|
+
shower_data if hist["1d"] else (shower_data, shower_data)
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
hists.update(hists_mc)
|
|
171
|
+
return hists
|
|
172
|
+
|
|
173
|
+
def get_histogram_definition(
|
|
174
|
+
self,
|
|
175
|
+
event_data_column=None,
|
|
176
|
+
event_data=None,
|
|
177
|
+
histogram=None,
|
|
178
|
+
bin_edges=None,
|
|
179
|
+
title=None,
|
|
180
|
+
axis_titles=None,
|
|
181
|
+
suffix=None,
|
|
182
|
+
is_1d=True,
|
|
183
|
+
plot_scales=None,
|
|
184
|
+
):
|
|
185
|
+
"""Return a single histogram definition."""
|
|
186
|
+
return {
|
|
187
|
+
"histogram": histogram,
|
|
188
|
+
"event_data_column": event_data_column,
|
|
189
|
+
"event_data": event_data,
|
|
190
|
+
"1d": is_1d,
|
|
191
|
+
"bin_edges": bin_edges,
|
|
192
|
+
"title": title,
|
|
193
|
+
"axis_titles": axis_titles,
|
|
194
|
+
"suffix": suffix,
|
|
195
|
+
"plot_scales": plot_scales,
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
def _fill_histogram_and_bin_edges(self, data):
|
|
199
|
+
"""
|
|
200
|
+
Fill histogram and bin edges into the histogram dictionary.
|
|
201
|
+
|
|
202
|
+
Adds to existing histogram if present, otherwise initializes it.
|
|
203
|
+
"""
|
|
204
|
+
if data["1d"]:
|
|
205
|
+
hist, _ = np.histogram(
|
|
206
|
+
getattr(data["event_data"], data["event_data_column"]),
|
|
207
|
+
bins=data["bin_edges"],
|
|
208
|
+
)
|
|
209
|
+
else:
|
|
210
|
+
hist, _, _ = np.histogram2d(
|
|
211
|
+
getattr(data["event_data"][0], data["event_data_column"][0]),
|
|
212
|
+
getattr(data["event_data"][1], data["event_data_column"][1]),
|
|
213
|
+
bins=[data["bin_edges"][0], data["bin_edges"][1]],
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
data["histogram"] = hist if data["histogram"] is None else data["histogram"] + hist
|
|
217
|
+
|
|
218
|
+
def calculate_efficiency_data(self):
|
|
219
|
+
"""
|
|
220
|
+
Calculate efficiency histograms (triggered divided by simulated).
|
|
221
|
+
|
|
222
|
+
Assumes that for each histogram with simulated events, there is a
|
|
223
|
+
corresponding histogram with triggered events.
|
|
224
|
+
|
|
225
|
+
Returns
|
|
226
|
+
-------
|
|
227
|
+
dict
|
|
228
|
+
Dictionary containing the efficiency histograms.
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
def calculate_efficiency(trig_hist, mc_hist):
|
|
232
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
|
233
|
+
return np.divide(
|
|
234
|
+
trig_hist,
|
|
235
|
+
mc_hist,
|
|
236
|
+
out=np.zeros_like(trig_hist, dtype=float),
|
|
237
|
+
where=mc_hist > 0,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
eff_histograms = {}
|
|
241
|
+
for name, mc_hist in self.histograms.items():
|
|
242
|
+
if not name.endswith("_mc"):
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
base_name = name[:-3]
|
|
246
|
+
trig_hist = self.histograms.get(base_name)
|
|
247
|
+
if trig_hist is None:
|
|
248
|
+
continue
|
|
249
|
+
|
|
250
|
+
if mc_hist["histogram"].shape != trig_hist["histogram"].shape:
|
|
251
|
+
self._logger.warning(
|
|
252
|
+
f"Shape mismatch for {base_name} and {name}, skipping efficiency calculation."
|
|
253
|
+
)
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
eff = copy.copy(mc_hist)
|
|
257
|
+
eff.update(
|
|
258
|
+
{
|
|
259
|
+
"histogram": calculate_efficiency(trig_hist["histogram"], mc_hist["histogram"]),
|
|
260
|
+
"suffix": "_eff",
|
|
261
|
+
"title": "Efficiency",
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
eff["axis_titles"] = copy.copy(mc_hist["axis_titles"])
|
|
265
|
+
eff["axis_titles"][-1] = "Efficiency"
|
|
266
|
+
eff_histograms[f"{base_name}_eff"] = eff
|
|
267
|
+
|
|
268
|
+
self.histograms.update(eff_histograms)
|
|
269
|
+
return eff_histograms
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
def energy_bins(self):
|
|
273
|
+
"""Return bins for the energy histogram."""
|
|
274
|
+
if "energy_bin_edges" in self.histograms:
|
|
275
|
+
return self.histograms["energy_bin_edges"]
|
|
276
|
+
return np.logspace(
|
|
277
|
+
np.log10(self.file_info.get("energy_min", 1.0e-3 * u.TeV).to("TeV").value),
|
|
278
|
+
np.log10(self.file_info.get("energy_max", 1.0e3 * u.TeV).to("TeV").value),
|
|
279
|
+
100,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
@property
|
|
283
|
+
def core_distance_bins(self):
|
|
284
|
+
"""Return bins for the core distance histogram."""
|
|
285
|
+
if "core_distance_bin_edges" in self.histograms:
|
|
286
|
+
return self.histograms["core_distance_bin_edges"]
|
|
287
|
+
return np.linspace(
|
|
288
|
+
self.file_info.get("core_scatter_min", 0.0 * u.m).to("m").value,
|
|
289
|
+
self.file_info.get("core_scatter_max", 1.0e5 * u.m).to("m").value,
|
|
290
|
+
100,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
@property
|
|
294
|
+
def view_cone_bins(self):
|
|
295
|
+
"""Return bins for the viewcone histogram."""
|
|
296
|
+
if "viewcone_bin_edges" in self.histograms:
|
|
297
|
+
return self.histograms["viewcone_bin_edges"]
|
|
298
|
+
return np.linspace(
|
|
299
|
+
self.file_info.get("viewcone_min", 0.0 * u.deg).to("deg").value,
|
|
300
|
+
self.file_info.get("viewcone_max", 20.0 * u.deg).to("deg").value,
|
|
301
|
+
100,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
def calculate_cumulative_data(self):
|
|
305
|
+
"""
|
|
306
|
+
Calculate cumulative distributions for triggered histograms.
|
|
307
|
+
|
|
308
|
+
Returns
|
|
309
|
+
-------
|
|
310
|
+
dict
|
|
311
|
+
Dictionary containing the cumulative histograms.
|
|
312
|
+
"""
|
|
313
|
+
cumulative_data = {}
|
|
314
|
+
suffix = "_cumulative"
|
|
315
|
+
|
|
316
|
+
def add_cumulative(name, hist, **kwargs):
|
|
317
|
+
new = copy.copy(hist)
|
|
318
|
+
new["histogram"] = self._calculate_cumulative_histogram(hist["histogram"], **kwargs)
|
|
319
|
+
new["axis_titles"] = copy.copy(hist["axis_titles"])
|
|
320
|
+
new.update(
|
|
321
|
+
{
|
|
322
|
+
"suffix": suffix,
|
|
323
|
+
"title": "Cumulative triggered events",
|
|
324
|
+
}
|
|
325
|
+
)
|
|
326
|
+
new["axis_titles"][-1] = "Fraction of Events"
|
|
327
|
+
cumulative_data[f"{name}{suffix}"] = new
|
|
328
|
+
|
|
329
|
+
# 2D histograms vs energy
|
|
330
|
+
for name, hist in self.histograms.items():
|
|
331
|
+
if name.endswith("_vs_energy") and not name.endswith("_mc"):
|
|
332
|
+
add_cumulative(name, hist, axis=0, normalize=True)
|
|
333
|
+
|
|
334
|
+
# 1D histograms
|
|
335
|
+
for name in ["energy", "core_distance", "angular_distance"]:
|
|
336
|
+
if (hist := self.histograms.get(name)) is not None:
|
|
337
|
+
add_cumulative(name, hist, reverse=name == "energy")
|
|
338
|
+
|
|
339
|
+
self.histograms.update(cumulative_data)
|
|
340
|
+
return cumulative_data
|
|
341
|
+
|
|
342
|
+
def _calculate_cumulative_histogram(self, hist, reverse=False, axis=None, normalize=False):
|
|
343
|
+
"""
|
|
344
|
+
Calculate cumulative distribution of a histogram.
|
|
345
|
+
|
|
346
|
+
Works with both 1D and 2D histograms.
|
|
347
|
+
|
|
348
|
+
Parameters
|
|
349
|
+
----------
|
|
350
|
+
hist : np.ndarray
|
|
351
|
+
Histogram (1D or 2D)
|
|
352
|
+
reverse : bool, optional
|
|
353
|
+
If True, sum from high to low values
|
|
354
|
+
axis : int, optional
|
|
355
|
+
For 2D histograms, axis along which to compute cumulative sum
|
|
356
|
+
None means default behavior: for 1D just cumsum, for 2D along rows
|
|
357
|
+
normalize : bool, optional
|
|
358
|
+
If True, normalize by the total sum for each slice along the specified axis
|
|
359
|
+
For 1D histograms, normalizes by the total sum
|
|
360
|
+
|
|
361
|
+
Returns
|
|
362
|
+
-------
|
|
363
|
+
np.ndarray
|
|
364
|
+
Histogram with cumulative counts, optionally normalized
|
|
365
|
+
"""
|
|
366
|
+
if hist is None:
|
|
367
|
+
return None
|
|
368
|
+
|
|
369
|
+
if hist.ndim == 1:
|
|
370
|
+
result = self._calculate_cumulative_1d(hist, reverse)
|
|
371
|
+
if normalize and np.sum(hist) > 0:
|
|
372
|
+
result = result / np.sum(hist)
|
|
373
|
+
return result
|
|
374
|
+
|
|
375
|
+
axis = axis if axis is not None else 1
|
|
376
|
+
result = self._apply_cumsum_along_axis(hist.copy(), axis, reverse)
|
|
377
|
+
|
|
378
|
+
if normalize:
|
|
379
|
+
# Ensure floating dtype to allow in-place normalization without casting errors
|
|
380
|
+
if not np.issubdtype(result.dtype, np.floating):
|
|
381
|
+
result = result.astype(float)
|
|
382
|
+
self._normalize_along_axis(result, hist, axis)
|
|
383
|
+
|
|
384
|
+
return result
|
|
385
|
+
|
|
386
|
+
def _normalize_along_axis(self, result, hist, axis):
|
|
387
|
+
"""
|
|
388
|
+
Normalize cumulative histogram along the specified axis.
|
|
389
|
+
|
|
390
|
+
Parameters
|
|
391
|
+
----------
|
|
392
|
+
result : np.ndarray
|
|
393
|
+
Cumulative histogram to normalize (modified in-place)
|
|
394
|
+
hist : np.ndarray
|
|
395
|
+
Original histogram (for calculating totals)
|
|
396
|
+
axis : int
|
|
397
|
+
Axis along which normalization should be applied
|
|
398
|
+
"""
|
|
399
|
+
normalized = np.zeros_like(result, dtype=float)
|
|
400
|
+
|
|
401
|
+
if axis == 0:
|
|
402
|
+
for i in range(result.shape[1]):
|
|
403
|
+
col_total = np.sum(hist[:, i])
|
|
404
|
+
if col_total > 0:
|
|
405
|
+
normalized[:, i] = result[:, i] / col_total
|
|
406
|
+
else: # axis == 1
|
|
407
|
+
for i in range(result.shape[0]):
|
|
408
|
+
row_total = np.sum(hist[i, :])
|
|
409
|
+
if row_total > 0:
|
|
410
|
+
normalized[i, :] = result[i, :] / row_total
|
|
411
|
+
|
|
412
|
+
np.copyto(result, normalized)
|
|
413
|
+
|
|
414
|
+
def _calculate_cumulative_1d(self, hist, reverse):
|
|
415
|
+
"""Calculate cumulative distribution for 1D histogram."""
|
|
416
|
+
if reverse:
|
|
417
|
+
return np.cumsum(hist[::-1])[::-1]
|
|
418
|
+
return np.cumsum(hist)
|
|
419
|
+
|
|
420
|
+
def _calculate_cumulative_2d(self, hist, reverse, axis=None):
|
|
421
|
+
"""Calculate cumulative distribution for 2D histogram."""
|
|
422
|
+
axis = axis if axis is not None else 1
|
|
423
|
+
return self._apply_cumsum_along_axis(hist, axis, reverse)
|
|
424
|
+
|
|
425
|
+
def _apply_cumsum_along_axis(self, hist, axis, reverse):
|
|
426
|
+
"""Apply cumulative sum along the specified axis of a 2D histogram."""
|
|
427
|
+
|
|
428
|
+
def cumsum_func(arr):
|
|
429
|
+
return np.cumsum(arr[::-1])[::-1] if reverse else np.cumsum(arr)
|
|
430
|
+
|
|
431
|
+
return np.apply_along_axis(cumsum_func, axis, hist)
|
|
432
|
+
|
|
433
|
+
@staticmethod
|
|
434
|
+
def rebin_2d_histogram(hist, x_bins, y_bins, rebin_factor=2):
|
|
435
|
+
"""
|
|
436
|
+
Rebin a 2D histogram by merging neighboring bins along the energy dimension (y-axis) only.
|
|
437
|
+
|
|
438
|
+
Parameters
|
|
439
|
+
----------
|
|
440
|
+
hist : np.ndarray
|
|
441
|
+
Original 2D histogram data
|
|
442
|
+
x_bins : np.ndarray
|
|
443
|
+
Original x-axis bin edges (preserved)
|
|
444
|
+
y_bins : np.ndarray
|
|
445
|
+
Original y-axis (energy) bin edges
|
|
446
|
+
rebin_factor : int, optional
|
|
447
|
+
Factor by which to reduce the number of bins in the energy dimension
|
|
448
|
+
Default is 2 (merge every 2 bins)
|
|
449
|
+
|
|
450
|
+
Returns
|
|
451
|
+
-------
|
|
452
|
+
tuple
|
|
453
|
+
(re-binned_hist, x_bins, re-binned_y_bins)
|
|
454
|
+
"""
|
|
455
|
+
if rebin_factor <= 1:
|
|
456
|
+
return hist, x_bins, y_bins
|
|
457
|
+
|
|
458
|
+
x_size = hist.shape[0]
|
|
459
|
+
new_y_size = hist.shape[1] // rebin_factor
|
|
460
|
+
|
|
461
|
+
new_hist = np.zeros((x_size, new_y_size), dtype=float)
|
|
462
|
+
|
|
463
|
+
for i in range(x_size):
|
|
464
|
+
for j in range(new_y_size):
|
|
465
|
+
y_start = j * rebin_factor
|
|
466
|
+
y_end = (j + 1) * rebin_factor
|
|
467
|
+
new_hist[i, j] = np.sum(hist[i, y_start:y_end])
|
|
468
|
+
|
|
469
|
+
new_y_bins = y_bins[::rebin_factor]
|
|
470
|
+
|
|
471
|
+
return new_hist, x_bins, new_y_bins
|
|
472
|
+
|
|
473
|
+
def print_summary(self):
|
|
474
|
+
"""
|
|
475
|
+
Print a summary of the histogram statistics.
|
|
476
|
+
|
|
477
|
+
Total number of events is retrieved from the 'energy' histograms.
|
|
478
|
+
"""
|
|
479
|
+
total_simulated = np.sum(self.histograms.get("energy_mc", {}).get("histogram", []))
|
|
480
|
+
total_triggered = np.sum(self.histograms.get("energy", {}).get("histogram", []))
|
|
481
|
+
|
|
482
|
+
self._logger.info(f"Total simulated events: {total_simulated}")
|
|
483
|
+
self._logger.info(f"Total triggered events: {total_triggered}")
|
|
@@ -5,11 +5,11 @@ from dataclasses import dataclass, field
|
|
|
5
5
|
|
|
6
6
|
import astropy.units as u
|
|
7
7
|
import numpy as np
|
|
8
|
-
from astropy.coordinates import
|
|
9
|
-
from ctapipe.coordinates import GroundFrame, TiltedGroundFrame
|
|
8
|
+
from astropy.coordinates import angular_separation
|
|
10
9
|
|
|
11
10
|
from simtools.corsika.primary_particle import PrimaryParticle
|
|
12
|
-
from simtools.
|
|
11
|
+
from simtools.io import table_handler
|
|
12
|
+
from simtools.utils.geometry import solid_angle, transform_ground_to_shower_coordinates
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
@dataclass
|
|
@@ -28,6 +28,7 @@ class ShowerEventData:
|
|
|
28
28
|
x_core_shower: list[np.float64] = field(default_factory=list)
|
|
29
29
|
y_core_shower: list[np.float64] = field(default_factory=list)
|
|
30
30
|
core_distance_shower: list[np.float64] = field(default_factory=list)
|
|
31
|
+
angular_distance: list[float] = field(default_factory=list)
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
@dataclass
|
|
@@ -52,6 +53,7 @@ class SimtelIOEventDataReader:
|
|
|
52
53
|
self.telescope_list = telescope_list
|
|
53
54
|
|
|
54
55
|
self.data_sets = self.read_table_list(event_data_file)
|
|
56
|
+
self.reduced_file_info = None
|
|
55
57
|
|
|
56
58
|
def read_table_list(self, event_data_file):
|
|
57
59
|
"""
|
|
@@ -71,14 +73,21 @@ class SimtelIOEventDataReader:
|
|
|
71
73
|
list
|
|
72
74
|
List of dictionaries containing the data from the tables.
|
|
73
75
|
"""
|
|
74
|
-
dataset_dict =
|
|
76
|
+
dataset_dict = table_handler.read_table_list(
|
|
75
77
|
event_data_file,
|
|
76
78
|
["SHOWERS", "TRIGGERS", "FILE_INFO"],
|
|
77
79
|
include_indexed_tables=True,
|
|
78
80
|
)
|
|
79
81
|
|
|
80
82
|
data_sets = []
|
|
81
|
-
|
|
83
|
+
try:
|
|
84
|
+
sorted_indices = sorted(
|
|
85
|
+
range(len(dataset_dict["SHOWERS"])),
|
|
86
|
+
key=lambda i: int(dataset_dict["SHOWERS"][i].split("_")[-1]),
|
|
87
|
+
)
|
|
88
|
+
except (ValueError, AttributeError):
|
|
89
|
+
sorted_indices = [0] # Handle the case where the key is only "SHOWERS"
|
|
90
|
+
for i in sorted_indices:
|
|
82
91
|
data_sets.append(
|
|
83
92
|
{
|
|
84
93
|
"SHOWERS": dataset_dict["SHOWERS"][i],
|
|
@@ -110,16 +119,27 @@ class SimtelIOEventDataReader:
|
|
|
110
119
|
if table[col].unit:
|
|
111
120
|
setattr(shower_data, f"{col}_unit", table[col].unit)
|
|
112
121
|
|
|
113
|
-
shower_data.x_core_shower, shower_data.y_core_shower = (
|
|
114
|
-
|
|
122
|
+
shower_data.x_core_shower, shower_data.y_core_shower, _ = (
|
|
123
|
+
transform_ground_to_shower_coordinates(
|
|
115
124
|
shower_data.x_core,
|
|
116
125
|
shower_data.y_core,
|
|
126
|
+
0.0,
|
|
117
127
|
shower_data.shower_azimuth,
|
|
118
128
|
shower_data.shower_altitude,
|
|
119
129
|
)
|
|
120
130
|
)
|
|
121
|
-
shower_data.core_distance_shower = np.
|
|
122
|
-
shower_data.x_core_shower
|
|
131
|
+
shower_data.core_distance_shower = np.hypot(
|
|
132
|
+
shower_data.x_core_shower, shower_data.y_core_shower
|
|
133
|
+
)
|
|
134
|
+
shower_data.angular_distance = (
|
|
135
|
+
angular_separation(
|
|
136
|
+
shower_data.shower_azimuth * u.deg,
|
|
137
|
+
shower_data.shower_altitude * u.deg,
|
|
138
|
+
self.reduced_file_info["azimuth"],
|
|
139
|
+
(90.0 * u.deg - self.reduced_file_info["zenith"]),
|
|
140
|
+
)
|
|
141
|
+
.to(u.deg)
|
|
142
|
+
.value
|
|
123
143
|
)
|
|
124
144
|
|
|
125
145
|
return shower_data
|
|
@@ -191,7 +211,7 @@ class SimtelIOEventDataReader:
|
|
|
191
211
|
& (shower_data.event_id == tr_event_id)
|
|
192
212
|
& (shower_data.file_id == tr_file_id)
|
|
193
213
|
)
|
|
194
|
-
matched_idx = np.
|
|
214
|
+
matched_idx = np.nonzero(mask)[0]
|
|
195
215
|
if len(matched_idx) == 1:
|
|
196
216
|
matched_indices.append(matched_idx[0])
|
|
197
217
|
else:
|
|
@@ -233,10 +253,13 @@ class SimtelIOEventDataReader:
|
|
|
233
253
|
def get_name(key):
|
|
234
254
|
return table_name_map.get(key, key)
|
|
235
255
|
|
|
236
|
-
tables =
|
|
256
|
+
tables = table_handler.read_tables(
|
|
237
257
|
event_data_file,
|
|
238
258
|
table_names=[get_name(k) for k in ("SHOWERS", "TRIGGERS", "FILE_INFO")],
|
|
239
259
|
)
|
|
260
|
+
self.reduced_file_info = self.get_reduced_simulation_file_info(
|
|
261
|
+
tables[get_name("FILE_INFO")]
|
|
262
|
+
)
|
|
240
263
|
|
|
241
264
|
shower_data = self._table_to_shower_data(tables[get_name("SHOWERS")])
|
|
242
265
|
triggered_data = self._table_to_triggered_data(tables[get_name("TRIGGERS")])
|
|
@@ -249,10 +272,10 @@ class SimtelIOEventDataReader:
|
|
|
249
272
|
|
|
250
273
|
triggered_data.angular_distance = (
|
|
251
274
|
angular_separation(
|
|
252
|
-
triggered_shower.shower_azimuth * u.
|
|
253
|
-
triggered_shower.shower_altitude * u.
|
|
254
|
-
triggered_data.array_azimuth * u.
|
|
255
|
-
triggered_data.array_altitude * u.
|
|
275
|
+
triggered_shower.shower_azimuth * u.deg,
|
|
276
|
+
triggered_shower.shower_altitude * u.deg,
|
|
277
|
+
triggered_data.array_azimuth * u.deg,
|
|
278
|
+
triggered_data.array_altitude * u.deg,
|
|
256
279
|
)
|
|
257
280
|
.to(u.deg)
|
|
258
281
|
.value
|
|
@@ -298,34 +321,6 @@ class SimtelIOEventDataReader:
|
|
|
298
321
|
|
|
299
322
|
return filtered_triggered_data, filtered_triggered_shower_data
|
|
300
323
|
|
|
301
|
-
def _transform_to_shower_coordinates(self, x_core, y_core, shower_azimuth, shower_altitude):
|
|
302
|
-
"""
|
|
303
|
-
Transform core positions from ground coordinates to shower coordinates.
|
|
304
|
-
|
|
305
|
-
Parameters
|
|
306
|
-
----------
|
|
307
|
-
x_core : np.ndarray
|
|
308
|
-
Core x positions in ground coordinates.
|
|
309
|
-
y_core : np.ndarray
|
|
310
|
-
Core y positions in ground coordinates.
|
|
311
|
-
shower_azimuth : np.ndarray
|
|
312
|
-
Shower azimuth angles.
|
|
313
|
-
shower_altitude : np.ndarray
|
|
314
|
-
Shower altitude angles.
|
|
315
|
-
|
|
316
|
-
Returns
|
|
317
|
-
-------
|
|
318
|
-
tuple
|
|
319
|
-
Core positions in shower coordinates (x, y).
|
|
320
|
-
"""
|
|
321
|
-
ground = GroundFrame(x=x_core * u.m, y=y_core * u.m, z=np.zeros_like(x_core) * u.m)
|
|
322
|
-
shower_frame = ground.transform_to(
|
|
323
|
-
TiltedGroundFrame(
|
|
324
|
-
pointing_direction=AltAz(az=shower_azimuth * u.rad, alt=shower_altitude * u.rad)
|
|
325
|
-
)
|
|
326
|
-
)
|
|
327
|
-
return shower_frame.x.value, shower_frame.y.value
|
|
328
|
-
|
|
329
324
|
def get_reduced_simulation_file_info(self, simulation_file_info):
|
|
330
325
|
"""
|
|
331
326
|
Return reduced simulation file info assuming single-valued parameters.
|
|
@@ -382,4 +377,31 @@ class SimtelIOEventDataReader:
|
|
|
382
377
|
value = value * simulation_file_info[key].unit
|
|
383
378
|
reduced_info[key] = value
|
|
384
379
|
|
|
380
|
+
reduced_info["solid_angle"] = solid_angle(
|
|
381
|
+
angle_min=reduced_info.get("viewcone_min", 0.0 * u.rad),
|
|
382
|
+
angle_max=reduced_info.get("viewcone_max", 0.0 * u.rad),
|
|
383
|
+
)
|
|
384
|
+
reduced_info["scatter_area"] = self.scatter_area(
|
|
385
|
+
core_scatter_min=reduced_info.get("core_scatter_min", 0.0 * u.m),
|
|
386
|
+
core_scatter_max=reduced_info.get("core_scatter_max", 0.0 * u.m),
|
|
387
|
+
)
|
|
388
|
+
|
|
385
389
|
return reduced_info
|
|
390
|
+
|
|
391
|
+
def scatter_area(self, core_scatter_min, core_scatter_max):
|
|
392
|
+
"""
|
|
393
|
+
Calculate the scatter area of the core.
|
|
394
|
+
|
|
395
|
+
Parameters
|
|
396
|
+
----------
|
|
397
|
+
core_scatter_min : astropy.units.Quantity
|
|
398
|
+
Minimum core scatter radius.
|
|
399
|
+
core_scatter_max : astropy.units.Quantity
|
|
400
|
+
Maximum core scatter radius.
|
|
401
|
+
|
|
402
|
+
Returns
|
|
403
|
+
-------
|
|
404
|
+
astropy.units.Quantity
|
|
405
|
+
Scatter area.
|
|
406
|
+
"""
|
|
407
|
+
return np.pi * (core_scatter_max**2 - core_scatter_min**2)
|