gammasimtools 0.17.0__py3-none-any.whl → 0.19.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.17.0.dist-info → gammasimtools-0.19.0.dist-info}/METADATA +27 -69
- gammasimtools-0.19.0.dist-info/RECORD +393 -0
- {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.0.dist-info}/entry_points.txt +10 -2
- {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.0.dist-info}/licenses/LICENSE +1 -1
- simtools/_version.py +16 -3
- simtools/applications/calculate_trigger_rate.py +1 -1
- 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 +10 -1
- simtools/applications/db_add_value_from_json_to_db.py +2 -1
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +8 -13
- simtools/applications/db_generate_compound_indexes.py +61 -0
- simtools/applications/db_get_file_from_db.py +1 -1
- simtools/applications/db_get_parameter_from_db.py +4 -4
- simtools/applications/db_inspect_databases.py +20 -10
- simtools/applications/derive_mirror_rnda.py +18 -12
- simtools/applications/derive_psf_parameters.py +59 -309
- 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_sim_telarray_histograms.py +1 -1
- simtools/applications/generate_simtel_event_data.py +97 -5
- 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 +16 -18
- simtools/applications/plot_array_layout.py +3 -3
- simtools/applications/plot_simtel_events.py +379 -0
- simtools/applications/plot_tabular_data.py +21 -3
- simtools/applications/plot_tabular_data_for_model_parameter.py +104 -0
- simtools/applications/print_version.py +8 -9
- simtools/applications/production_derive_corsika_limits.py +64 -27
- 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 +2 -1
- 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 +31 -1
- simtools/configuration/configurator.py +4 -4
- simtools/constants.py +2 -0
- 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 +88 -24
- simtools/data_model/validate_data.py +34 -9
- simtools/db/db_handler.py +48 -37
- simtools/db/db_model_upload.py +3 -3
- simtools/dependencies.py +88 -25
- simtools/io/ascii_handler.py +279 -0
- simtools/{io_operations → io}/io_handler.py +25 -3
- simtools/{io_operations/io_table_handler.py → io/table_handler.py} +1 -1
- simtools/job_execution/htcondor_script_generator.py +15 -4
- simtools/layout/array_layout.py +1 -1
- simtools/layout/array_layout_utils.py +19 -8
- simtools/model/array_model.py +28 -5
- simtools/model/flasher_model.py +106 -0
- simtools/model/model_parameter.py +4 -4
- simtools/model/model_repository.py +197 -2
- simtools/model/telescope_model.py +3 -1
- simtools/production_configuration/derive_corsika_limits.py +361 -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/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/resources/array-element-ids.json +126 -0
- 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 +7 -3
- 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 +42 -1
- simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +44 -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 +11 -1
- simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +11 -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 +32 -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 +13 -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 +11 -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 +11 -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 +13 -1
- 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 +1 -1
- 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 +20 -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 +11 -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 +1 -1
- 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 +51 -59
- simtools/schemas/production_configuration_metrics.schema.yml +12 -2
- simtools/schemas/production_tables.schema.yml +2 -2
- simtools/simtel/simtel_config_reader.py +2 -2
- simtools/simtel/simtel_config_writer.py +16 -4
- simtools/simtel/simtel_io_event_histograms.py +746 -0
- simtools/simtel/simtel_io_event_reader.py +16 -43
- simtools/simtel/simtel_io_event_writer.py +46 -10
- simtools/simtel/simtel_io_histogram.py +3 -1
- simtools/simtel/simtel_io_histograms.py +7 -3
- simtools/simtel/simtel_io_metadata.py +99 -3
- simtools/simtel/simtel_table_reader.py +92 -10
- 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/testing/configuration.py +24 -26
- simtools/testing/helpers.py +2 -2
- simtools/testing/log_inspector.py +50 -0
- simtools/testing/validate_output.py +87 -37
- simtools/utils/general.py +125 -257
- simtools/utils/geometry.py +36 -0
- simtools/utils/names.py +72 -3
- simtools/visualization/legend_handlers.py +180 -264
- simtools/visualization/plot_array_layout.py +20 -8
- simtools/visualization/plot_pixels.py +1 -2
- simtools/visualization/plot_tables.py +202 -27
- simtools/visualization/simtel_event_plots.py +816 -0
- simtools/visualization/visualize.py +4 -101
- gammasimtools-0.17.0.dist-info/RECORD +0 -374
- simtools/production_configuration/derive_corsika_limits_grid.py +0 -189
- {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.17.0.dist-info → gammasimtools-0.19.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/{schemas → resources}/array_elements.yml +0 -0
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
"""Histograms for shower and triggered events."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
import astropy.units as u
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
import numpy as np
|
|
8
|
+
from matplotlib.colors import LogNorm
|
|
9
|
+
|
|
10
|
+
from simtools.simtel.simtel_io_event_reader import SimtelIOEventDataReader
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SimtelIOEventHistograms:
|
|
14
|
+
"""
|
|
15
|
+
Generate and fill histograms for shower and triggered events.
|
|
16
|
+
|
|
17
|
+
Event data is read from the reduced MC event data file.
|
|
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
|
+
self.telescope_list = telescope_list
|
|
35
|
+
|
|
36
|
+
self.histograms = {}
|
|
37
|
+
self.file_info = {}
|
|
38
|
+
|
|
39
|
+
self.reader = SimtelIOEventDataReader(event_data_file, telescope_list=telescope_list)
|
|
40
|
+
|
|
41
|
+
def _fill_histogram_and_bin_edges(self, name, data, bins, hist1d=True):
|
|
42
|
+
"""
|
|
43
|
+
Fill histogram and bin edges and it both to histogram dictionary.
|
|
44
|
+
|
|
45
|
+
Adds histogram to existing histogram if it exists, otherwise initializes it.
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
if name in self.histograms:
|
|
49
|
+
if hist1d:
|
|
50
|
+
bins = self.histograms[f"{name}_bin_edges"]
|
|
51
|
+
hist, _ = np.histogram(data, bins=bins)
|
|
52
|
+
self.histograms[name] += hist
|
|
53
|
+
else:
|
|
54
|
+
x_bins = self.histograms[f"{name}_bin_x_edges"]
|
|
55
|
+
y_bins = self.histograms[f"{name}_bin_y_edges"]
|
|
56
|
+
hist, _, _ = np.histogram2d(data[0], data[1], bins=[x_bins, y_bins])
|
|
57
|
+
self.histograms[name] += hist
|
|
58
|
+
else:
|
|
59
|
+
if hist1d:
|
|
60
|
+
hist, bin_edges = np.histogram(data, bins=bins)
|
|
61
|
+
self.histograms[name] = hist
|
|
62
|
+
self.histograms[f"{name}_bin_edges"] = bin_edges
|
|
63
|
+
else:
|
|
64
|
+
hist, x_edges, y_edges = np.histogram2d(data[0], data[1], bins=bins)
|
|
65
|
+
self.histograms[name] = hist
|
|
66
|
+
self.histograms[f"{name}_bin_x_edges"] = x_edges
|
|
67
|
+
self.histograms[f"{name}_bin_y_edges"] = y_edges
|
|
68
|
+
|
|
69
|
+
def fill(self):
|
|
70
|
+
"""
|
|
71
|
+
Fill histograms with event data.
|
|
72
|
+
|
|
73
|
+
Involves looping over all event data, and therefore is the slowest part of the
|
|
74
|
+
limit calculation. Adds the histograms to the histogram dictionary.
|
|
75
|
+
|
|
76
|
+
Assume that all event data files are generated with similar configurations
|
|
77
|
+
(self.file_info contains the latest file info).
|
|
78
|
+
"""
|
|
79
|
+
for data_set in self.reader.data_sets:
|
|
80
|
+
self._logger.info(f"Reading event data from {self.event_data_file} for {data_set}")
|
|
81
|
+
_file_info_table, _, event_data, triggered_data = self.reader.read_event_data(
|
|
82
|
+
self.event_data_file, table_name_map=data_set
|
|
83
|
+
)
|
|
84
|
+
_file_info_table = self.reader.get_reduced_simulation_file_info(_file_info_table)
|
|
85
|
+
self.file_info = {
|
|
86
|
+
"energy_min": _file_info_table["energy_min"].to("TeV"),
|
|
87
|
+
"core_scatter_max": _file_info_table["core_scatter_max"].to("m"),
|
|
88
|
+
"viewcone_max": _file_info_table["viewcone_max"].to("deg"),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
self._fill_histogram_and_bin_edges(
|
|
92
|
+
"energy", event_data.simulated_energy, self.energy_bins
|
|
93
|
+
)
|
|
94
|
+
self._fill_histogram_and_bin_edges(
|
|
95
|
+
"core_distance", event_data.core_distance_shower, self.core_distance_bins
|
|
96
|
+
)
|
|
97
|
+
self._fill_histogram_and_bin_edges(
|
|
98
|
+
"angular_distance", triggered_data.angular_distance, self.view_cone_bins
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
xy_bins = np.linspace(
|
|
102
|
+
-1.0 * self.core_distance_bins.max(),
|
|
103
|
+
self.core_distance_bins.max(),
|
|
104
|
+
len(self.core_distance_bins),
|
|
105
|
+
)
|
|
106
|
+
self._fill_histogram_and_bin_edges(
|
|
107
|
+
"shower_cores",
|
|
108
|
+
(event_data.x_core_shower, event_data.y_core_shower),
|
|
109
|
+
[xy_bins, xy_bins],
|
|
110
|
+
hist1d=False,
|
|
111
|
+
)
|
|
112
|
+
self._fill_histogram_and_bin_edges(
|
|
113
|
+
"core_vs_energy",
|
|
114
|
+
(event_data.core_distance_shower, event_data.simulated_energy),
|
|
115
|
+
[self.core_distance_bins, self.energy_bins],
|
|
116
|
+
hist1d=False,
|
|
117
|
+
)
|
|
118
|
+
self._fill_histogram_and_bin_edges(
|
|
119
|
+
"angular_distance_vs_energy",
|
|
120
|
+
(triggered_data.angular_distance, event_data.simulated_energy),
|
|
121
|
+
[self.view_cone_bins, self.energy_bins],
|
|
122
|
+
hist1d=False,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def energy_bins(self):
|
|
127
|
+
"""Return bins for the energy histogram."""
|
|
128
|
+
if "energy_bin_edges" in self.histograms:
|
|
129
|
+
return self.histograms["energy_bin_edges"]
|
|
130
|
+
return np.logspace(
|
|
131
|
+
np.log10(self.file_info.get("energy_min", 1.0e-3 * u.TeV).to("TeV").value),
|
|
132
|
+
np.log10(self.file_info.get("energy_max", 1.0e3 * u.TeV).to("TeV").value),
|
|
133
|
+
100,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def core_distance_bins(self):
|
|
138
|
+
"""Return bins for the core distance histogram."""
|
|
139
|
+
if "core_distance_bin_edges" in self.histograms:
|
|
140
|
+
return self.histograms["core_distance_bin_edges"]
|
|
141
|
+
return np.linspace(
|
|
142
|
+
self.file_info.get("core_scatter_min", 0.0 * u.m).to("m").value,
|
|
143
|
+
self.file_info.get("core_scatter_max", 1.0e5 * u.m).to("m").value,
|
|
144
|
+
100,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
@property
|
|
148
|
+
def view_cone_bins(self):
|
|
149
|
+
"""Return bins for the viewcone histogram."""
|
|
150
|
+
if "viewcone_bin_edges" in self.histograms:
|
|
151
|
+
return self.histograms["viewcone_bin_edges"]
|
|
152
|
+
return np.linspace(
|
|
153
|
+
self.file_info.get("viewcone_min", 0.0 * u.deg).to("deg").value,
|
|
154
|
+
self.file_info.get("viewcone_max", 20.0 * u.deg).to("deg").value,
|
|
155
|
+
100,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
def plot_data(self, output_path=None, limits=None, rebin_factor=2):
|
|
159
|
+
"""
|
|
160
|
+
Histogram plotting.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
output_path: Path or str, optional
|
|
165
|
+
Directory to save plots. If None, plots will be displayed.
|
|
166
|
+
limits: dict, optional
|
|
167
|
+
Dictionary containing limits for plotting. Keys can include:
|
|
168
|
+
- "upper_radius_limit": Upper limit for core distance
|
|
169
|
+
- "lower_energy_limit": Lower limit for energy
|
|
170
|
+
- "viewcone_radius": Radius for the viewcone
|
|
171
|
+
rebin_factor: int, optional
|
|
172
|
+
Factor by which to reduce the number of bins in 2D histograms for rebinned plots.
|
|
173
|
+
Default is 2 (merge every 2 bins). Set to 0 or 1 to disable rebinning.
|
|
174
|
+
"""
|
|
175
|
+
# Plot label constants
|
|
176
|
+
core_distance_label = "Core Distance [m]"
|
|
177
|
+
energy_label = "Energy [TeV]"
|
|
178
|
+
pointing_direction_label = "Distance to pointing direction [deg]"
|
|
179
|
+
cumulative_prefix = "Cumulative "
|
|
180
|
+
event_count_label = "Event Count"
|
|
181
|
+
core_x_label = "Core X [m]"
|
|
182
|
+
core_y_label = "Core Y [m]"
|
|
183
|
+
|
|
184
|
+
# Plot parameter constants
|
|
185
|
+
hist_1d_params = {"color": "tab:green", "edgecolor": "tab:green", "lw": 1}
|
|
186
|
+
hist_1d_cumulative_params = {"color": "tab:blue", "edgecolor": "tab:blue", "lw": 1}
|
|
187
|
+
hist_2d_params = {"norm": "log", "cmap": "viridis", "show_contour": False}
|
|
188
|
+
hist_2d_equal_params = {
|
|
189
|
+
"norm": "log",
|
|
190
|
+
"cmap": "viridis",
|
|
191
|
+
"aspect": "equal",
|
|
192
|
+
"show_contour": False,
|
|
193
|
+
}
|
|
194
|
+
hist_2d_normalized_params = {"norm": "linear", "cmap": "viridis", "show_contour": True}
|
|
195
|
+
|
|
196
|
+
self._logger.info(f"Plotting histograms written to {output_path}")
|
|
197
|
+
|
|
198
|
+
angular_dist_vs_energy = self.histograms.get("angular_distance_vs_energy")
|
|
199
|
+
normalized_cumulative_angular_vs_energy = self._calculate_cumulative_histogram(
|
|
200
|
+
angular_dist_vs_energy, axis=0, normalize=True
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
core_vs_energy = self.histograms.get("core_vs_energy")
|
|
204
|
+
normalized_cumulative_core_vs_energy = self._calculate_cumulative_histogram(
|
|
205
|
+
core_vs_energy, axis=0, normalize=True
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
energy_hist = self.histograms.get("energy")
|
|
209
|
+
cumulative_energy = self._calculate_cumulative_histogram(energy_hist, reverse=True)
|
|
210
|
+
|
|
211
|
+
core_distance_hist = self.histograms.get("core_distance")
|
|
212
|
+
cumulative_core_distance = self._calculate_cumulative_histogram(core_distance_hist)
|
|
213
|
+
|
|
214
|
+
angular_distance_hist = self.histograms.get("angular_distance")
|
|
215
|
+
cumulative_angular_distance = self._calculate_cumulative_histogram(angular_distance_hist)
|
|
216
|
+
|
|
217
|
+
upper_radius_limit, lower_energy_limit, viewcone_radius = self._get_limits(limits)
|
|
218
|
+
|
|
219
|
+
plots = {
|
|
220
|
+
"core_vs_energy": {
|
|
221
|
+
"data": self.histograms.get("core_vs_energy"),
|
|
222
|
+
"bins": [
|
|
223
|
+
self.histograms.get("core_vs_energy_bin_x_edges"),
|
|
224
|
+
self.histograms.get("core_vs_energy_bin_y_edges"),
|
|
225
|
+
],
|
|
226
|
+
"plot_type": "histogram2d",
|
|
227
|
+
"plot_params": hist_2d_params,
|
|
228
|
+
"labels": {
|
|
229
|
+
"x": core_distance_label,
|
|
230
|
+
"y": energy_label,
|
|
231
|
+
"title": "Triggered events: core distance vs energy",
|
|
232
|
+
},
|
|
233
|
+
"lines": {"x": upper_radius_limit, "y": lower_energy_limit},
|
|
234
|
+
"scales": {"y": "log"},
|
|
235
|
+
"colorbar_label": event_count_label,
|
|
236
|
+
"filename": "core_vs_energy_distribution",
|
|
237
|
+
},
|
|
238
|
+
"energy_distribution": {
|
|
239
|
+
"data": self.histograms.get("energy"),
|
|
240
|
+
"bins": self.histograms.get("energy_bin_edges"),
|
|
241
|
+
"plot_type": "histogram",
|
|
242
|
+
"plot_params": hist_1d_params,
|
|
243
|
+
"labels": {
|
|
244
|
+
"x": energy_label,
|
|
245
|
+
"y": event_count_label,
|
|
246
|
+
"title": "Triggered events: energy distribution",
|
|
247
|
+
},
|
|
248
|
+
"scales": {"x": "log", "y": "log"},
|
|
249
|
+
"lines": {"x": lower_energy_limit},
|
|
250
|
+
"filename": "energy_distribution",
|
|
251
|
+
},
|
|
252
|
+
"energy_distribution_cumulative": {
|
|
253
|
+
"data": cumulative_energy,
|
|
254
|
+
"bins": self.histograms.get("energy_bin_edges"),
|
|
255
|
+
"plot_type": "histogram",
|
|
256
|
+
"plot_params": hist_1d_cumulative_params,
|
|
257
|
+
"labels": {
|
|
258
|
+
"x": energy_label,
|
|
259
|
+
"y": cumulative_prefix + event_count_label,
|
|
260
|
+
"title": "Triggered events: cumulative energy distribution",
|
|
261
|
+
},
|
|
262
|
+
"scales": {"x": "log", "y": "log"},
|
|
263
|
+
"lines": {"x": lower_energy_limit},
|
|
264
|
+
"filename": "energy_distribution_cumulative",
|
|
265
|
+
},
|
|
266
|
+
"core_distance": {
|
|
267
|
+
"data": self.histograms.get("core_distance"),
|
|
268
|
+
"bins": self.histograms.get("core_distance_bin_edges"),
|
|
269
|
+
"plot_type": "histogram",
|
|
270
|
+
"plot_params": hist_1d_params,
|
|
271
|
+
"labels": {
|
|
272
|
+
"x": core_distance_label,
|
|
273
|
+
"y": event_count_label,
|
|
274
|
+
"title": "Triggered events: core distance distribution",
|
|
275
|
+
},
|
|
276
|
+
"lines": {"x": upper_radius_limit},
|
|
277
|
+
"filename": "core_distance_distribution",
|
|
278
|
+
},
|
|
279
|
+
"core_distance_cumulative": {
|
|
280
|
+
"data": cumulative_core_distance,
|
|
281
|
+
"bins": self.histograms.get("core_distance_bin_edges"),
|
|
282
|
+
"plot_type": "histogram",
|
|
283
|
+
"plot_params": hist_1d_cumulative_params,
|
|
284
|
+
"labels": {
|
|
285
|
+
"x": core_distance_label,
|
|
286
|
+
"y": cumulative_prefix + event_count_label,
|
|
287
|
+
"title": "Triggered events: cumulative core distance distribution",
|
|
288
|
+
},
|
|
289
|
+
"lines": {"x": upper_radius_limit},
|
|
290
|
+
"filename": "core_distance_cumulative_distribution",
|
|
291
|
+
},
|
|
292
|
+
"core_xy": {
|
|
293
|
+
"data": self.histograms.get("shower_cores"),
|
|
294
|
+
"bins": [
|
|
295
|
+
self.histograms.get("shower_cores_bin_x_edges"),
|
|
296
|
+
self.histograms.get("shower_cores_bin_y_edges"),
|
|
297
|
+
],
|
|
298
|
+
"plot_type": "histogram2d",
|
|
299
|
+
"plot_params": hist_2d_equal_params,
|
|
300
|
+
"labels": {
|
|
301
|
+
"x": core_x_label,
|
|
302
|
+
"y": core_y_label,
|
|
303
|
+
"title": "Triggered events: core x vs core y",
|
|
304
|
+
},
|
|
305
|
+
"colorbar_label": event_count_label,
|
|
306
|
+
"lines": {
|
|
307
|
+
"r": upper_radius_limit,
|
|
308
|
+
},
|
|
309
|
+
"filename": "core_xy_distribution",
|
|
310
|
+
},
|
|
311
|
+
"angular_distance": {
|
|
312
|
+
"data": self.histograms.get("angular_distance"),
|
|
313
|
+
"bins": self.histograms.get("angular_distance_bin_edges"),
|
|
314
|
+
"plot_type": "histogram",
|
|
315
|
+
"plot_params": hist_1d_params,
|
|
316
|
+
"labels": {
|
|
317
|
+
"x": pointing_direction_label,
|
|
318
|
+
"y": event_count_label,
|
|
319
|
+
"title": "Triggered events: angular distance distribution",
|
|
320
|
+
},
|
|
321
|
+
"lines": {"x": viewcone_radius},
|
|
322
|
+
"filename": "angular_distance_distribution",
|
|
323
|
+
},
|
|
324
|
+
"angular_distance_cumulative": {
|
|
325
|
+
"data": cumulative_angular_distance,
|
|
326
|
+
"bins": self.histograms.get("angular_distance_bin_edges"),
|
|
327
|
+
"plot_type": "histogram",
|
|
328
|
+
"plot_params": hist_1d_cumulative_params,
|
|
329
|
+
"labels": {
|
|
330
|
+
"x": pointing_direction_label,
|
|
331
|
+
"y": cumulative_prefix + event_count_label,
|
|
332
|
+
"title": "Triggered events: cumulative angular distance distribution",
|
|
333
|
+
},
|
|
334
|
+
"lines": {"x": viewcone_radius},
|
|
335
|
+
"filename": "angular_distance_cumulative_distribution",
|
|
336
|
+
},
|
|
337
|
+
"angular_distance_vs_energy": {
|
|
338
|
+
"data": self.histograms.get("angular_distance_vs_energy"),
|
|
339
|
+
"bins": [
|
|
340
|
+
self.histograms.get("angular_distance_vs_energy_bin_x_edges"),
|
|
341
|
+
self.histograms.get("angular_distance_vs_energy_bin_y_edges"),
|
|
342
|
+
],
|
|
343
|
+
"plot_type": "histogram2d",
|
|
344
|
+
"plot_params": hist_2d_params,
|
|
345
|
+
"labels": {
|
|
346
|
+
"x": pointing_direction_label,
|
|
347
|
+
"y": energy_label,
|
|
348
|
+
"title": "Triggered events: angular distance distance vs energy",
|
|
349
|
+
},
|
|
350
|
+
"lines": {
|
|
351
|
+
"x": viewcone_radius,
|
|
352
|
+
"y": lower_energy_limit,
|
|
353
|
+
},
|
|
354
|
+
"scales": {"y": "log"},
|
|
355
|
+
"colorbar_label": event_count_label,
|
|
356
|
+
"filename": "angular_distance_vs_energy_distribution",
|
|
357
|
+
},
|
|
358
|
+
"angular_distance_vs_energy_cumulative": {
|
|
359
|
+
"data": normalized_cumulative_angular_vs_energy,
|
|
360
|
+
"bins": [
|
|
361
|
+
self.histograms.get("angular_distance_vs_energy_bin_x_edges"),
|
|
362
|
+
self.histograms.get("angular_distance_vs_energy_bin_y_edges"),
|
|
363
|
+
],
|
|
364
|
+
"plot_type": "histogram2d",
|
|
365
|
+
"plot_params": hist_2d_normalized_params, # Includes contour line at value=1
|
|
366
|
+
"labels": {
|
|
367
|
+
"x": pointing_direction_label,
|
|
368
|
+
"y": energy_label,
|
|
369
|
+
"title": "Triggered events: fraction of events by angular distance vs energy",
|
|
370
|
+
},
|
|
371
|
+
"lines": {
|
|
372
|
+
"x": viewcone_radius,
|
|
373
|
+
"y": lower_energy_limit,
|
|
374
|
+
},
|
|
375
|
+
"scales": {"y": "log"},
|
|
376
|
+
"colorbar_label": "Fraction of events",
|
|
377
|
+
"filename": "angular_distance_vs_energy_cumulative_distribution",
|
|
378
|
+
},
|
|
379
|
+
"core_vs_energy_cumulative": {
|
|
380
|
+
"data": normalized_cumulative_core_vs_energy,
|
|
381
|
+
"bins": [
|
|
382
|
+
self.histograms.get("core_vs_energy_bin_x_edges"),
|
|
383
|
+
self.histograms.get("core_vs_energy_bin_y_edges"),
|
|
384
|
+
],
|
|
385
|
+
"plot_type": "histogram2d",
|
|
386
|
+
"plot_params": hist_2d_normalized_params,
|
|
387
|
+
"labels": {
|
|
388
|
+
"x": core_distance_label,
|
|
389
|
+
"y": energy_label,
|
|
390
|
+
"title": "Triggered events: fraction of events by core distance vs energy",
|
|
391
|
+
},
|
|
392
|
+
"lines": {
|
|
393
|
+
"x": upper_radius_limit,
|
|
394
|
+
"y": lower_energy_limit,
|
|
395
|
+
},
|
|
396
|
+
"scales": {"y": "log"},
|
|
397
|
+
"colorbar_label": "Fraction of events",
|
|
398
|
+
"filename": "core_vs_energy_cumulative_distribution",
|
|
399
|
+
},
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
for plot_key, plot_args in plots.items():
|
|
403
|
+
plot_filename = plot_args.pop("filename")
|
|
404
|
+
if self.array_name and plot_args.get("labels", {}).get("title"):
|
|
405
|
+
plot_args["labels"]["title"] += f" ({self.array_name} array)"
|
|
406
|
+
|
|
407
|
+
filename = self._build_plot_filename(plot_filename, self.array_name)
|
|
408
|
+
output_file = output_path / filename if output_path else None
|
|
409
|
+
self._create_plot(**plot_args, output_file=output_file)
|
|
410
|
+
|
|
411
|
+
if self._should_create_rebinned_plot(rebin_factor, plot_args, plot_key):
|
|
412
|
+
self._create_rebinned_plot(plot_args, filename, output_path, rebin_factor)
|
|
413
|
+
|
|
414
|
+
def _get_limits(self, limits):
|
|
415
|
+
"""Extract limits from the provided dictionary for plotting."""
|
|
416
|
+
upper_radius_limit = None
|
|
417
|
+
lower_energy_limit = None
|
|
418
|
+
viewcone_radius = None
|
|
419
|
+
if limits:
|
|
420
|
+
upper_radius_limit = (
|
|
421
|
+
limits["upper_radius_limit"].value if "upper_radius_limit" in limits else None
|
|
422
|
+
)
|
|
423
|
+
lower_energy_limit = (
|
|
424
|
+
limits["lower_energy_limit"].value if "lower_energy_limit" in limits else None
|
|
425
|
+
)
|
|
426
|
+
viewcone_radius = (
|
|
427
|
+
limits["viewcone_radius"].value if "viewcone_radius" in limits else None
|
|
428
|
+
)
|
|
429
|
+
return upper_radius_limit, lower_energy_limit, viewcone_radius
|
|
430
|
+
|
|
431
|
+
def _build_plot_filename(self, base_filename, array_name=None):
|
|
432
|
+
"""
|
|
433
|
+
Build the full plot filename with appropriate extensions.
|
|
434
|
+
|
|
435
|
+
Parameters
|
|
436
|
+
----------
|
|
437
|
+
base_filename : str
|
|
438
|
+
The base filename without extension
|
|
439
|
+
array_name : str, optional
|
|
440
|
+
Name of the array to append to filename
|
|
441
|
+
|
|
442
|
+
Returns
|
|
443
|
+
-------
|
|
444
|
+
str
|
|
445
|
+
Complete filename with extension
|
|
446
|
+
"""
|
|
447
|
+
if array_name:
|
|
448
|
+
return f"{base_filename}_{array_name}.png"
|
|
449
|
+
return f"{base_filename}.png"
|
|
450
|
+
|
|
451
|
+
def _should_create_rebinned_plot(self, rebin_factor, plot_args, plot_key):
|
|
452
|
+
"""
|
|
453
|
+
Check if a rebinned version of the plot should be created.
|
|
454
|
+
|
|
455
|
+
Parameters
|
|
456
|
+
----------
|
|
457
|
+
rebin_factor : int
|
|
458
|
+
Factor by which to rebin the energy axis
|
|
459
|
+
plot_args : dict
|
|
460
|
+
Plot arguments
|
|
461
|
+
plot_key : str
|
|
462
|
+
Key identifying the plot type
|
|
463
|
+
|
|
464
|
+
Returns
|
|
465
|
+
-------
|
|
466
|
+
bool
|
|
467
|
+
True if a rebinned plot should be created, False otherwise
|
|
468
|
+
"""
|
|
469
|
+
return (
|
|
470
|
+
rebin_factor > 1
|
|
471
|
+
and plot_args["plot_type"] == "histogram2d"
|
|
472
|
+
and plot_key.endswith("_cumulative")
|
|
473
|
+
and plot_args.get("plot_params", {}).get("norm") == "linear"
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
def _create_rebinned_plot(self, plot_args, filename, output_path, rebin_factor):
|
|
477
|
+
"""
|
|
478
|
+
Create a rebinned version of a 2D histogram plot.
|
|
479
|
+
|
|
480
|
+
Parameters
|
|
481
|
+
----------
|
|
482
|
+
plot_args : dict
|
|
483
|
+
Plot arguments for the original plot
|
|
484
|
+
filename : str
|
|
485
|
+
Filename of the original plot
|
|
486
|
+
output_path : Path or None
|
|
487
|
+
Path to save the plot to, or None
|
|
488
|
+
rebin_factor : int
|
|
489
|
+
Factor by which to rebin the energy axis
|
|
490
|
+
"""
|
|
491
|
+
data = plot_args["data"]
|
|
492
|
+
bins = plot_args["bins"]
|
|
493
|
+
|
|
494
|
+
rebinned_data, rebinned_x_bins, rebinned_y_bins = self._rebin_2d_histogram(
|
|
495
|
+
data, bins[0], bins[1], rebin_factor
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
rebinned_plot_args = plot_args.copy()
|
|
499
|
+
rebinned_plot_args["data"] = rebinned_data
|
|
500
|
+
rebinned_plot_args["bins"] = [rebinned_x_bins, rebinned_y_bins]
|
|
501
|
+
|
|
502
|
+
if rebinned_plot_args.get("labels", {}).get("title"):
|
|
503
|
+
rebinned_plot_args["labels"]["title"] += f" (Energy rebinned {rebin_factor}x)"
|
|
504
|
+
|
|
505
|
+
rebinned_filename = f"{filename.replace('.png', '')}_rebinned.png"
|
|
506
|
+
rebinned_output_file = output_path / rebinned_filename if output_path else None
|
|
507
|
+
self._create_plot(**rebinned_plot_args, output_file=rebinned_output_file)
|
|
508
|
+
|
|
509
|
+
def _create_plot(
|
|
510
|
+
self,
|
|
511
|
+
data,
|
|
512
|
+
bins=None,
|
|
513
|
+
plot_type="histogram",
|
|
514
|
+
plot_params=None,
|
|
515
|
+
labels=None,
|
|
516
|
+
scales=None,
|
|
517
|
+
colorbar_label=None,
|
|
518
|
+
output_file=None,
|
|
519
|
+
lines=None,
|
|
520
|
+
):
|
|
521
|
+
"""
|
|
522
|
+
Create and save a plot with the given parameters.
|
|
523
|
+
|
|
524
|
+
For normalized 2D histograms, a contour line is drawn at the value of 1.0
|
|
525
|
+
to indicate the boundary where each energy bin reaches complete containment.
|
|
526
|
+
This can be controlled with the 'show_contour' parameter in plot_params.
|
|
527
|
+
"""
|
|
528
|
+
plot_params = plot_params or {}
|
|
529
|
+
labels = labels or {}
|
|
530
|
+
scales = scales or {}
|
|
531
|
+
lines = lines or {}
|
|
532
|
+
|
|
533
|
+
fig, ax = plt.subplots(figsize=(8, 6))
|
|
534
|
+
|
|
535
|
+
if plot_type == "histogram":
|
|
536
|
+
plt.bar(bins[:-1], data, width=np.diff(bins), **plot_params)
|
|
537
|
+
elif plot_type == "histogram2d":
|
|
538
|
+
pcm = self._create_2d_histogram_plot(data, bins, plot_params)
|
|
539
|
+
plt.colorbar(pcm, label=colorbar_label)
|
|
540
|
+
|
|
541
|
+
if "x" in lines:
|
|
542
|
+
plt.axvline(lines["x"], color="r", linestyle="--", linewidth=0.5)
|
|
543
|
+
if "y" in lines:
|
|
544
|
+
plt.axhline(lines["y"], color="r", linestyle="--", linewidth=0.5)
|
|
545
|
+
if "r" in lines:
|
|
546
|
+
circle = plt.Circle(
|
|
547
|
+
(0, 0), lines["r"], color="r", fill=False, linestyle="--", linewidth=0.5
|
|
548
|
+
)
|
|
549
|
+
plt.gca().add_artist(circle)
|
|
550
|
+
|
|
551
|
+
ax.set(
|
|
552
|
+
xlabel=labels.get("x", ""),
|
|
553
|
+
ylabel=labels.get("y", ""),
|
|
554
|
+
title=labels.get("title", ""),
|
|
555
|
+
xscale=scales.get("x", "linear"),
|
|
556
|
+
yscale=scales.get("y", "linear"),
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
if output_file:
|
|
560
|
+
self._logger.info(f"Saving plot to {output_file}")
|
|
561
|
+
plt.savefig(output_file, dpi=300, bbox_inches="tight")
|
|
562
|
+
plt.close()
|
|
563
|
+
else:
|
|
564
|
+
plt.tight_layout()
|
|
565
|
+
plt.show()
|
|
566
|
+
|
|
567
|
+
return fig
|
|
568
|
+
|
|
569
|
+
def _create_2d_histogram_plot(self, data, bins, plot_params):
|
|
570
|
+
"""
|
|
571
|
+
Create a 2D histogram plot with the given parameters.
|
|
572
|
+
|
|
573
|
+
Parameters
|
|
574
|
+
----------
|
|
575
|
+
data : np.ndarray
|
|
576
|
+
2D histogram data
|
|
577
|
+
bins : tuple of np.ndarray
|
|
578
|
+
Bin edges for x and y axes
|
|
579
|
+
plot_params : dict
|
|
580
|
+
Plot parameters including norm, cmap, and show_contour
|
|
581
|
+
|
|
582
|
+
Returns
|
|
583
|
+
-------
|
|
584
|
+
matplotlib.collections.QuadMesh
|
|
585
|
+
The created pcolormesh object for colorbar attachment
|
|
586
|
+
"""
|
|
587
|
+
if plot_params.get("norm") == "linear":
|
|
588
|
+
pcm = plt.pcolormesh(
|
|
589
|
+
bins[0],
|
|
590
|
+
bins[1],
|
|
591
|
+
data.T,
|
|
592
|
+
vmin=0,
|
|
593
|
+
vmax=1,
|
|
594
|
+
cmap=plot_params.get("cmap", "viridis"),
|
|
595
|
+
)
|
|
596
|
+
# Add contour line at value=1.0 for normalized histograms
|
|
597
|
+
if plot_params.get("show_contour", True):
|
|
598
|
+
x_centers = (bins[0][1:] + bins[0][:-1]) / 2
|
|
599
|
+
y_centers = (bins[1][1:] + bins[1][:-1]) / 2
|
|
600
|
+
x_mesh, y_mesh = np.meshgrid(x_centers, y_centers)
|
|
601
|
+
plt.contour(
|
|
602
|
+
x_mesh,
|
|
603
|
+
y_mesh,
|
|
604
|
+
data.T,
|
|
605
|
+
levels=[0.999999], # very close to 1 for floating point precision
|
|
606
|
+
colors=["tab:red"],
|
|
607
|
+
linestyles=["--"],
|
|
608
|
+
linewidths=[0.5],
|
|
609
|
+
)
|
|
610
|
+
else:
|
|
611
|
+
pcm = plt.pcolormesh(
|
|
612
|
+
bins[0], bins[1], data.T, norm=LogNorm(vmin=1, vmax=data.max()), cmap="viridis"
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
return pcm
|
|
616
|
+
|
|
617
|
+
def _calculate_cumulative_histogram(self, hist, reverse=False, axis=None, normalize=False):
|
|
618
|
+
"""
|
|
619
|
+
Calculate cumulative distribution of a histogram.
|
|
620
|
+
|
|
621
|
+
Works with both 1D and 2D histograms.
|
|
622
|
+
|
|
623
|
+
Parameters
|
|
624
|
+
----------
|
|
625
|
+
hist : np.ndarray
|
|
626
|
+
Histogram (1D or 2D)
|
|
627
|
+
reverse : bool, optional
|
|
628
|
+
If True, sum from high to low values
|
|
629
|
+
axis : int, optional
|
|
630
|
+
For 2D histograms, axis along which to compute cumulative sum
|
|
631
|
+
None means default behavior: for 1D just cumsum, for 2D along rows
|
|
632
|
+
normalize : bool, optional
|
|
633
|
+
If True, normalize by the total sum for each slice along the specified axis
|
|
634
|
+
For 1D histograms, normalizes by the total sum
|
|
635
|
+
|
|
636
|
+
Returns
|
|
637
|
+
-------
|
|
638
|
+
np.ndarray
|
|
639
|
+
Histogram with cumulative counts, optionally normalized
|
|
640
|
+
"""
|
|
641
|
+
if hist is None:
|
|
642
|
+
return None
|
|
643
|
+
|
|
644
|
+
if hist.ndim == 1:
|
|
645
|
+
result = self._calculate_cumulative_1d(hist, reverse)
|
|
646
|
+
if normalize and np.sum(hist) > 0:
|
|
647
|
+
result = result / np.sum(hist)
|
|
648
|
+
return result
|
|
649
|
+
|
|
650
|
+
if axis is None:
|
|
651
|
+
axis = 1
|
|
652
|
+
|
|
653
|
+
result = self._apply_cumsum_along_axis(hist.copy(), axis, reverse)
|
|
654
|
+
|
|
655
|
+
if normalize:
|
|
656
|
+
self._normalize_along_axis(result, hist, axis)
|
|
657
|
+
|
|
658
|
+
return result
|
|
659
|
+
|
|
660
|
+
def _normalize_along_axis(self, result, hist, axis):
|
|
661
|
+
"""
|
|
662
|
+
Normalize cumulative histogram along the specified axis.
|
|
663
|
+
|
|
664
|
+
Parameters
|
|
665
|
+
----------
|
|
666
|
+
result : np.ndarray
|
|
667
|
+
Cumulative histogram to normalize (modified in-place)
|
|
668
|
+
hist : np.ndarray
|
|
669
|
+
Original histogram (for calculating totals)
|
|
670
|
+
axis : int
|
|
671
|
+
Axis along which normalization should be applied
|
|
672
|
+
"""
|
|
673
|
+
normalized = np.zeros_like(result, dtype=float)
|
|
674
|
+
|
|
675
|
+
if axis == 0:
|
|
676
|
+
for i in range(result.shape[1]):
|
|
677
|
+
col_total = np.sum(hist[:, i])
|
|
678
|
+
if col_total > 0:
|
|
679
|
+
normalized[:, i] = result[:, i] / col_total
|
|
680
|
+
else: # axis == 1
|
|
681
|
+
for i in range(result.shape[0]):
|
|
682
|
+
row_total = np.sum(hist[i, :])
|
|
683
|
+
if row_total > 0:
|
|
684
|
+
normalized[i, :] = result[i, :] / row_total
|
|
685
|
+
|
|
686
|
+
np.copyto(result, normalized)
|
|
687
|
+
|
|
688
|
+
def _calculate_cumulative_1d(self, hist, reverse):
|
|
689
|
+
"""Calculate cumulative distribution for 1D histogram."""
|
|
690
|
+
if reverse:
|
|
691
|
+
return np.cumsum(hist[::-1])[::-1]
|
|
692
|
+
return np.cumsum(hist)
|
|
693
|
+
|
|
694
|
+
def _calculate_cumulative_2d(self, hist, reverse, axis=None):
|
|
695
|
+
"""Calculate cumulative distribution for 2D histogram."""
|
|
696
|
+
if axis is None:
|
|
697
|
+
axis = 1
|
|
698
|
+
|
|
699
|
+
return self._apply_cumsum_along_axis(hist, axis, reverse)
|
|
700
|
+
|
|
701
|
+
def _apply_cumsum_along_axis(self, hist, axis, reverse):
|
|
702
|
+
"""Apply cumulative sum along the specified axis of a 2D histogram."""
|
|
703
|
+
|
|
704
|
+
def cumsum_func(arr):
|
|
705
|
+
return np.cumsum(arr[::-1])[::-1] if reverse else np.cumsum(arr)
|
|
706
|
+
|
|
707
|
+
return np.apply_along_axis(cumsum_func, axis, hist)
|
|
708
|
+
|
|
709
|
+
def _rebin_2d_histogram(self, hist, x_bins, y_bins, rebin_factor=2):
|
|
710
|
+
"""
|
|
711
|
+
Rebin a 2D histogram by merging neighboring bins along the energy dimension (y-axis) only.
|
|
712
|
+
|
|
713
|
+
Parameters
|
|
714
|
+
----------
|
|
715
|
+
hist : np.ndarray
|
|
716
|
+
Original 2D histogram data
|
|
717
|
+
x_bins : np.ndarray
|
|
718
|
+
Original x-axis bin edges (preserved)
|
|
719
|
+
y_bins : np.ndarray
|
|
720
|
+
Original y-axis (energy) bin edges
|
|
721
|
+
rebin_factor : int, optional
|
|
722
|
+
Factor by which to reduce the number of bins in the energy dimension
|
|
723
|
+
Default is 2 (merge every 2 bins)
|
|
724
|
+
|
|
725
|
+
Returns
|
|
726
|
+
-------
|
|
727
|
+
tuple
|
|
728
|
+
(rebinned_hist, x_bins, rebinned_y_bins)
|
|
729
|
+
"""
|
|
730
|
+
if rebin_factor <= 1:
|
|
731
|
+
return hist, x_bins, y_bins
|
|
732
|
+
|
|
733
|
+
x_size = hist.shape[0]
|
|
734
|
+
new_y_size = hist.shape[1] // rebin_factor
|
|
735
|
+
|
|
736
|
+
new_hist = np.zeros((x_size, new_y_size), dtype=float)
|
|
737
|
+
|
|
738
|
+
for i in range(x_size):
|
|
739
|
+
for j in range(new_y_size):
|
|
740
|
+
y_start = j * rebin_factor
|
|
741
|
+
y_end = (j + 1) * rebin_factor
|
|
742
|
+
new_hist[i, j] = np.sum(hist[i, y_start:y_end])
|
|
743
|
+
|
|
744
|
+
new_y_bins = y_bins[::rebin_factor]
|
|
745
|
+
|
|
746
|
+
return new_hist, x_bins, new_y_bins
|