gammasimtools 0.6.1__py3-none-any.whl → 0.8.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gammasimtools-0.8.2.dist-info/METADATA +173 -0
- gammasimtools-0.8.2.dist-info/RECORD +345 -0
- {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/WHEEL +1 -1
- gammasimtools-0.8.2.dist-info/entry_points.txt +31 -0
- simtools/_dev_version/__init__.py +9 -0
- simtools/_version.py +2 -2
- simtools/applications/calculate_trigger_rate.py +210 -0
- simtools/applications/convert_all_model_parameters_from_simtel.py +372 -0
- simtools/applications/{print_array_elements.py → convert_geo_coordinates_of_array_elements.py} +58 -63
- simtools/applications/convert_model_parameter_from_simtel.py +119 -0
- simtools/applications/{add_file_to_db.py → db_add_file_to_db.py} +70 -60
- simtools/applications/db_add_model_parameters_from_repository_to_db.py +184 -0
- simtools/applications/db_add_value_from_json_to_db.py +105 -0
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +180 -0
- simtools/applications/db_get_array_layouts_from_db.py +162 -0
- simtools/applications/{get_file_from_db.py → db_get_file_from_db.py} +30 -34
- simtools/applications/db_get_parameter_from_db.py +131 -0
- simtools/applications/db_inspect_databases.py +52 -0
- simtools/applications/derive_mirror_rnda.py +39 -255
- simtools/applications/derive_psf_parameters.py +441 -0
- simtools/applications/generate_array_config.py +82 -0
- simtools/applications/generate_corsika_histograms.py +52 -52
- simtools/applications/generate_default_metadata.py +5 -8
- simtools/applications/generate_regular_arrays.py +117 -0
- simtools/applications/generate_simtel_array_histograms.py +97 -56
- simtools/applications/plot_array_layout.py +345 -115
- simtools/applications/production_generate_simulation_config.py +158 -0
- simtools/applications/production_scale_events.py +168 -0
- simtools/applications/simulate_light_emission.py +478 -0
- simtools/applications/simulate_prod.py +97 -175
- simtools/applications/submit_data_from_external.py +9 -12
- simtools/applications/submit_model_parameter_from_external.py +122 -0
- simtools/applications/validate_camera_efficiency.py +35 -102
- simtools/applications/validate_camera_fov.py +20 -19
- simtools/applications/{compare_cumulative_psf.py → validate_cumulative_psf.py} +45 -44
- simtools/applications/validate_file_using_schema.py +111 -47
- simtools/applications/validate_optics.py +17 -22
- simtools/camera_efficiency.py +193 -202
- simtools/configuration/commandline_parser.py +384 -96
- simtools/configuration/configurator.py +55 -71
- simtools/constants.py +5 -5
- simtools/corsika/corsika_config.py +482 -342
- simtools/corsika/corsika_histograms.py +226 -204
- simtools/corsika/corsika_histograms_visualize.py +23 -24
- simtools/corsika/primary_particle.py +159 -0
- simtools/data_model/data_reader.py +25 -20
- simtools/data_model/format_checkers.py +52 -0
- simtools/data_model/metadata_collector.py +211 -185
- simtools/data_model/metadata_model.py +115 -37
- simtools/data_model/model_data_writer.py +335 -26
- simtools/data_model/validate_data.py +366 -154
- simtools/db/db_array_elements.py +130 -0
- simtools/db/db_from_repo_handler.py +106 -0
- simtools/db/db_handler.py +1246 -0
- simtools/io_operations/hdf5_handler.py +3 -1
- simtools/io_operations/io_handler.py +32 -57
- simtools/job_execution/job_manager.py +82 -69
- simtools/layout/array_layout.py +325 -537
- simtools/layout/geo_coordinates.py +8 -11
- simtools/layout/telescope_position.py +163 -86
- simtools/model/array_model.py +312 -259
- simtools/model/calibration_model.py +50 -0
- simtools/model/camera.py +277 -523
- simtools/model/mirrors.py +68 -49
- simtools/model/model_parameter.py +602 -0
- simtools/model/model_utils.py +11 -39
- simtools/model/site_model.py +161 -0
- simtools/model/telescope_model.py +143 -633
- simtools/production_configuration/calculate_statistical_errors_grid_point.py +454 -0
- simtools/production_configuration/event_scaler.py +146 -0
- simtools/production_configuration/generate_simulation_config.py +193 -0
- simtools/production_configuration/interpolation_handler.py +197 -0
- simtools/ray_tracing/__init__.py +0 -0
- simtools/ray_tracing/mirror_panel_psf.py +280 -0
- simtools/{psf_analysis.py → ray_tracing/psf_analysis.py} +133 -47
- simtools/ray_tracing/ray_tracing.py +646 -0
- simtools/runners/__init__.py +0 -0
- simtools/runners/corsika_runner.py +240 -0
- simtools/runners/corsika_simtel_runner.py +225 -0
- simtools/runners/runner_services.py +307 -0
- simtools/runners/simtel_runner.py +224 -0
- simtools/schemas/array_elements.yml +137 -0
- simtools/schemas/integration_tests_config.metaschema.yml +93 -0
- simtools/schemas/metadata.metaschema.yml +6 -0
- simtools/schemas/model_parameter.metaschema.yml +78 -0
- simtools/schemas/{data.metaschema.yml → model_parameter_and_data_schema.metaschema.yml} +27 -44
- simtools/schemas/model_parameters/adjust_gain.schema.yml +37 -0
- simtools/schemas/model_parameters/altitude.schema.yml +37 -0
- simtools/schemas/model_parameters/array_coordinates.schema.yml +33 -0
- simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +77 -0
- simtools/schemas/model_parameters/array_element_position_ground.schema.yml +39 -0
- simtools/schemas/model_parameters/array_element_position_utm.schema.yml +39 -0
- simtools/schemas/model_parameters/array_layouts.schema.yml +48 -0
- simtools/schemas/model_parameters/array_triggers.schema.yml +93 -0
- simtools/schemas/model_parameters/asum_clipping.schema.yml +38 -0
- simtools/schemas/model_parameters/asum_offset.schema.yml +35 -0
- simtools/schemas/model_parameters/asum_shaping.schema.yml +35 -0
- simtools/schemas/model_parameters/asum_threshold.schema.yml +38 -0
- simtools/schemas/model_parameters/atmospheric_profile.schema.yml +32 -0
- simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +35 -0
- simtools/schemas/model_parameters/axes_offsets.schema.yml +53 -0
- simtools/schemas/model_parameters/camera_body_diameter.schema.yml +40 -0
- simtools/schemas/model_parameters/camera_body_shape.schema.yml +45 -0
- simtools/schemas/model_parameters/camera_config_file.schema.yml +40 -0
- simtools/schemas/model_parameters/camera_config_rotate.schema.yml +36 -0
- simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +43 -0
- simtools/schemas/model_parameters/camera_degraded_map.schema.yml +42 -0
- simtools/schemas/model_parameters/camera_depth.schema.yml +42 -0
- simtools/schemas/model_parameters/camera_filter.schema.yml +45 -0
- simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +29 -0
- simtools/schemas/model_parameters/camera_pixels.schema.yml +36 -0
- simtools/schemas/model_parameters/camera_transmission.schema.yml +41 -0
- simtools/schemas/model_parameters/channels_per_chip.schema.yml +36 -0
- simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +35 -0
- simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +27 -0
- simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +38 -0
- simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +28 -0
- simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +23 -0
- simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +27 -0
- simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +28 -0
- simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +27 -0
- simtools/schemas/model_parameters/corsika_observation_level.schema.yml +38 -0
- simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +52 -0
- simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +27 -0
- simtools/schemas/model_parameters/dark_events.schema.yml +32 -0
- simtools/schemas/model_parameters/default_trigger.schema.yml +35 -0
- simtools/schemas/model_parameters/design_model.schema.yml +31 -0
- simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +32 -0
- simtools/schemas/model_parameters/disc_bins.schema.yml +39 -0
- simtools/schemas/model_parameters/disc_start.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +42 -0
- simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +39 -0
- simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +40 -0
- simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +33 -0
- simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +42 -0
- simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +37 -0
- simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +44 -0
- simtools/schemas/model_parameters/discriminator_threshold.schema.yml +36 -0
- simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +45 -0
- simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +40 -0
- simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +41 -0
- simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +38 -0
- simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +38 -0
- simtools/schemas/model_parameters/dish_shape_length.schema.yml +41 -0
- simtools/schemas/model_parameters/dsum_clipping.schema.yml +38 -0
- simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +38 -0
- simtools/schemas/model_parameters/dsum_offset.schema.yml +37 -0
- simtools/schemas/model_parameters/dsum_pedsub.schema.yml +33 -0
- simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +39 -0
- simtools/schemas/model_parameters/dsum_prescale.schema.yml +44 -0
- simtools/schemas/model_parameters/dsum_presum_max.schema.yml +38 -0
- simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +45 -0
- simtools/schemas/model_parameters/dsum_shaping.schema.yml +44 -0
- simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +32 -0
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +43 -0
- simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +42 -0
- simtools/schemas/model_parameters/effective_focal_length.schema.yml +61 -0
- simtools/schemas/model_parameters/epsg_code.schema.yml +37 -0
- simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +35 -0
- simtools/schemas/model_parameters/fadc_amplitude.schema.yml +46 -0
- simtools/schemas/model_parameters/fadc_bins.schema.yml +40 -0
- simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +50 -0
- simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +38 -0
- simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +49 -0
- simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +47 -0
- simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +51 -0
- simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +37 -0
- simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +49 -0
- simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +39 -0
- simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +40 -0
- simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +50 -0
- simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_max_signal.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_max_sum.schema.yml +39 -0
- simtools/schemas/model_parameters/fadc_mhz.schema.yml +31 -0
- simtools/schemas/model_parameters/fadc_noise.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_pedestal.schema.yml +40 -0
- simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +39 -0
- simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +50 -0
- simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +43 -0
- simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +42 -0
- simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +42 -0
- simtools/schemas/model_parameters/flatfielding.schema.yml +37 -0
- simtools/schemas/model_parameters/focal_length.schema.yml +45 -0
- simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +158 -0
- simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +29 -0
- simtools/schemas/model_parameters/focus_offset.schema.yml +66 -0
- simtools/schemas/model_parameters/gain_variation.schema.yml +43 -0
- simtools/schemas/model_parameters/geomag_horizontal.schema.yml +34 -0
- simtools/schemas/model_parameters/geomag_rotation.schema.yml +37 -0
- simtools/schemas/model_parameters/geomag_vertical.schema.yml +34 -0
- simtools/schemas/model_parameters/hg_lg_variation.schema.yml +36 -0
- simtools/schemas/model_parameters/iobuf_maximum.schema.yml +34 -0
- simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +34 -0
- simtools/schemas/model_parameters/laser_events.schema.yml +36 -0
- simtools/schemas/model_parameters/laser_external_trigger.schema.yml +35 -0
- simtools/schemas/model_parameters/laser_photons.schema.yml +32 -0
- simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +34 -0
- simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +34 -0
- simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +33 -0
- simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +33 -0
- simtools/schemas/model_parameters/laser_var_photons.schema.yml +33 -0
- simtools/schemas/model_parameters/laser_wavelength.schema.yml +33 -0
- simtools/schemas/model_parameters/led_events.schema.yml +34 -0
- simtools/schemas/model_parameters/led_photons.schema.yml +34 -0
- simtools/schemas/model_parameters/led_pulse_offset.schema.yml +32 -0
- simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +33 -0
- simtools/schemas/model_parameters/led_var_photons.schema.yml +34 -0
- simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +41 -0
- simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +43 -0
- simtools/schemas/model_parameters/min_photoelectrons.schema.yml +35 -0
- simtools/schemas/model_parameters/min_photons.schema.yml +32 -0
- simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +36 -0
- simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +64 -0
- simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +64 -0
- simtools/schemas/model_parameters/mirror_class.schema.yml +41 -0
- simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +51 -0
- simtools/schemas/model_parameters/mirror_focal_length.schema.yml +42 -0
- simtools/schemas/model_parameters/mirror_list.schema.yml +38 -0
- simtools/schemas/model_parameters/mirror_offset.schema.yml +41 -0
- simtools/schemas/model_parameters/mirror_panel_2f_measurements.schema.yml +39 -0
- simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +61 -0
- simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +40 -0
- simtools/schemas/model_parameters/multiplicity_offset.schema.yml +46 -0
- simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +51 -0
- simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +37 -0
- simtools/schemas/model_parameters/nsb_offaxis.schema.yml +79 -0
- simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +47 -0
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +34 -0
- simtools/schemas/model_parameters/nsb_reference_value.schema.yml +33 -0
- simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +35 -0
- simtools/schemas/model_parameters/nsb_skymap.schema.yml +39 -0
- simtools/schemas/model_parameters/nsb_spectrum.schema.yml +50 -0
- simtools/schemas/model_parameters/num_gains.schema.yml +34 -0
- simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +33 -0
- simtools/schemas/model_parameters/optics_properties.schema.yml +31 -0
- simtools/schemas/model_parameters/parabolic_dish.schema.yml +32 -0
- simtools/schemas/model_parameters/pedestal_events.schema.yml +32 -0
- simtools/schemas/model_parameters/photon_delay.schema.yml +38 -0
- simtools/schemas/model_parameters/photons_per_run.schema.yml +33 -0
- simtools/schemas/model_parameters/pixel_cells.schema.yml +35 -0
- simtools/schemas/model_parameters/pixels_parallel.schema.yml +54 -0
- simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +40 -0
- simtools/schemas/model_parameters/pm_average_gain.schema.yml +34 -0
- simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +40 -0
- simtools/schemas/model_parameters/pm_gain_index.schema.yml +36 -0
- simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +41 -0
- simtools/schemas/model_parameters/pm_transit_time.schema.yml +63 -0
- simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +39 -0
- simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +42 -0
- simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +33 -0
- simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +33 -0
- simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +29 -0
- simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +168 -0
- simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +36 -0
- simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +34 -0
- simtools/schemas/model_parameters/qe_variation.schema.yml +43 -0
- simtools/schemas/model_parameters/quantum_efficiency.schema.yml +42 -0
- simtools/schemas/model_parameters/random_focal_length.schema.yml +45 -0
- simtools/schemas/model_parameters/random_generator.schema.yml +36 -0
- simtools/schemas/model_parameters/reference_point_altitude.schema.yml +35 -0
- simtools/schemas/model_parameters/reference_point_latitude.schema.yml +36 -0
- simtools/schemas/model_parameters/reference_point_longitude.schema.yml +36 -0
- simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +34 -0
- simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +34 -0
- simtools/schemas/model_parameters/sampled_output.schema.yml +31 -0
- simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +34 -0
- simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +79 -0
- simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +42 -0
- simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +41 -0
- simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +33 -0
- simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +36 -0
- simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +29 -0
- simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +168 -0
- simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +36 -0
- simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +35 -0
- simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +37 -0
- simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +40 -0
- simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +40 -0
- simtools/schemas/model_parameters/store_photoelectrons.schema.yml +41 -0
- simtools/schemas/model_parameters/tailcut_scale.schema.yml +40 -0
- simtools/schemas/model_parameters/telescope_axis_height.schema.yml +31 -0
- simtools/schemas/model_parameters/telescope_random_angle.schema.yml +35 -0
- simtools/schemas/model_parameters/telescope_random_error.schema.yml +34 -0
- simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +37 -0
- simtools/schemas/model_parameters/telescope_transmission.schema.yml +113 -0
- simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +41 -0
- simtools/schemas/model_parameters/teltrig_min_time.schema.yml +36 -0
- simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +36 -0
- simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +37 -0
- simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +38 -0
- simtools/schemas/model_parameters/transit_time_error.schema.yml +45 -0
- simtools/schemas/model_parameters/transit_time_jitter.schema.yml +36 -0
- simtools/schemas/model_parameters/trigger_current_limit.schema.yml +32 -0
- simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +53 -0
- simtools/schemas/model_parameters/trigger_pixels.schema.yml +40 -0
- simtools/simtel/simtel_config_reader.py +353 -0
- simtools/simtel/simtel_config_writer.py +244 -63
- simtools/simtel/{simtel_events.py → simtel_io_events.py} +26 -25
- simtools/simtel/simtel_io_histogram.py +661 -0
- simtools/simtel/simtel_io_histograms.py +569 -0
- simtools/simtel/simulator_array.py +145 -0
- simtools/simtel/{simtel_runner_camera_efficiency.py → simulator_camera_efficiency.py} +76 -52
- simtools/simtel/simulator_light_emission.py +473 -0
- simtools/simtel/simulator_ray_tracing.py +262 -0
- simtools/simulator.py +220 -446
- simtools/testing/__init__.py +0 -0
- simtools/testing/assertions.py +151 -0
- simtools/testing/configuration.py +226 -0
- simtools/testing/helpers.py +42 -0
- simtools/testing/validate_output.py +240 -0
- simtools/utils/general.py +340 -437
- simtools/utils/geometry.py +12 -12
- simtools/utils/names.py +257 -644
- simtools/utils/value_conversion.py +176 -0
- simtools/version.py +3 -1
- simtools/visualization/legend_handlers.py +135 -152
- simtools/visualization/plot_camera.py +379 -0
- simtools/visualization/visualize.py +346 -167
- gammasimtools-0.6.1.dist-info/METADATA +0 -180
- gammasimtools-0.6.1.dist-info/RECORD +0 -91
- gammasimtools-0.6.1.dist-info/entry_points.txt +0 -23
- simtools/_dev_version/scm_version.py +0 -10
- simtools/applications/db_development_tools/add_new_parameter_to_db.py +0 -81
- simtools/applications/db_development_tools/add_unit_to_parameter_in_db.py +0 -59
- simtools/applications/db_development_tools/mark_non_optics_parameters_non_applicable.py +0 -102
- simtools/applications/get_parameter.py +0 -92
- simtools/applications/make_regular_arrays.py +0 -160
- simtools/applications/produce_array_config.py +0 -136
- simtools/applications/production.py +0 -313
- simtools/applications/sim_showers_for_trigger_rates.py +0 -187
- simtools/applications/tune_psf.py +0 -334
- simtools/corsika/corsika_default_config.py +0 -282
- simtools/corsika/corsika_runner.py +0 -450
- simtools/corsika_simtel/corsika_simtel_runner.py +0 -197
- simtools/db_handler.py +0 -1480
- simtools/ray_tracing.py +0 -525
- simtools/simtel/simtel_histograms.py +0 -414
- simtools/simtel/simtel_runner.py +0 -244
- simtools/simtel/simtel_runner_array.py +0 -293
- simtools/simtel/simtel_runner_ray_tracing.py +0 -277
- {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/LICENSE +0 -0
- {gammasimtools-0.6.1.dist-info → gammasimtools-0.8.2.dist-info}/top_level.txt +0 -0
- /simtools/{corsika_simtel → db}/__init__.py +0 -0
simtools/model/camera.py
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
|
+
"""Definition and modeling of camera."""
|
|
2
|
+
|
|
1
3
|
import logging
|
|
4
|
+
from pathlib import Path
|
|
2
5
|
|
|
3
6
|
import astropy.units as u
|
|
4
|
-
import matplotlib as mlp
|
|
5
|
-
import matplotlib.colors as mcolors
|
|
6
|
-
import matplotlib.patches as mpatches
|
|
7
|
-
import matplotlib.pyplot as plt
|
|
8
7
|
import numpy as np
|
|
9
|
-
from matplotlib.collections import PatchCollection
|
|
10
8
|
from scipy.spatial import cKDTree as KDTree
|
|
11
9
|
from scipy.spatial import distance
|
|
12
10
|
|
|
13
|
-
import simtools.visualization.legend_handlers as leg_h
|
|
14
|
-
from simtools.model.model_utils import is_two_mirror_telescope
|
|
15
|
-
from simtools.utils import names
|
|
16
11
|
from simtools.utils.geometry import rotate
|
|
17
12
|
|
|
18
13
|
__all__ = ["Camera"]
|
|
@@ -20,57 +15,59 @@ __all__ = ["Camera"]
|
|
|
20
15
|
|
|
21
16
|
class Camera:
|
|
22
17
|
"""
|
|
23
|
-
Camera class, defining pixel layout
|
|
24
|
-
|
|
18
|
+
Camera class, defining pixel layout.
|
|
19
|
+
|
|
20
|
+
This includes rotation, finding neighbor pixels, calculating FoV and plotting the camera.
|
|
25
21
|
|
|
26
22
|
Parameters
|
|
27
23
|
----------
|
|
28
|
-
telescope_model_name:
|
|
29
|
-
As provided by the telescope model method TelescopeModel (
|
|
30
|
-
camera_config_file:
|
|
24
|
+
telescope_model_name: str
|
|
25
|
+
As provided by the telescope model method TelescopeModel (e.g., LSTN-01)
|
|
26
|
+
camera_config_file: str or Path
|
|
31
27
|
The sim_telarray file name.
|
|
32
28
|
focal_length: float
|
|
33
29
|
The focal length of the camera in (preferably the effective focal length), assumed to be \
|
|
34
30
|
in the same unit as the pixel positions in the camera_config_file, usually cm.
|
|
35
31
|
"""
|
|
36
32
|
|
|
37
|
-
# Constants for finding
|
|
33
|
+
# Constants for finding neighbor pixels.
|
|
38
34
|
PMT_NEIGHBOR_RADIUS_FACTOR = 1.1
|
|
39
35
|
SIPM_NEIGHBOR_RADIUS_FACTOR = 1.4
|
|
40
36
|
SIPM_ROW_COLUMN_DIST_FACTOR = 0.2
|
|
41
37
|
|
|
42
|
-
def __init__(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
calculating FoV and plotting the camera.
|
|
38
|
+
def __init__(
|
|
39
|
+
self, telescope_model_name: str, camera_config_file: str | Path, focal_length: float
|
|
40
|
+
):
|
|
46
41
|
"""
|
|
42
|
+
Initialize Camera class, defining pixel layout.
|
|
47
43
|
|
|
44
|
+
This includes rotation, finding neighbor pixels, calculating FoV and plotting the camera.
|
|
45
|
+
"""
|
|
48
46
|
self._logger = logging.getLogger(__name__)
|
|
49
47
|
|
|
50
|
-
self.
|
|
51
|
-
_, self._camera_name, _ = names.split_telescope_model_name(telescope_model_name)
|
|
48
|
+
self.telescope_model_name = telescope_model_name
|
|
52
49
|
self._camera_config_file = camera_config_file
|
|
53
|
-
self.
|
|
54
|
-
if self.
|
|
50
|
+
self.focal_length = focal_length
|
|
51
|
+
if self.focal_length <= 0:
|
|
55
52
|
raise ValueError("The focal length must be larger than zero")
|
|
56
|
-
self.
|
|
53
|
+
self.pixels = self.read_pixel_list(camera_config_file)
|
|
57
54
|
|
|
58
|
-
self.
|
|
55
|
+
self.pixels = self._rotate_pixels(self.pixels)
|
|
59
56
|
|
|
60
|
-
# Initialize an empty list of
|
|
61
|
-
self.
|
|
57
|
+
# Initialize an empty list of neighbors, to be calculated only when necessary.
|
|
58
|
+
self._neighbors = None
|
|
62
59
|
|
|
63
60
|
# Initialize an empty list of edge pixels, to be calculated only when necessary.
|
|
64
61
|
self._edge_pixel_indices = None
|
|
65
62
|
|
|
66
63
|
@staticmethod
|
|
67
|
-
def read_pixel_list(camera_config_file):
|
|
64
|
+
def read_pixel_list(camera_config_file: str | Path) -> dict:
|
|
68
65
|
"""
|
|
69
66
|
Read the pixel layout from the camera config file, assumed to be in a sim_telarray format.
|
|
70
67
|
|
|
71
68
|
Parameters
|
|
72
69
|
----------
|
|
73
|
-
camera_config_file:
|
|
70
|
+
camera_config_file: str or Path
|
|
74
71
|
The sim_telarray file name.
|
|
75
72
|
|
|
76
73
|
Returns
|
|
@@ -85,65 +82,112 @@ class Camera:
|
|
|
85
82
|
The hexagonal shapes differ in their orientation, where those denoted as 3 are rotated
|
|
86
83
|
clockwise by 30 degrees with respect to those denoted as 1.
|
|
87
84
|
"""
|
|
85
|
+
pixels = Camera.initialize_pixel_dict()
|
|
88
86
|
|
|
89
|
-
|
|
90
|
-
pixels["pixel_diameter"] = 9999
|
|
91
|
-
pixels["pixel_shape"] = 9999
|
|
92
|
-
pixels["pixel_spacing"] = 9999
|
|
93
|
-
pixels["lightguide_efficiency_angle_file"] = "none"
|
|
94
|
-
pixels["lightguide_efficiency_wavelength_file"] = "none"
|
|
95
|
-
pixels["rotate_angle"] = 0
|
|
96
|
-
pixels["x"] = []
|
|
97
|
-
pixels["y"] = []
|
|
98
|
-
pixels["pix_id"] = []
|
|
99
|
-
pixels["pix_on"] = []
|
|
100
|
-
|
|
101
|
-
with open(camera_config_file, "r", encoding="utf-8") as dat_file:
|
|
87
|
+
with open(camera_config_file, encoding="utf-8") as dat_file:
|
|
102
88
|
for line in dat_file:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
89
|
+
Camera.process_line(line, pixels)
|
|
90
|
+
|
|
91
|
+
Camera.validate_pixels(pixels, camera_config_file)
|
|
92
|
+
|
|
93
|
+
return pixels
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def initialize_pixel_dict() -> dict:
|
|
97
|
+
"""
|
|
98
|
+
Initialize the pixel dictionary with default values.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
dict
|
|
103
|
+
A dictionary with default pixel properties.
|
|
104
|
+
"""
|
|
105
|
+
return {
|
|
106
|
+
"pixel_diameter": 9999,
|
|
107
|
+
"pixel_shape": 9999,
|
|
108
|
+
"pixel_spacing": 9999,
|
|
109
|
+
"lightguide_efficiency_angle_file": "none",
|
|
110
|
+
"lightguide_efficiency_wavelength_file": "none",
|
|
111
|
+
"rotate_angle": 0,
|
|
112
|
+
"x": [],
|
|
113
|
+
"y": [],
|
|
114
|
+
"pix_id": [],
|
|
115
|
+
"pix_on": [],
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def process_line(line: str, pixels: dict):
|
|
120
|
+
"""
|
|
121
|
+
Process a line from the camera config file and update the pixels dictionary.
|
|
127
122
|
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
line: str
|
|
126
|
+
A line from the camera config file.
|
|
127
|
+
pixels: dict
|
|
128
|
+
The dictionary to update with pixel information.
|
|
129
|
+
"""
|
|
130
|
+
pix_info = line.split()
|
|
131
|
+
|
|
132
|
+
if line.startswith("PixType"):
|
|
133
|
+
pixels["pixel_shape"] = int(pix_info[5].strip())
|
|
134
|
+
pixels["pixel_diameter"] = float(pix_info[6].strip())
|
|
135
|
+
pixels["lightguide_efficiency_angle_file"] = pix_info[8].strip().replace('"', "")
|
|
136
|
+
|
|
137
|
+
if len(pix_info) > 9:
|
|
138
|
+
pixels["lightguide_efficiency_wavelength_file"] = (
|
|
139
|
+
pix_info[9].strip().replace('"', "")
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
elif line.startswith("Rotate"):
|
|
143
|
+
pixels["rotate_angle"] = np.deg2rad(float(pix_info[1].strip()))
|
|
144
|
+
|
|
145
|
+
elif line.startswith("Pixel"):
|
|
146
|
+
pixels["x"].append(float(pix_info[3].strip()))
|
|
147
|
+
pixels["y"].append(float(pix_info[4].strip()))
|
|
148
|
+
pixels["pix_id"].append(int(pix_info[1].strip()))
|
|
149
|
+
|
|
150
|
+
if len(pix_info) > 9:
|
|
151
|
+
pixels["pix_on"].append(int(pix_info[9].strip()) != 0)
|
|
152
|
+
else:
|
|
153
|
+
pixels["pix_on"].append(True)
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
def validate_pixels(pixels: dict, camera_config_file: str | Path):
|
|
157
|
+
"""
|
|
158
|
+
Validate the pixel dictionary to ensure all required fields are present.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
pixels: dict
|
|
163
|
+
The pixel dictionary to validate.
|
|
164
|
+
camera_config_file: string
|
|
165
|
+
The sim_telarray file name for error messages.
|
|
166
|
+
|
|
167
|
+
Raises
|
|
168
|
+
------
|
|
169
|
+
ValueError
|
|
170
|
+
If the pixel diameter or pixel shape is invalid.
|
|
171
|
+
"""
|
|
128
172
|
if pixels["pixel_diameter"] == 9999:
|
|
129
173
|
raise ValueError(f"Could not read the pixel diameter from {camera_config_file} file")
|
|
174
|
+
|
|
130
175
|
if pixels["pixel_shape"] not in [1, 2, 3]:
|
|
131
176
|
raise ValueError(
|
|
132
177
|
f"Pixel shape in {camera_config_file} unrecognized (has to be 1, 2 or 3)"
|
|
133
178
|
)
|
|
134
179
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def _rotate_pixels(self, pixels):
|
|
180
|
+
def _rotate_pixels(self, pixels: dict) -> dict:
|
|
138
181
|
"""
|
|
139
182
|
Rotate the pixels according to the rotation angle given in pixels['rotate_angle'].
|
|
183
|
+
|
|
140
184
|
Additional rotation is added to get to the camera view of an observer facing the camera.
|
|
141
185
|
The angle for the axes rotation depends on the coordinate system in which the original
|
|
142
186
|
data was provided.
|
|
143
187
|
|
|
144
188
|
Parameters
|
|
145
189
|
----------
|
|
146
|
-
pixels:
|
|
190
|
+
pixels: dict
|
|
147
191
|
The dictionary produced by the read_pixel_list method of this class
|
|
148
192
|
|
|
149
193
|
Returns
|
|
@@ -153,7 +197,6 @@ class Camera:
|
|
|
153
197
|
The pixels orientation for plotting is added to the dictionary in pixels['orientation'].
|
|
154
198
|
The orientation is determined by the pixel shape (see read_pixel_list for details).
|
|
155
199
|
"""
|
|
156
|
-
|
|
157
200
|
rotate_angle = pixels["rotate_angle"] * u.rad # So not to change the original angle
|
|
158
201
|
# The original pixel list is given such that
|
|
159
202
|
# x -> North, y -> West, z -> Up in the ground system.
|
|
@@ -179,19 +222,18 @@ class Camera:
|
|
|
179
222
|
|
|
180
223
|
return pixels
|
|
181
224
|
|
|
182
|
-
def get_number_of_pixels(self):
|
|
225
|
+
def get_number_of_pixels(self) -> int:
|
|
183
226
|
"""
|
|
184
|
-
Get the number of pixels in the camera (all pixels, including those defined as "off".
|
|
227
|
+
Get the number of pixels in the camera (all pixels, including those defined as "off").
|
|
185
228
|
|
|
186
229
|
Returns
|
|
187
230
|
-------
|
|
188
231
|
int
|
|
189
232
|
number of pixels.
|
|
190
233
|
"""
|
|
234
|
+
return len(self.pixels["x"])
|
|
191
235
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
def get_pixel_diameter(self):
|
|
236
|
+
def get_pixel_diameter(self) -> float:
|
|
195
237
|
"""
|
|
196
238
|
Get pixel diameter contained in _pixels.
|
|
197
239
|
|
|
@@ -200,10 +242,9 @@ class Camera:
|
|
|
200
242
|
float
|
|
201
243
|
Pixel diameter (usually in cm).
|
|
202
244
|
"""
|
|
245
|
+
return self.pixels["pixel_diameter"]
|
|
203
246
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
def get_pixel_active_solid_angle(self):
|
|
247
|
+
def get_pixel_active_solid_angle(self) -> float:
|
|
207
248
|
"""
|
|
208
249
|
Get the active solid angle of a pixel in sr.
|
|
209
250
|
|
|
@@ -212,16 +253,17 @@ class Camera:
|
|
|
212
253
|
float
|
|
213
254
|
active solid angle of a pixel in sr.
|
|
214
255
|
"""
|
|
215
|
-
|
|
216
256
|
pixel_area = self.get_pixel_diameter() ** 2
|
|
217
257
|
# In case we have hexagonal pixels:
|
|
218
258
|
if self.get_pixel_shape() == 1 or self.get_pixel_shape() == 3:
|
|
219
259
|
pixel_area *= np.sqrt(3) / 2
|
|
220
|
-
return pixel_area / (self.
|
|
260
|
+
return pixel_area / (self.focal_length**2)
|
|
221
261
|
|
|
222
|
-
def get_pixel_shape(self):
|
|
262
|
+
def get_pixel_shape(self) -> int:
|
|
223
263
|
"""
|
|
224
|
-
Get pixel shape code 1, 2 or 3
|
|
264
|
+
Get pixel shape code 1, 2 or 3.
|
|
265
|
+
|
|
266
|
+
Where 1 and 3 are hexagonal pixels, where one is rotated by\
|
|
225
267
|
30 degrees with respect to the other. A square pixel is denoted as 2.
|
|
226
268
|
|
|
227
269
|
Returns
|
|
@@ -229,9 +271,9 @@ class Camera:
|
|
|
229
271
|
int (1, 2 or 3)
|
|
230
272
|
Pixel shape.
|
|
231
273
|
"""
|
|
232
|
-
return self.
|
|
274
|
+
return self.pixels["pixel_shape"]
|
|
233
275
|
|
|
234
|
-
def get_lightguide_efficiency_angle_file_name(self):
|
|
276
|
+
def get_lightguide_efficiency_angle_file_name(self) -> str:
|
|
235
277
|
"""
|
|
236
278
|
Get the file name of the light guide efficiency as a function of incidence angle.
|
|
237
279
|
|
|
@@ -240,10 +282,9 @@ class Camera:
|
|
|
240
282
|
str
|
|
241
283
|
File name of the light guide efficiency as a function of incidence angle.
|
|
242
284
|
"""
|
|
285
|
+
return self.pixels["lightguide_efficiency_angle_file"]
|
|
243
286
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
def get_lightguide_efficiency_wavelength_file_name(self):
|
|
287
|
+
def get_lightguide_efficiency_wavelength_file_name(self) -> str:
|
|
247
288
|
"""
|
|
248
289
|
Get the file name of the light guide efficiency as a function of wavelength.
|
|
249
290
|
|
|
@@ -252,26 +293,28 @@ class Camera:
|
|
|
252
293
|
str
|
|
253
294
|
File name of the light guide efficiency as a function of wavelength.
|
|
254
295
|
"""
|
|
255
|
-
return self.
|
|
296
|
+
return self.pixels["lightguide_efficiency_wavelength_file"]
|
|
256
297
|
|
|
257
|
-
def get_camera_fill_factor(self):
|
|
298
|
+
def get_camera_fill_factor(self) -> float:
|
|
258
299
|
"""
|
|
259
|
-
Calculate the fill factor of the camera, defined as (pixel_diameter/pixel_spacing)**2
|
|
300
|
+
Calculate the fill factor of the camera, defined as (pixel_diameter/pixel_spacing)**2.
|
|
260
301
|
|
|
261
302
|
Returns
|
|
262
303
|
-------
|
|
263
304
|
float
|
|
264
305
|
The camera fill factor.
|
|
265
306
|
"""
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
points = np.array([self._pixels["x"], self._pixels["y"]]).T
|
|
307
|
+
if self.pixels["pixel_spacing"] == 9999:
|
|
308
|
+
points = np.array([self.pixels["x"], self.pixels["y"]]).T
|
|
269
309
|
pixel_distances = distance.cdist(points, points, "euclidean")
|
|
270
|
-
|
|
310
|
+
# pylint: disable=unsubscriptable-object
|
|
311
|
+
pixel_distances = pixel_distances[pixel_distances > 0]
|
|
312
|
+
pixel_spacing = np.min(pixel_distances)
|
|
313
|
+
self.pixels["pixel_spacing"] = pixel_spacing
|
|
271
314
|
|
|
272
|
-
return (self.
|
|
315
|
+
return (self.pixels["pixel_diameter"] / self.pixels["pixel_spacing"]) ** 2
|
|
273
316
|
|
|
274
|
-
def calc_fov(self):
|
|
317
|
+
def calc_fov(self) -> tuple[float, float]:
|
|
275
318
|
"""
|
|
276
319
|
Calculate the FOV of the camera in degrees, taking into account the focal length.
|
|
277
320
|
|
|
@@ -286,17 +329,21 @@ class Camera:
|
|
|
286
329
|
-----
|
|
287
330
|
The x,y pixel positions and focal length are assumed to have the same unit (usually cm)
|
|
288
331
|
"""
|
|
289
|
-
|
|
290
332
|
self._logger.debug("Calculating the FoV")
|
|
291
|
-
|
|
292
333
|
return self._calc_fov(
|
|
293
|
-
self.
|
|
294
|
-
self.
|
|
334
|
+
self.pixels["x"],
|
|
335
|
+
self.pixels["y"],
|
|
295
336
|
self.get_edge_pixels(),
|
|
296
|
-
self.
|
|
337
|
+
self.focal_length,
|
|
297
338
|
)
|
|
298
339
|
|
|
299
|
-
def _calc_fov(
|
|
340
|
+
def _calc_fov(
|
|
341
|
+
self,
|
|
342
|
+
x_pixel: list[float],
|
|
343
|
+
y_pixel: list[float],
|
|
344
|
+
edge_pixel_indices: list[int],
|
|
345
|
+
focal_length: float,
|
|
346
|
+
) -> tuple[float, float]:
|
|
300
347
|
"""
|
|
301
348
|
Calculate the FOV of the camera in degrees, taking into account the focal length.
|
|
302
349
|
|
|
@@ -323,7 +370,6 @@ class Camera:
|
|
|
323
370
|
-----
|
|
324
371
|
The x,y pixel positions and focal length are assumed to have the same unit (usually cm)
|
|
325
372
|
"""
|
|
326
|
-
|
|
327
373
|
self._logger.debug("Calculating the FoV")
|
|
328
374
|
|
|
329
375
|
average_edge_distance = 0
|
|
@@ -336,10 +382,11 @@ class Camera:
|
|
|
336
382
|
return fov, average_edge_distance
|
|
337
383
|
|
|
338
384
|
@staticmethod
|
|
339
|
-
def
|
|
385
|
+
def _find_neighbors(x_pos: np.ndarray, y_pos: np.ndarray, radius: float) -> list[list[int]]:
|
|
340
386
|
"""
|
|
341
|
-
|
|
342
|
-
|
|
387
|
+
Use a KD-Tree to quickly find nearest neighbors.
|
|
388
|
+
|
|
389
|
+
This applies to e.g., of the pixels in a camera or mirror facets.
|
|
343
390
|
|
|
344
391
|
Parameters
|
|
345
392
|
----------
|
|
@@ -348,96 +395,120 @@ class Camera:
|
|
|
348
395
|
y_pos : numpy.array_like
|
|
349
396
|
y position of each e.g., pixel
|
|
350
397
|
radius : float
|
|
351
|
-
radius to consider
|
|
398
|
+
radius to consider neighbor it should be slightly larger than the pixel diameter or \
|
|
352
399
|
mirror facet.
|
|
353
400
|
|
|
354
401
|
Returns
|
|
355
402
|
-------
|
|
356
|
-
|
|
357
|
-
Array of
|
|
403
|
+
list of lists
|
|
404
|
+
Array of neighbor indices in a list for each pixel
|
|
358
405
|
"""
|
|
406
|
+
tree = KDTree(np.column_stack([x_pos, y_pos]))
|
|
407
|
+
neighbors = tree.query_ball_tree(tree, radius)
|
|
408
|
+
return [list(np.setdiff1d(neigh, [i])) for i, neigh in enumerate(neighbors)]
|
|
359
409
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
neighbours = [kdtree.query_ball_point(p, r=radius) for p in points]
|
|
364
|
-
|
|
365
|
-
for neighbour_now, index_now in zip(neighbours, indices):
|
|
366
|
-
neighbour_now.remove(index_now) # get rid of the pixel or mirror itself
|
|
367
|
-
|
|
368
|
-
return neighbours
|
|
369
|
-
|
|
370
|
-
def _find_adjacent_neighbour_pixels(self, x_pos, y_pos, radius, row_coloumn_dist):
|
|
410
|
+
def _find_adjacent_neighbor_pixels(
|
|
411
|
+
self, x_pos: np.ndarray, y_pos: np.ndarray, radius: float, row_column_dist: float
|
|
412
|
+
) -> list[list[int]]:
|
|
371
413
|
"""
|
|
372
|
-
Find adjacent
|
|
373
|
-
|
|
414
|
+
Find adjacent neighbor pixels in cameras with square pixels.
|
|
415
|
+
|
|
416
|
+
Only directly adjacent neighbors are allowed, no diagonals.
|
|
374
417
|
|
|
375
418
|
Parameters
|
|
376
419
|
----------
|
|
377
|
-
x_pos
|
|
420
|
+
x_pos: np.ndarray
|
|
378
421
|
x position of each pixel
|
|
379
|
-
y_pos
|
|
380
|
-
y position of each
|
|
381
|
-
radius
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
neighbour. Should be around 20% of the pixel diameter.
|
|
422
|
+
y_pos: np.ndarray
|
|
423
|
+
y position of each pixel
|
|
424
|
+
radius: float
|
|
425
|
+
Radius within which to find neighbors
|
|
426
|
+
row_column_dist: float
|
|
427
|
+
Distance to consider for row/column adjacency.
|
|
428
|
+
Should be around 20% of the pixel diameter.
|
|
387
429
|
|
|
388
430
|
Returns
|
|
389
431
|
-------
|
|
390
|
-
|
|
391
|
-
Array of
|
|
432
|
+
list of lists
|
|
433
|
+
Array of neighbor indices in a list for each pixel
|
|
392
434
|
"""
|
|
435
|
+
# First find the neighbors with the usual method and the original radius
|
|
436
|
+
# which does not allow for diagonal neighbors.
|
|
437
|
+
neighbors = self._find_neighbors(x_pos, y_pos, radius)
|
|
393
438
|
|
|
394
|
-
|
|
395
|
-
# which does not allow for diagonal neighbours.
|
|
396
|
-
neighbours = self._find_neighbours(x_pos, y_pos, radius)
|
|
397
|
-
for i_pix, nn in enumerate(neighbours):
|
|
439
|
+
for i_pix, nn in enumerate(neighbors):
|
|
398
440
|
# Find pixels defined as edge pixels now
|
|
399
441
|
if len(nn) < 4:
|
|
400
442
|
# Go over all other pixels and search for ones which are adjacent
|
|
401
443
|
# but further than sqrt(2) away
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
444
|
+
self._add_additional_neighbors(i_pix, nn, x_pos, y_pos, radius, row_column_dist)
|
|
445
|
+
|
|
446
|
+
return neighbors
|
|
447
|
+
|
|
448
|
+
def _add_additional_neighbors(
|
|
449
|
+
self,
|
|
450
|
+
i_pix: int,
|
|
451
|
+
nn: list[int],
|
|
452
|
+
x_pos: np.ndarray,
|
|
453
|
+
y_pos: np.ndarray,
|
|
454
|
+
radius: float,
|
|
455
|
+
row_column_dist: float,
|
|
456
|
+
):
|
|
457
|
+
"""
|
|
458
|
+
Add neighbors for a given pixel if they are not already neighbors and are adjacent.
|
|
459
|
+
|
|
460
|
+
Parameters
|
|
461
|
+
----------
|
|
462
|
+
i_pix: int
|
|
463
|
+
Index of the pixel to find neighbors for
|
|
464
|
+
nn: list
|
|
465
|
+
Current list of neighbors for the pixel
|
|
466
|
+
x_pos: np.ndarray
|
|
467
|
+
x position of each pixel
|
|
468
|
+
y_pos: np.ndarray
|
|
469
|
+
y position of each pixel
|
|
470
|
+
radius: float
|
|
471
|
+
Radius within which to find neighbors
|
|
472
|
+
row_column_dist: float
|
|
473
|
+
Distance to consider for row/column adjacency
|
|
474
|
+
"""
|
|
475
|
+
for j_pix, _ in enumerate(x_pos):
|
|
476
|
+
# No need to look at the pixel itself
|
|
477
|
+
# nor at any pixels already in the neighbors list
|
|
478
|
+
if j_pix != i_pix and j_pix not in nn:
|
|
479
|
+
dist = np.sqrt(
|
|
480
|
+
(x_pos[i_pix] - x_pos[j_pix]) ** 2 + (y_pos[i_pix] - y_pos[j_pix]) ** 2
|
|
481
|
+
)
|
|
482
|
+
# Check if this pixel is in the same row or column
|
|
483
|
+
# and allow it to be ~1.68*diameter away (1.4*1.2 = 1.68)
|
|
484
|
+
# Need to increase the distance because of the curvature
|
|
485
|
+
# of the CHEC camera
|
|
486
|
+
if (
|
|
487
|
+
abs(x_pos[i_pix] - x_pos[j_pix]) < row_column_dist
|
|
488
|
+
or abs(y_pos[i_pix] - y_pos[j_pix]) < row_column_dist
|
|
489
|
+
) and dist < 1.2 * radius:
|
|
490
|
+
nn.append(j_pix)
|
|
491
|
+
|
|
492
|
+
def _calc_neighbor_pixels(self, pixels: dict) -> list[list[int]]:
|
|
493
|
+
"""
|
|
494
|
+
Find adjacent neighbor pixels in cameras with hexagonal or square pixels.
|
|
495
|
+
|
|
496
|
+
Only directly adjacent neighbors are searched for, no diagonals.
|
|
425
497
|
|
|
426
498
|
Parameters
|
|
427
499
|
----------
|
|
428
|
-
pixels:
|
|
500
|
+
pixels: dict
|
|
429
501
|
The dictionary produced by the read_pixel_list method of this class
|
|
430
502
|
|
|
431
503
|
Returns
|
|
432
504
|
-------
|
|
433
|
-
|
|
434
|
-
Array of
|
|
505
|
+
neighbors: list of lists
|
|
506
|
+
Array of neighbor indices in a list for each pixel
|
|
435
507
|
"""
|
|
436
|
-
|
|
437
|
-
self._logger.debug("Searching for neighbour pixels")
|
|
508
|
+
self._logger.debug("Searching for neighbor pixels")
|
|
438
509
|
|
|
439
510
|
if pixels["pixel_shape"] == 1 or pixels["pixel_shape"] == 3:
|
|
440
|
-
self.
|
|
511
|
+
self._neighbors = self._find_neighbors(
|
|
441
512
|
pixels["x"],
|
|
442
513
|
pixels["y"],
|
|
443
514
|
self.PMT_NEIGHBOR_RADIUS_FACTOR * pixels["pixel_diameter"],
|
|
@@ -445,21 +516,22 @@ class Camera:
|
|
|
445
516
|
elif pixels["pixel_shape"] == 2:
|
|
446
517
|
# Distance increased by 40% to take into account gaps in the SiPM cameras
|
|
447
518
|
# Pixels in the same row/column can be 20% shifted from one another
|
|
448
|
-
# Inside
|
|
519
|
+
# Inside find_adjacent_neighbor_pixels the distance is increased
|
|
449
520
|
# further for pixels in the same row/column to 1.68*diameter.
|
|
450
|
-
self.
|
|
521
|
+
self._neighbors = self._find_adjacent_neighbor_pixels(
|
|
451
522
|
pixels["x"],
|
|
452
523
|
pixels["y"],
|
|
453
524
|
self.SIPM_NEIGHBOR_RADIUS_FACTOR * pixels["pixel_diameter"],
|
|
454
525
|
self.SIPM_ROW_COLUMN_DIST_FACTOR * pixels["pixel_diameter"],
|
|
455
526
|
)
|
|
456
527
|
|
|
457
|
-
return self.
|
|
528
|
+
return self._neighbors
|
|
458
529
|
|
|
459
|
-
def
|
|
530
|
+
def get_neighbor_pixels(self, pixels: dict | None = None) -> list[list[int]]:
|
|
460
531
|
"""
|
|
461
|
-
Get a list of
|
|
462
|
-
|
|
532
|
+
Get a list of neighbor pixels by calling calc_neighbor_pixels() when necessary.
|
|
533
|
+
|
|
534
|
+
The purpose of this function is to ensure the calculation occurs only once and only when
|
|
463
535
|
necessary.
|
|
464
536
|
|
|
465
537
|
Parameters
|
|
@@ -469,51 +541,54 @@ class Camera:
|
|
|
469
541
|
|
|
470
542
|
Returns
|
|
471
543
|
-------
|
|
472
|
-
|
|
473
|
-
Array of
|
|
544
|
+
neighbors: list of lists
|
|
545
|
+
Array of neighbor indices in a list for each pixel.
|
|
474
546
|
"""
|
|
475
|
-
|
|
476
|
-
if self._neighbours is None:
|
|
547
|
+
if self._neighbors is None:
|
|
477
548
|
if pixels is None:
|
|
478
|
-
pixels = self.
|
|
479
|
-
return self.
|
|
549
|
+
pixels = self.pixels
|
|
550
|
+
return self._calc_neighbor_pixels(pixels)
|
|
480
551
|
|
|
481
|
-
return self.
|
|
552
|
+
return self._neighbors
|
|
482
553
|
|
|
483
|
-
def _calc_edge_pixels(self, pixels,
|
|
554
|
+
def _calc_edge_pixels(self, pixels: dict, neighbors: list[list[int]]) -> list[int]:
|
|
484
555
|
"""
|
|
485
556
|
Find the edge pixels of the camera.
|
|
486
557
|
|
|
487
558
|
Parameters
|
|
488
559
|
----------
|
|
489
|
-
pixels:
|
|
560
|
+
pixels: dict
|
|
490
561
|
The dictionary produced by the read_pixel_list method of this class.
|
|
491
|
-
|
|
492
|
-
Array of
|
|
562
|
+
neighbors: list of lists
|
|
563
|
+
Array of neighbor indices in a list for each pixel.
|
|
493
564
|
|
|
494
565
|
Returns
|
|
495
566
|
-------
|
|
496
|
-
edge_pixel_indices:
|
|
567
|
+
edge_pixel_indices: list
|
|
497
568
|
Array of edge pixel indices.
|
|
498
569
|
"""
|
|
499
|
-
|
|
500
570
|
self._logger.debug("Searching for edge pixels")
|
|
501
|
-
|
|
502
571
|
edge_pixel_indices = []
|
|
503
572
|
|
|
573
|
+
def is_edge_pixel(i_pix):
|
|
574
|
+
pixel_shape = pixels["pixel_shape"]
|
|
575
|
+
pix_on = pixels["pix_on"][i_pix]
|
|
576
|
+
num_neighbors = len(neighbors[i_pix])
|
|
577
|
+
|
|
578
|
+
shape_condition = (pixel_shape in [1, 3] and num_neighbors < 6) or (
|
|
579
|
+
pixel_shape == 2 and num_neighbors < 4
|
|
580
|
+
)
|
|
581
|
+
return pix_on and shape_condition
|
|
582
|
+
|
|
504
583
|
for i_pix, _ in enumerate(pixels["x"]):
|
|
505
|
-
if
|
|
506
|
-
|
|
507
|
-
if len(neighbours[i_pix]) < 6:
|
|
508
|
-
edge_pixel_indices.append(i_pix)
|
|
509
|
-
elif pixels["pixel_shape"] == 2:
|
|
510
|
-
if pixels["pix_on"][i_pix]:
|
|
511
|
-
if len(neighbours[i_pix]) < 4:
|
|
512
|
-
edge_pixel_indices.append(i_pix)
|
|
584
|
+
if is_edge_pixel(i_pix):
|
|
585
|
+
edge_pixel_indices.append(i_pix)
|
|
513
586
|
|
|
514
587
|
return edge_pixel_indices
|
|
515
588
|
|
|
516
|
-
def get_edge_pixels(
|
|
589
|
+
def get_edge_pixels(
|
|
590
|
+
self, pixels: dict | None = None, neighbors: list[list[int]] | None = None
|
|
591
|
+
) -> list[int]:
|
|
517
592
|
"""
|
|
518
593
|
Get the indices of the edge pixels of the camera.
|
|
519
594
|
|
|
@@ -521,340 +596,19 @@ class Camera:
|
|
|
521
596
|
----------
|
|
522
597
|
pixels: dict
|
|
523
598
|
The dictionary produced by the read_pixel_list method of this class.
|
|
524
|
-
|
|
525
|
-
Array of
|
|
599
|
+
neighbors: list of lists
|
|
600
|
+
Array of neighbor indices in a list for each pixel.
|
|
526
601
|
|
|
527
602
|
Returns
|
|
528
603
|
-------
|
|
529
|
-
edge_pixel_indices:
|
|
604
|
+
edge_pixel_indices: list
|
|
530
605
|
Array of edge pixel indices.
|
|
531
606
|
"""
|
|
532
|
-
|
|
533
607
|
if self._edge_pixel_indices is None:
|
|
534
608
|
if pixels is None:
|
|
535
|
-
pixels = self.
|
|
536
|
-
if
|
|
537
|
-
|
|
538
|
-
return self._calc_edge_pixels(pixels,
|
|
609
|
+
pixels = self.pixels
|
|
610
|
+
if neighbors is None:
|
|
611
|
+
neighbors = self.get_neighbor_pixels()
|
|
612
|
+
return self._calc_edge_pixels(pixels, neighbors)
|
|
539
613
|
|
|
540
614
|
return self._edge_pixel_indices
|
|
541
|
-
|
|
542
|
-
def _plot_axes_def(self, plot, rotate_angle):
|
|
543
|
-
"""
|
|
544
|
-
Plot three axes definitions on the pyplot.plt instance provided. The three axes are Alt/Az,\
|
|
545
|
-
the camera coordinate system and the original coordinate system the pixel list was provided.
|
|
546
|
-
|
|
547
|
-
Parameters
|
|
548
|
-
----------
|
|
549
|
-
plot: pyplot.plt instance
|
|
550
|
-
A pyplot.plt instance where to add the axes definitions.
|
|
551
|
-
rotate_angle: float
|
|
552
|
-
The rotation angle applied
|
|
553
|
-
"""
|
|
554
|
-
|
|
555
|
-
invert_yaxis = False
|
|
556
|
-
x_left = 0.7 # Position of the left most axis
|
|
557
|
-
if not is_two_mirror_telescope(self._telescope_model_name):
|
|
558
|
-
invert_yaxis = True
|
|
559
|
-
x_left = 0.8
|
|
560
|
-
|
|
561
|
-
x_title = r"$x_{\!pix}$"
|
|
562
|
-
y_title = r"$y_{\!pix}$"
|
|
563
|
-
x_pos, y_pos = (x_left, 0.12)
|
|
564
|
-
# The rotation of LST (above 100 degrees) raises the axes.
|
|
565
|
-
# In this case, lower the starting point.
|
|
566
|
-
if np.rad2deg(rotate_angle) > 100:
|
|
567
|
-
y_pos -= 0.09
|
|
568
|
-
x_pos -= 0.05
|
|
569
|
-
kwargs = {
|
|
570
|
-
"x_title": x_title,
|
|
571
|
-
"y_title": y_title,
|
|
572
|
-
"x_pos": x_pos,
|
|
573
|
-
"y_pos": y_pos,
|
|
574
|
-
"rotate_angle": rotate_angle - (1 / 2.0) * np.pi,
|
|
575
|
-
"fc": "black",
|
|
576
|
-
"ec": "black",
|
|
577
|
-
"invert_yaxis": invert_yaxis,
|
|
578
|
-
}
|
|
579
|
-
self._plot_one_axis_def(plot, **kwargs)
|
|
580
|
-
|
|
581
|
-
x_title = r"$x_{\!cam}$"
|
|
582
|
-
y_title = r"$y_{\!cam}$"
|
|
583
|
-
x_pos, y_pos = (x_left + 0.15, 0.12)
|
|
584
|
-
kwargs = {
|
|
585
|
-
"x_title": x_title,
|
|
586
|
-
"y_title": y_title,
|
|
587
|
-
"x_pos": x_pos,
|
|
588
|
-
"y_pos": y_pos,
|
|
589
|
-
"rotate_angle": (3 / 2.0) * np.pi,
|
|
590
|
-
"fc": "blue",
|
|
591
|
-
"ec": "blue",
|
|
592
|
-
"invert_yaxis": invert_yaxis,
|
|
593
|
-
}
|
|
594
|
-
self._plot_one_axis_def(plot, **kwargs)
|
|
595
|
-
|
|
596
|
-
x_title = "Alt"
|
|
597
|
-
y_title = "Az"
|
|
598
|
-
x_pos, y_pos = (x_left + 0.15, 0.25)
|
|
599
|
-
kwargs = {
|
|
600
|
-
"x_title": x_title,
|
|
601
|
-
"y_title": y_title,
|
|
602
|
-
"x_pos": x_pos,
|
|
603
|
-
"y_pos": y_pos,
|
|
604
|
-
"rotate_angle": (3 / 2.0) * np.pi,
|
|
605
|
-
"fc": "red",
|
|
606
|
-
"ec": "red",
|
|
607
|
-
"invert_yaxis": invert_yaxis,
|
|
608
|
-
}
|
|
609
|
-
self._plot_one_axis_def(plot, **kwargs)
|
|
610
|
-
|
|
611
|
-
@staticmethod
|
|
612
|
-
def _plot_one_axis_def(plot, **kwargs):
|
|
613
|
-
"""
|
|
614
|
-
Plot an axis on the pyplot.plt instance provided.
|
|
615
|
-
|
|
616
|
-
Parameters
|
|
617
|
-
----------
|
|
618
|
-
plot: pyplot.plt instance
|
|
619
|
-
A pyplot.plt instance where to add the axes definitions.
|
|
620
|
-
**kwargs: dict
|
|
621
|
-
x_title: str
|
|
622
|
-
x-axis title
|
|
623
|
-
y_title: str
|
|
624
|
-
y-axis title,
|
|
625
|
-
x_pos: float
|
|
626
|
-
x position of the axis to draw
|
|
627
|
-
y_pos: float
|
|
628
|
-
y position of the axis to draw
|
|
629
|
-
rotate_angle: float
|
|
630
|
-
rotation angle of the axis in radians
|
|
631
|
-
fc: str
|
|
632
|
-
face colour of the axis
|
|
633
|
-
ec: str
|
|
634
|
-
edge colour of the axis
|
|
635
|
-
invert_yaxis: bool
|
|
636
|
-
Flag to invert the y-axis (for dual mirror telescopes).
|
|
637
|
-
"""
|
|
638
|
-
|
|
639
|
-
x_title = kwargs["x_title"]
|
|
640
|
-
y_title = kwargs["y_title"]
|
|
641
|
-
x_pos, y_pos = (kwargs["x_pos"], kwargs["y_pos"])
|
|
642
|
-
|
|
643
|
-
r = 0.1 # size of arrow
|
|
644
|
-
sign = 1.0
|
|
645
|
-
if kwargs["invert_yaxis"]:
|
|
646
|
-
sign *= -1.0
|
|
647
|
-
x_text1 = x_pos + sign * r * np.cos(kwargs["rotate_angle"])
|
|
648
|
-
y_text1 = y_pos + r * np.sin(0 + kwargs["rotate_angle"])
|
|
649
|
-
x_text2 = x_pos + sign * r * np.cos(np.pi / 2.0 + kwargs["rotate_angle"])
|
|
650
|
-
y_text2 = y_pos + r * np.sin(np.pi / 2.0 + kwargs["rotate_angle"])
|
|
651
|
-
|
|
652
|
-
plot.gca().annotate(
|
|
653
|
-
x_title,
|
|
654
|
-
xy=(x_pos, y_pos),
|
|
655
|
-
xytext=(x_text1, y_text1),
|
|
656
|
-
xycoords="axes fraction",
|
|
657
|
-
ha="center",
|
|
658
|
-
va="center",
|
|
659
|
-
size="xx-large",
|
|
660
|
-
arrowprops={
|
|
661
|
-
"arrowstyle": "<|-",
|
|
662
|
-
"shrinkA": 0,
|
|
663
|
-
"shrinkB": 0,
|
|
664
|
-
"fc": kwargs["fc"],
|
|
665
|
-
"ec": kwargs["ec"],
|
|
666
|
-
},
|
|
667
|
-
)
|
|
668
|
-
|
|
669
|
-
plot.gca().annotate(
|
|
670
|
-
y_title,
|
|
671
|
-
xy=(x_pos, y_pos),
|
|
672
|
-
xytext=(x_text2, y_text2),
|
|
673
|
-
xycoords="axes fraction",
|
|
674
|
-
ha="center",
|
|
675
|
-
va="center",
|
|
676
|
-
size="xx-large",
|
|
677
|
-
arrowprops={
|
|
678
|
-
"arrowstyle": "<|-",
|
|
679
|
-
"shrinkA": 0,
|
|
680
|
-
"shrinkB": 0,
|
|
681
|
-
"fc": kwargs["fc"],
|
|
682
|
-
"ec": kwargs["ec"],
|
|
683
|
-
},
|
|
684
|
-
)
|
|
685
|
-
|
|
686
|
-
def plot_pixel_layout(self, camera_in_sky_coor=False, pixels_id_to_print=50):
|
|
687
|
-
"""
|
|
688
|
-
Plot the pixel layout for an observer facing the camera. Including in the plot edge pixels,\
|
|
689
|
-
off pixels, pixel ID for the first 50 pixels, coordinate systems, FOV, focal length and the\
|
|
690
|
-
average edge radius.
|
|
691
|
-
|
|
692
|
-
Returns
|
|
693
|
-
-------
|
|
694
|
-
fig: plt.figure instance
|
|
695
|
-
Figure with the pixel layout.
|
|
696
|
-
"""
|
|
697
|
-
|
|
698
|
-
self._logger.info(f"Plotting the {self._telescope_model_name} camera")
|
|
699
|
-
|
|
700
|
-
fig, ax = plt.subplots()
|
|
701
|
-
plt.gcf().set_size_inches(8, 8)
|
|
702
|
-
|
|
703
|
-
if not is_two_mirror_telescope(self._telescope_model_name):
|
|
704
|
-
if not camera_in_sky_coor:
|
|
705
|
-
self._pixels["y"] = [(-1) * y_val for y_val in self._pixels["y"]]
|
|
706
|
-
|
|
707
|
-
on_pixels, edge_pixels, off_pixels = [], [], []
|
|
708
|
-
|
|
709
|
-
for i_pix, xy_pix_pos in enumerate(zip(self._pixels["x"], self._pixels["y"])):
|
|
710
|
-
if self._pixels["pixel_shape"] == 1 or self._pixels["pixel_shape"] == 3:
|
|
711
|
-
hexagon = mpatches.RegularPolygon(
|
|
712
|
-
(xy_pix_pos[0], xy_pix_pos[1]),
|
|
713
|
-
numVertices=6,
|
|
714
|
-
radius=self._pixels["pixel_diameter"] / np.sqrt(3),
|
|
715
|
-
orientation=np.deg2rad(self._pixels["orientation"]),
|
|
716
|
-
)
|
|
717
|
-
if self._pixels["pix_on"][i_pix]:
|
|
718
|
-
if len(self.get_neighbour_pixels()[i_pix]) < 6:
|
|
719
|
-
edge_pixels.append(hexagon)
|
|
720
|
-
else:
|
|
721
|
-
on_pixels.append(hexagon)
|
|
722
|
-
else:
|
|
723
|
-
off_pixels.append(hexagon)
|
|
724
|
-
elif self._pixels["pixel_shape"] == 2:
|
|
725
|
-
square = mpatches.Rectangle(
|
|
726
|
-
(
|
|
727
|
-
xy_pix_pos[0] - self._pixels["pixel_diameter"] / 2.0,
|
|
728
|
-
xy_pix_pos[1] - self._pixels["pixel_diameter"] / 2.0,
|
|
729
|
-
),
|
|
730
|
-
width=self._pixels["pixel_diameter"],
|
|
731
|
-
height=self._pixels["pixel_diameter"],
|
|
732
|
-
)
|
|
733
|
-
if self._pixels["pix_on"][i_pix]:
|
|
734
|
-
if len(self.get_neighbour_pixels()[i_pix]) < 4:
|
|
735
|
-
edge_pixels.append(square)
|
|
736
|
-
else:
|
|
737
|
-
on_pixels.append(square)
|
|
738
|
-
else:
|
|
739
|
-
off_pixels.append(square)
|
|
740
|
-
|
|
741
|
-
if self._pixels["pix_id"][i_pix] < pixels_id_to_print + 1:
|
|
742
|
-
font_size = 4
|
|
743
|
-
if names.get_telescope_class(self._telescope_model_name) == "SCT":
|
|
744
|
-
font_size = 2
|
|
745
|
-
plt.text(
|
|
746
|
-
xy_pix_pos[0],
|
|
747
|
-
xy_pix_pos[1],
|
|
748
|
-
self._pixels["pix_id"][i_pix],
|
|
749
|
-
horizontalalignment="center",
|
|
750
|
-
verticalalignment="center",
|
|
751
|
-
fontsize=font_size,
|
|
752
|
-
)
|
|
753
|
-
|
|
754
|
-
ax.add_collection(
|
|
755
|
-
PatchCollection(on_pixels, facecolor="none", edgecolor="black", linewidth=0.2)
|
|
756
|
-
)
|
|
757
|
-
ax.add_collection(
|
|
758
|
-
PatchCollection(
|
|
759
|
-
edge_pixels,
|
|
760
|
-
facecolor=mcolors.to_rgb("brown") + (0.5,),
|
|
761
|
-
edgecolor=mcolors.to_rgb("black") + (1,),
|
|
762
|
-
linewidth=0.2,
|
|
763
|
-
)
|
|
764
|
-
)
|
|
765
|
-
ax.add_collection(
|
|
766
|
-
PatchCollection(off_pixels, facecolor="black", edgecolor="black", linewidth=0.2)
|
|
767
|
-
)
|
|
768
|
-
|
|
769
|
-
legend_objects = [leg_h.PixelObject(), leg_h.EdgePixelObject()]
|
|
770
|
-
legend_labels = ["Pixel", "Edge pixel"]
|
|
771
|
-
if isinstance(on_pixels[0], mlp.patches.RegularPolygon):
|
|
772
|
-
legend_handler_map = {
|
|
773
|
-
leg_h.PixelObject: leg_h.HexPixelHandler(),
|
|
774
|
-
leg_h.EdgePixelObject: leg_h.HexEdgePixelHandler(),
|
|
775
|
-
leg_h.OffPixelObject: leg_h.HexOffPixelHandler(),
|
|
776
|
-
}
|
|
777
|
-
elif isinstance(on_pixels[0], mlp.patches.Rectangle):
|
|
778
|
-
legend_handler_map = {
|
|
779
|
-
leg_h.PixelObject: leg_h.SquarePixelHandler(),
|
|
780
|
-
leg_h.EdgePixelObject: leg_h.SquareEdgePixelHandler(),
|
|
781
|
-
leg_h.OffPixelObject: leg_h.SquareOffPixelHandler(),
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
if len(off_pixels) > 0:
|
|
785
|
-
legend_objects.append(leg_h.OffPixelObject())
|
|
786
|
-
legend_labels.append("Disabled pixel")
|
|
787
|
-
|
|
788
|
-
plt.axis("equal")
|
|
789
|
-
plt.grid(True)
|
|
790
|
-
ax.set_axisbelow(True)
|
|
791
|
-
plt.axis(
|
|
792
|
-
[
|
|
793
|
-
min(self._pixels["x"]),
|
|
794
|
-
max(self._pixels["x"]),
|
|
795
|
-
min(self._pixels["y"]) * 1.42,
|
|
796
|
-
max(self._pixels["y"]) * 1.42,
|
|
797
|
-
]
|
|
798
|
-
)
|
|
799
|
-
plt.xlabel("Horizontal scale [cm]", fontsize=18, labelpad=0)
|
|
800
|
-
plt.ylabel("Vertical scale [cm]", fontsize=18, labelpad=0)
|
|
801
|
-
ax.set_title(
|
|
802
|
-
f"Pixels layout in {self._telescope_model_name:s} camera",
|
|
803
|
-
fontsize=15,
|
|
804
|
-
y=1.02,
|
|
805
|
-
)
|
|
806
|
-
plt.tick_params(axis="both", which="major", labelsize=15)
|
|
807
|
-
|
|
808
|
-
self._plot_axes_def(plt, self._pixels["rotate_angle"])
|
|
809
|
-
description = "For an observer facing the camera"
|
|
810
|
-
if camera_in_sky_coor and not is_two_mirror_telescope(self._telescope_model_name):
|
|
811
|
-
description = "For an observer behind the camera looking through"
|
|
812
|
-
if is_two_mirror_telescope(self._telescope_model_name):
|
|
813
|
-
description = "For an observer looking from secondary to camera"
|
|
814
|
-
ax.text(
|
|
815
|
-
0.02,
|
|
816
|
-
0.02,
|
|
817
|
-
description,
|
|
818
|
-
transform=ax.transAxes,
|
|
819
|
-
color="black",
|
|
820
|
-
fontsize=12,
|
|
821
|
-
)
|
|
822
|
-
|
|
823
|
-
fov, r_edge_avg = self.calc_fov()
|
|
824
|
-
ax.text(
|
|
825
|
-
0.02,
|
|
826
|
-
0.96,
|
|
827
|
-
r"$f_{\mathrm{eff}}$ = " + f"{self._focal_length:.3f} cm",
|
|
828
|
-
transform=ax.transAxes,
|
|
829
|
-
color="black",
|
|
830
|
-
fontsize=12,
|
|
831
|
-
)
|
|
832
|
-
ax.text(
|
|
833
|
-
0.02,
|
|
834
|
-
0.92,
|
|
835
|
-
f"Avg. edge radius = {r_edge_avg:.3f} cm",
|
|
836
|
-
transform=ax.transAxes,
|
|
837
|
-
color="black",
|
|
838
|
-
fontsize=12,
|
|
839
|
-
)
|
|
840
|
-
ax.text(
|
|
841
|
-
0.02,
|
|
842
|
-
0.88,
|
|
843
|
-
f"FoV = {fov:.3f} deg",
|
|
844
|
-
transform=ax.transAxes,
|
|
845
|
-
color="black",
|
|
846
|
-
fontsize=12,
|
|
847
|
-
)
|
|
848
|
-
|
|
849
|
-
plt.legend(
|
|
850
|
-
legend_objects,
|
|
851
|
-
legend_labels,
|
|
852
|
-
handler_map=legend_handler_map,
|
|
853
|
-
prop={"size": 11},
|
|
854
|
-
loc="upper right",
|
|
855
|
-
)
|
|
856
|
-
|
|
857
|
-
ax.set_aspect("equal", "datalim")
|
|
858
|
-
plt.tight_layout()
|
|
859
|
-
|
|
860
|
-
return fig
|