gammasimtools 0.21.0__py3-none-any.whl → 0.23.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.21.0.dist-info → gammasimtools-0.23.0.dist-info}/METADATA +3 -3
- gammasimtools-0.23.0.dist-info/RECORD +414 -0
- {gammasimtools-0.21.0.dist-info → gammasimtools-0.23.0.dist-info}/entry_points.txt +2 -1
- simtools/_version.py +2 -2
- simtools/application_control.py +118 -0
- simtools/applications/calculate_incident_angles.py +17 -25
- simtools/applications/convert_all_model_parameters_from_simtel.py +29 -45
- simtools/applications/convert_geo_coordinates_of_array_elements.py +26 -45
- simtools/applications/convert_model_parameter_from_simtel.py +21 -42
- simtools/applications/db_add_file_to_db.py +12 -13
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +20 -33
- simtools/applications/db_add_value_from_json_to_db.py +28 -23
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +19 -34
- simtools/applications/db_generate_compound_indexes.py +12 -27
- simtools/applications/db_get_array_layouts_from_db.py +19 -39
- simtools/applications/db_get_file_from_db.py +15 -17
- simtools/applications/db_get_parameter_from_db.py +33 -35
- simtools/applications/db_inspect_databases.py +10 -11
- simtools/applications/db_upload_model_repository.py +104 -0
- simtools/applications/derive_ctao_array_layouts.py +16 -21
- simtools/applications/derive_mirror_rnda.py +9 -14
- simtools/applications/derive_photon_electron_spectrum.py +7 -10
- simtools/applications/derive_psf_parameters.py +24 -21
- simtools/applications/derive_trigger_rates.py +6 -9
- simtools/applications/docs_produce_array_element_report.py +22 -23
- simtools/applications/docs_produce_calibration_reports.py +26 -24
- simtools/applications/docs_produce_model_parameter_reports.py +15 -22
- simtools/applications/docs_produce_simulation_configuration_report.py +21 -22
- simtools/applications/generate_array_config.py +14 -33
- simtools/applications/generate_corsika_histograms.py +22 -43
- simtools/applications/generate_default_metadata.py +15 -36
- simtools/applications/generate_regular_arrays.py +11 -15
- simtools/applications/generate_simtel_event_data.py +23 -33
- simtools/applications/maintain_simulation_model_add_production.py +17 -48
- simtools/applications/maintain_simulation_model_compare_productions.py +10 -12
- simtools/applications/maintain_simulation_model_verify_production_tables.py +8 -11
- simtools/applications/merge_tables.py +15 -24
- simtools/applications/plot_array_layout.py +77 -55
- simtools/applications/plot_simtel_events.py +11 -13
- simtools/applications/plot_tabular_data.py +17 -38
- simtools/applications/plot_tabular_data_for_model_parameter.py +16 -23
- simtools/applications/print_version.py +14 -42
- simtools/applications/production_derive_corsika_limits.py +5 -9
- simtools/applications/production_derive_statistics.py +12 -26
- simtools/applications/production_generate_grid.py +20 -48
- simtools/applications/production_merge_corsika_limits.py +17 -21
- simtools/applications/run_application.py +12 -32
- simtools/applications/simulate_flasher.py +79 -81
- simtools/applications/simulate_illuminator.py +56 -197
- simtools/applications/{simulate_calibration_events.py → simulate_pedestals.py} +22 -68
- simtools/applications/simulate_prod.py +21 -33
- simtools/applications/simulate_prod_htcondor_generator.py +11 -25
- simtools/applications/submit_array_layouts.py +15 -18
- simtools/applications/submit_data_from_external.py +18 -34
- simtools/applications/submit_model_parameter_from_external.py +27 -41
- simtools/applications/validate_camera_efficiency.py +23 -22
- simtools/applications/validate_camera_fov.py +21 -27
- simtools/applications/validate_cumulative_psf.py +28 -37
- simtools/applications/validate_file_using_schema.py +35 -45
- simtools/applications/validate_optics.py +27 -33
- simtools/camera/camera_efficiency.py +8 -13
- simtools/configuration/commandline_parser.py +33 -11
- simtools/configuration/configurator.py +0 -7
- simtools/corsika/corsika_config.py +9 -16
- simtools/corsika/corsika_histograms.py +1 -1
- simtools/data_model/data_reader.py +0 -2
- simtools/data_model/metadata_collector.py +0 -2
- simtools/data_model/model_data_writer.py +87 -27
- simtools/data_model/schema.py +61 -2
- simtools/data_model/validate_data.py +1 -3
- simtools/db/db_handler.py +58 -39
- simtools/db/db_model_upload.py +210 -5
- simtools/io/hdf5_handler.py +0 -5
- simtools/io/io_handler.py +31 -83
- simtools/io/legacy_data_handler.py +0 -5
- simtools/job_execution/job_manager.py +43 -1
- simtools/layout/array_layout.py +0 -2
- simtools/layout/array_layout_utils.py +1 -5
- simtools/layout/telescope_position.py +0 -2
- simtools/model/array_model.py +95 -46
- simtools/model/calibration_model.py +0 -2
- simtools/model/camera.py +0 -2
- simtools/model/mirrors.py +0 -2
- simtools/model/model_parameter.py +50 -16
- simtools/model/model_repository.py +139 -106
- simtools/model/model_utils.py +21 -11
- simtools/model/site_model.py +0 -2
- simtools/model/telescope_model.py +20 -2
- simtools/production_configuration/calculate_statistical_uncertainties_grid_point.py +0 -2
- simtools/production_configuration/derive_corsika_limits.py +1 -1
- simtools/production_configuration/derive_production_statistics.py +0 -2
- simtools/production_configuration/interpolation_handler.py +0 -2
- simtools/ray_tracing/incident_angles.py +7 -7
- simtools/ray_tracing/mirror_panel_psf.py +1 -1
- simtools/ray_tracing/psf_analysis.py +0 -2
- simtools/ray_tracing/psf_parameter_optimisation.py +180 -73
- simtools/ray_tracing/ray_tracing.py +1 -5
- simtools/reporting/docs_auto_report_generator.py +108 -0
- simtools/reporting/docs_read_parameters.py +168 -104
- simtools/resources/array_elements.yml +26 -0
- simtools/runners/corsika_runner.py +0 -2
- simtools/runners/corsika_simtel_runner.py +11 -19
- simtools/runners/runner_services.py +5 -6
- simtools/runners/simtel_runner.py +0 -2
- simtools/runners/simtools_runner.py +0 -2
- simtools/schemas/application_workflow.metaschema.yml +1 -1
- simtools/schemas/common_definitions.schema.yml +39 -0
- simtools/schemas/model_parameter.metaschema.yml +19 -13
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +6 -12
- simtools/schemas/model_parameters/adjust_gain.schema.yml +0 -5
- simtools/schemas/model_parameters/altitude.schema.yml +0 -5
- simtools/schemas/model_parameters/array_coordinates.schema.yml +0 -5
- simtools/schemas/model_parameters/array_coordinates_UTM.schema.yml +0 -5
- simtools/schemas/model_parameters/array_element_position_ground.schema.yml +0 -7
- simtools/schemas/model_parameters/array_element_position_utm.schema.yml +0 -7
- simtools/schemas/model_parameters/array_layouts.schema.yml +0 -5
- simtools/schemas/model_parameters/array_triggers.schema.yml +0 -5
- simtools/schemas/model_parameters/array_window.schema.yml +0 -7
- simtools/schemas/model_parameters/asum_clipping.schema.yml +0 -3
- simtools/schemas/model_parameters/asum_offset.schema.yml +0 -7
- simtools/schemas/model_parameters/asum_shaping.schema.yml +0 -7
- simtools/schemas/model_parameters/asum_threshold.schema.yml +0 -7
- simtools/schemas/model_parameters/atmospheric_profile.schema.yml +0 -5
- simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +0 -5
- simtools/schemas/model_parameters/axes_offsets.schema.yml +0 -7
- simtools/schemas/model_parameters/calibration_devices.schema.yml +30 -0
- simtools/schemas/model_parameters/camera_body_diameter.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_body_shape.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_config_file.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_config_rotate.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_degraded_efficiency.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_degraded_map.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_depth.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_filter.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +0 -3
- simtools/schemas/model_parameters/camera_pixels.schema.yml +0 -7
- simtools/schemas/model_parameters/camera_transmission.schema.yml +0 -7
- simtools/schemas/model_parameters/channels_per_chip.schema.yml +0 -7
- simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +0 -7
- simtools/schemas/model_parameters/corsika_observation_level.schema.yml +0 -5
- simtools/schemas/model_parameters/dark_events.schema.yml +4 -3
- simtools/schemas/model_parameters/default_trigger.schema.yml +0 -7
- simtools/schemas/model_parameters/design_model.schema.yml +0 -7
- simtools/schemas/model_parameters/disc_ac_coupled.schema.yml +0 -7
- simtools/schemas/model_parameters/disc_bins.schema.yml +0 -7
- simtools/schemas/model_parameters/disc_start.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_amplitude.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_fall_time.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_gate_length.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_hysteresis.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_output_amplitude.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_output_var_percent.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_rise_time.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_scale_threshold.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_sigsum_over_threshold.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_threshold.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_time_over_threshold.schema.yml +1 -9
- simtools/schemas/model_parameters/discriminator_var_gate_length.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_var_sigsum_over_threshold.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_var_threshold.schema.yml +0 -7
- simtools/schemas/model_parameters/discriminator_var_time_over_threshold.schema.yml +0 -7
- simtools/schemas/model_parameters/dish_shape_length.schema.yml +0 -5
- simtools/schemas/model_parameters/dsum_clipping.schema.yml +1 -5
- simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_offset.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_pedsub.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_prescale.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_presum_max.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_shaping.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +0 -3
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +2 -12
- simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +0 -3
- simtools/schemas/model_parameters/effective_focal_length.schema.yml +0 -7
- simtools/schemas/model_parameters/epsg_code.schema.yml +0 -5
- simtools/schemas/model_parameters/fadc_ac_coupled.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_amplitude.schema.yml +2 -9
- simtools/schemas/model_parameters/fadc_bins.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +0 -2
- simtools/schemas/model_parameters/fadc_err_compensate_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_err_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_amplitude.schema.yml +2 -9
- simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +0 -2
- simtools/schemas/model_parameters/fadc_lg_err_compensate_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_err_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_max_signal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +0 -2
- simtools/schemas/model_parameters/fadc_lg_noise.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_sensitivity.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_sysvar_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_var_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_lg_var_sensitivity.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_long_event_threshold.schema.yml +0 -3
- simtools/schemas/model_parameters/fadc_long_sum_bins.schema.yml +0 -3
- simtools/schemas/model_parameters/fadc_long_sum_offset.schema.yml +0 -3
- simtools/schemas/model_parameters/fadc_max_signal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_max_sum.schema.yml +0 -2
- simtools/schemas/model_parameters/fadc_mhz.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_noise.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_sensitivity.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_sum_bins.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_sum_offset.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_sysvar_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_var_pedestal.schema.yml +0 -7
- simtools/schemas/model_parameters/fadc_var_sensitivity.schema.yml +0 -7
- simtools/schemas/model_parameters/fake_mirror_list.schema.yml +0 -3
- simtools/schemas/model_parameters/flasher_angular_distribution.schema.yml +32 -0
- simtools/schemas/model_parameters/flasher_angular_distribution_width.schema.yml +32 -0
- simtools/schemas/model_parameters/flasher_bunch_size.schema.yml +28 -0
- simtools/schemas/model_parameters/flasher_external_trigger.schema.yml +32 -0
- simtools/schemas/model_parameters/flasher_photons.schema.yml +34 -0
- simtools/schemas/model_parameters/flasher_position.schema.yml +43 -0
- simtools/schemas/model_parameters/flasher_pulse_exp_decay.schema.yml +29 -0
- simtools/schemas/model_parameters/flasher_pulse_offset.schema.yml +35 -0
- simtools/schemas/model_parameters/flasher_pulse_shape.schema.yml +30 -0
- simtools/schemas/model_parameters/flasher_pulse_width.schema.yml +32 -0
- simtools/schemas/model_parameters/flasher_type.schema.yml +28 -0
- simtools/schemas/model_parameters/flasher_var_photons.schema.yml +31 -0
- simtools/schemas/model_parameters/flasher_wavelength.schema.yml +33 -0
- simtools/schemas/model_parameters/flatfielding.schema.yml +0 -7
- simtools/schemas/model_parameters/focal_length.schema.yml +0 -7
- simtools/schemas/model_parameters/focal_surface_parameters.schema.yml +0 -3
- simtools/schemas/model_parameters/focal_surface_ref_radius.schema.yml +0 -3
- simtools/schemas/model_parameters/focus_offset.schema.yml +0 -7
- simtools/schemas/model_parameters/gain_variation.schema.yml +0 -7
- simtools/schemas/model_parameters/geomag_horizontal.schema.yml +2 -7
- simtools/schemas/model_parameters/geomag_rotation.schema.yml +2 -7
- simtools/schemas/model_parameters/geomag_vertical.schema.yml +2 -7
- simtools/schemas/model_parameters/hg_lg_variation.schema.yml +0 -5
- simtools/schemas/model_parameters/iobuf_maximum.schema.yml +0 -7
- simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +0 -7
- simtools/schemas/model_parameters/laser_events.schema.yml +4 -3
- simtools/schemas/model_parameters/laser_external_trigger.schema.yml +4 -3
- simtools/schemas/model_parameters/laser_photons.schema.yml +4 -3
- simtools/schemas/model_parameters/laser_pulse_exptime.schema.yml +4 -3
- simtools/schemas/model_parameters/laser_pulse_offset.schema.yml +4 -3
- simtools/schemas/model_parameters/laser_pulse_sigtime.schema.yml +4 -3
- simtools/schemas/model_parameters/laser_pulse_twidth.schema.yml +4 -3
- simtools/schemas/model_parameters/laser_var_photons.schema.yml +4 -3
- simtools/schemas/model_parameters/laser_wavelength.schema.yml +4 -3
- simtools/schemas/model_parameters/led_events.schema.yml +4 -3
- simtools/schemas/model_parameters/led_photons.schema.yml +4 -3
- simtools/schemas/model_parameters/led_pulse_offset.schema.yml +4 -3
- simtools/schemas/model_parameters/led_pulse_sigtime.schema.yml +4 -3
- simtools/schemas/model_parameters/led_var_photons.schema.yml +4 -3
- simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +0 -7
- simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +0 -7
- simtools/schemas/model_parameters/min_photoelectrons.schema.yml +0 -7
- simtools/schemas/model_parameters/min_photons.schema.yml +0 -7
- simtools/schemas/model_parameters/mirror_align_random_distance.schema.yml +0 -5
- simtools/schemas/model_parameters/mirror_align_random_horizontal.schema.yml +0 -7
- simtools/schemas/model_parameters/mirror_align_random_vertical.schema.yml +0 -7
- simtools/schemas/model_parameters/mirror_class.schema.yml +2 -9
- simtools/schemas/model_parameters/mirror_degraded_reflection.schema.yml +0 -7
- simtools/schemas/model_parameters/mirror_focal_length.schema.yml +0 -5
- simtools/schemas/model_parameters/mirror_list.schema.yml +0 -7
- simtools/schemas/model_parameters/mirror_offset.schema.yml +0 -7
- simtools/schemas/model_parameters/mirror_reflection_random_angle.schema.yml +0 -7
- simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +0 -7
- simtools/schemas/model_parameters/multiplicity_offset.schema.yml +0 -7
- simtools/schemas/model_parameters/muon_mono_threshold.schema.yml +0 -7
- simtools/schemas/model_parameters/nsb_autoscale_airmass.schema.yml +0 -7
- simtools/schemas/model_parameters/nsb_gain_drop_scale.schema.yml +0 -3
- simtools/schemas/model_parameters/nsb_offaxis.schema.yml +0 -7
- simtools/schemas/model_parameters/nsb_pixel_rate.schema.yml +0 -7
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +0 -5
- simtools/schemas/model_parameters/nsb_reference_value.schema.yml +0 -5
- simtools/schemas/model_parameters/nsb_scaling_factor.schema.yml +0 -5
- simtools/schemas/model_parameters/nsb_sky_map.schema.yml +0 -5
- simtools/schemas/model_parameters/nsb_spectrum.schema.yml +0 -5
- simtools/schemas/model_parameters/num_gains.schema.yml +0 -7
- simtools/schemas/model_parameters/only_triggered_telescopes.schema.yml +0 -7
- simtools/schemas/model_parameters/optics_properties.schema.yml +0 -7
- simtools/schemas/model_parameters/parabolic_dish.schema.yml +0 -3
- simtools/schemas/model_parameters/pedestal_events.schema.yml +4 -7
- simtools/schemas/model_parameters/photon_delay.schema.yml +0 -7
- simtools/schemas/model_parameters/photons_per_run.schema.yml +4 -4
- simtools/schemas/model_parameters/pixel_cells.schema.yml +0 -3
- simtools/schemas/model_parameters/pixels_parallel.schema.yml +0 -3
- simtools/schemas/model_parameters/pixeltrg_time_step.schema.yml +0 -7
- simtools/schemas/model_parameters/pm_average_gain.schema.yml +0 -5
- simtools/schemas/model_parameters/pm_collection_efficiency.schema.yml +0 -5
- simtools/schemas/model_parameters/pm_gain_index.schema.yml +0 -5
- simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +0 -7
- simtools/schemas/model_parameters/pm_transit_time.schema.yml +4 -9
- simtools/schemas/model_parameters/pm_voltage_variation.schema.yml +0 -5
- simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +0 -7
- simtools/schemas/model_parameters/primary_mirror_diameter.schema.yml +0 -3
- simtools/schemas/model_parameters/primary_mirror_hole_diameter.schema.yml +0 -3
- simtools/schemas/model_parameters/primary_mirror_incidence_angle.schema.yml +0 -3
- simtools/schemas/model_parameters/primary_mirror_parameters.schema.yml +0 -3
- simtools/schemas/model_parameters/primary_mirror_ref_radius.schema.yml +0 -3
- simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +0 -3
- simtools/schemas/model_parameters/qe_variation.schema.yml +0 -7
- simtools/schemas/model_parameters/quantum_efficiency.schema.yml +0 -7
- simtools/schemas/model_parameters/random_focal_length.schema.yml +2 -7
- simtools/schemas/model_parameters/random_generator.schema.yml +0 -7
- simtools/schemas/model_parameters/random_mono_probability.schema.yml +0 -7
- simtools/schemas/model_parameters/reference_point_altitude.schema.yml +0 -5
- simtools/schemas/model_parameters/reference_point_latitude.schema.yml +0 -5
- simtools/schemas/model_parameters/reference_point_longitude.schema.yml +0 -5
- simtools/schemas/model_parameters/reference_point_utm_east.schema.yml +0 -5
- simtools/schemas/model_parameters/reference_point_utm_north.schema.yml +0 -5
- simtools/schemas/model_parameters/sampled_output.schema.yml +0 -7
- simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +0 -7
- simtools/schemas/model_parameters/secondary_mirror_baffle.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_diameter.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_hole_diameter.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_incidence_angle.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_parameters.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_ref_radius.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_reflectivity.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_shadow_diameter.schema.yml +0 -3
- simtools/schemas/model_parameters/secondary_mirror_shadow_offset.schema.yml +0 -3
- simtools/schemas/model_parameters/stars.schema.yml +0 -5
- simtools/schemas/model_parameters/store_photoelectrons.schema.yml +0 -7
- simtools/schemas/model_parameters/tailcut_scale.schema.yml +0 -7
- simtools/schemas/model_parameters/telescope_axis_height.schema.yml +0 -7
- simtools/schemas/model_parameters/telescope_random_angle.schema.yml +0 -7
- simtools/schemas/model_parameters/telescope_random_error.schema.yml +0 -7
- simtools/schemas/model_parameters/telescope_sphere_radius.schema.yml +0 -7
- simtools/schemas/model_parameters/telescope_transmission.schema.yml +0 -7
- simtools/schemas/model_parameters/teltrig_min_sigsum.schema.yml +0 -7
- simtools/schemas/model_parameters/teltrig_min_time.schema.yml +0 -7
- simtools/schemas/model_parameters/transit_time_calib_error.schema.yml +0 -7
- simtools/schemas/model_parameters/transit_time_compensate_error.schema.yml +0 -7
- simtools/schemas/model_parameters/transit_time_compensate_step.schema.yml +0 -7
- simtools/schemas/model_parameters/transit_time_error.schema.yml +0 -7
- simtools/schemas/model_parameters/transit_time_jitter.schema.yml +0 -7
- simtools/schemas/model_parameters/transit_time_random.schema.yml +29 -0
- simtools/schemas/model_parameters/trigger_current_limit.schema.yml +0 -7
- simtools/schemas/model_parameters/trigger_delay_compensation.schema.yml +0 -7
- simtools/schemas/model_parameters/trigger_pixels.schema.yml +0 -7
- simtools/schemas/production_tables.schema.yml +8 -8
- simtools/schemas/simulation_models_info.schema.yml +78 -0
- simtools/simtel/simtel_config_reader.py +0 -2
- simtools/simtel/simtel_config_writer.py +118 -26
- simtools/simtel/simtel_io_metadata.py +3 -3
- simtools/simtel/simulator_array.py +43 -85
- simtools/simtel/simulator_camera_efficiency.py +0 -2
- simtools/simtel/simulator_light_emission.py +336 -631
- simtools/simtel/simulator_ray_tracing.py +2 -4
- simtools/simulator.py +45 -19
- simtools/testing/assertions.py +2 -2
- simtools/testing/configuration.py +21 -6
- simtools/testing/sim_telarray_metadata.py +4 -4
- simtools/utils/general.py +5 -13
- simtools/utils/geometry.py +34 -5
- simtools/utils/names.py +1 -13
- simtools/version.py +83 -0
- simtools/visualization/plot_array_layout.py +129 -23
- simtools/visualization/plot_incident_angles.py +0 -2
- simtools/visualization/plot_psf.py +163 -61
- simtools/visualization/plot_simtel_events.py +1 -12
- simtools/visualization/visualize.py +0 -12
- gammasimtools-0.21.0.dist-info/RECORD +0 -396
- simtools/model/flasher_model.py +0 -106
- {gammasimtools-0.21.0.dist-info → gammasimtools-0.23.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.21.0.dist-info → gammasimtools-0.23.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.21.0.dist-info → gammasimtools-0.23.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Light emission simulation (e.g. illuminators or flashers)."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
import shutil
|
|
@@ -10,261 +10,200 @@ import astropy.units as u
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
|
|
12
12
|
from simtools.io import io_handler
|
|
13
|
+
from simtools.model.model_utils import initialize_simulation_models
|
|
13
14
|
from simtools.runners.simtel_runner import SimtelRunner
|
|
14
15
|
from simtools.utils.general import clear_default_sim_telarray_cfg_directories
|
|
15
|
-
|
|
16
|
-
__all__ = ["SimulatorLightEmission"]
|
|
16
|
+
from simtools.utils.geometry import fiducial_radius_from_shape
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class SimulatorLightEmission(SimtelRunner):
|
|
20
20
|
"""
|
|
21
|
-
|
|
21
|
+
Light emission simulation (e.g. illuminators or flashers).
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
"""
|
|
23
|
+
Uses the sim_telarray LightEmission package to simulate the light emission.
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
light_emission_config=None,
|
|
34
|
-
light_source_setup=None,
|
|
35
|
-
simtel_path=None,
|
|
36
|
-
light_source_type=None,
|
|
37
|
-
label=None,
|
|
38
|
-
test=False,
|
|
39
|
-
):
|
|
40
|
-
"""Initialize SimtelRunner.
|
|
41
|
-
|
|
42
|
-
Parameters
|
|
43
|
-
----------
|
|
44
|
-
telescope_model : TelescopeModel
|
|
45
|
-
Model of the telescope to be simulated
|
|
46
|
-
calibration_model : CalibrationModel, optional
|
|
47
|
-
Model of the calibration device to be simulated
|
|
48
|
-
flasher_model : FlasherModel, optional
|
|
49
|
-
Model of the flasher device to be simulated
|
|
50
|
-
site_model : SiteModel, optional
|
|
51
|
-
Model of the site
|
|
52
|
-
light_emission_config : dict, optional
|
|
53
|
-
Configuration for the light emission
|
|
54
|
-
light_source_setup : str, optional
|
|
55
|
-
Setup for light source positioning ("variable" or "layout")
|
|
56
|
-
simtel_path : Path, optional
|
|
57
|
-
Path to the sim_telarray installation
|
|
58
|
-
light_source_type : str, optional
|
|
59
|
-
Type of light source: 'illuminator', or 'flasher'
|
|
60
|
-
label : str, optional
|
|
61
|
-
Label for the simulation
|
|
62
|
-
test : bool, optional
|
|
63
|
-
Whether this is a test run
|
|
64
|
-
"""
|
|
65
|
-
super().__init__(simtel_path=simtel_path, label=label, corsika_config=None)
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
light_emission_config : dict, optional
|
|
28
|
+
Configuration for the light emission (e.g. number of events, model names)
|
|
29
|
+
label : str, optional
|
|
30
|
+
Label for the simulation
|
|
31
|
+
"""
|
|
66
32
|
|
|
33
|
+
def __init__(self, light_emission_config, db_config=None, label=None):
|
|
34
|
+
"""Initialize SimulatorLightEmission."""
|
|
67
35
|
self._logger = logging.getLogger(__name__)
|
|
36
|
+
self.io_handler = io_handler.IOHandler()
|
|
37
|
+
|
|
38
|
+
super().__init__(
|
|
39
|
+
simtel_path=light_emission_config.get("simtel_path"), label=label, corsika_config=None
|
|
40
|
+
)
|
|
68
41
|
|
|
69
|
-
self.
|
|
70
|
-
self._calibration_model = calibration_model
|
|
71
|
-
self._flasher_model = flasher_model
|
|
72
|
-
self._site_model = site_model
|
|
73
|
-
self.light_emission_config = light_emission_config or {}
|
|
74
|
-
self.light_source_setup = light_source_setup
|
|
75
|
-
self.light_source_type = light_source_type or "illuminator"
|
|
76
|
-
self.test = test
|
|
42
|
+
self.output_directory = self.io_handler.get_output_directory()
|
|
77
43
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
44
|
+
self.telescope_model, self.site_model, self.calibration_model = (
|
|
45
|
+
initialize_simulation_models(
|
|
46
|
+
label=label,
|
|
47
|
+
db_config=db_config,
|
|
48
|
+
site=light_emission_config.get("site"),
|
|
49
|
+
telescope_name=light_emission_config.get("telescope"),
|
|
50
|
+
calibration_device_name=light_emission_config.get("light_source"),
|
|
51
|
+
model_version=light_emission_config.get("model_version"),
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
self.telescope_model.write_sim_telarray_config_file(additional_models=self.site_model)
|
|
81
55
|
|
|
82
|
-
self.
|
|
56
|
+
self.light_emission_config = self._initialize_light_emission_configuration(
|
|
57
|
+
light_emission_config
|
|
58
|
+
)
|
|
83
59
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
60
|
+
def _initialize_light_emission_configuration(self, config):
|
|
61
|
+
"""Initialize light emission configuration."""
|
|
62
|
+
if self.calibration_model.get_parameter_value("flasher_type"):
|
|
63
|
+
config["light_source_type"] = self.calibration_model.get_parameter_value(
|
|
64
|
+
"flasher_type"
|
|
65
|
+
).lower()
|
|
66
|
+
|
|
67
|
+
config["flasher_photons"] = (
|
|
68
|
+
self.calibration_model.get_parameter_value("flasher_photons")
|
|
69
|
+
if not config.get("test", False)
|
|
70
|
+
else 1e8
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
if config.get("light_source_position") is not None:
|
|
74
|
+
config["light_source_position"] = (
|
|
75
|
+
np.array(config["light_source_position"], dtype=float) * u.m
|
|
90
76
|
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
77
|
+
|
|
78
|
+
return config
|
|
79
|
+
|
|
80
|
+
def simulate(self):
|
|
81
|
+
"""
|
|
82
|
+
Simulate light emission.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
Path
|
|
87
|
+
The output simtel file path.
|
|
88
|
+
"""
|
|
89
|
+
run_script = self.prepare_script()
|
|
90
|
+
log_path = Path(self.output_directory) / "logfile.log"
|
|
91
|
+
with open(log_path, "w", encoding="utf-8") as fh:
|
|
92
|
+
subprocess.run(
|
|
93
|
+
run_script,
|
|
94
|
+
shell=False,
|
|
95
|
+
check=False,
|
|
96
|
+
text=True,
|
|
97
|
+
stdout=fh,
|
|
98
|
+
stderr=fh,
|
|
96
99
|
)
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
out = Path(self._get_simulation_output_filename())
|
|
101
|
+
if not out.exists():
|
|
102
|
+
self._logger.warning(f"Expected sim_telarray output not found: {out}")
|
|
103
|
+
return out
|
|
104
|
+
|
|
105
|
+
def prepare_script(self):
|
|
106
|
+
"""
|
|
107
|
+
Build and return bash run script containing the light-emission command.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
Path
|
|
112
|
+
Full path of the run script.
|
|
113
|
+
"""
|
|
114
|
+
script_dir = self.output_directory.joinpath("scripts")
|
|
115
|
+
script_dir.mkdir(parents=True, exist_ok=True)
|
|
116
|
+
|
|
117
|
+
app_name = self._get_light_emission_application_name()
|
|
118
|
+
script_file = script_dir / f"{app_name}-light_emission.sh"
|
|
119
|
+
self._logger.debug(f"Run bash script - {script_file}")
|
|
99
120
|
|
|
100
|
-
|
|
101
|
-
if
|
|
102
|
-
|
|
121
|
+
target_out = Path(self._get_simulation_output_filename())
|
|
122
|
+
if target_out.exists():
|
|
123
|
+
raise FileExistsError(
|
|
124
|
+
f"sim_telarray output file exists, cancelling simulation: {target_out}"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
lines = [
|
|
128
|
+
"#!/usr/bin/env bash\n",
|
|
129
|
+
f"{self._make_light_emission_script()}\n\n",
|
|
130
|
+
(
|
|
131
|
+
f"[ -s '{self.output_directory}/{app_name}.iact.gz' ] || "
|
|
132
|
+
f"{{ echo 'LightEmission did not produce IACT file' >&2; exit 1; }}\n\n"
|
|
133
|
+
),
|
|
134
|
+
f"{self._make_simtel_script()}\n\n",
|
|
135
|
+
f"rm -f '{self.output_directory}/{app_name}.iact.gz'\n\n",
|
|
136
|
+
]
|
|
103
137
|
|
|
104
|
-
|
|
105
|
-
|
|
138
|
+
script_file.write_text("".join(lines), encoding="utf-8")
|
|
139
|
+
script_file.chmod(script_file.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP)
|
|
140
|
+
return script_file
|
|
106
141
|
|
|
107
|
-
def _get_prefix(self)
|
|
142
|
+
def _get_prefix(self):
|
|
108
143
|
prefix = self.light_emission_config.get("output_prefix", "")
|
|
109
144
|
if prefix is not None:
|
|
110
145
|
return f"{prefix}_"
|
|
111
146
|
return ""
|
|
112
147
|
|
|
113
|
-
def
|
|
114
|
-
"""
|
|
148
|
+
def _get_light_emission_application_name(self):
|
|
149
|
+
"""
|
|
150
|
+
Return the LightEmission application and mode from type.
|
|
115
151
|
|
|
116
152
|
Returns
|
|
117
153
|
-------
|
|
118
|
-
|
|
119
|
-
|
|
154
|
+
str
|
|
155
|
+
app_name
|
|
120
156
|
"""
|
|
121
|
-
if self.light_source_type == "
|
|
122
|
-
return
|
|
157
|
+
if self.light_emission_config["light_source_type"] == "flat_fielding":
|
|
158
|
+
return "ff-1m"
|
|
123
159
|
# default to illuminator xyzls, mode from setup
|
|
124
|
-
|
|
125
|
-
return ("xyzls", mode)
|
|
160
|
+
return "xyzls"
|
|
126
161
|
|
|
127
|
-
|
|
128
|
-
def light_emission_default_configuration():
|
|
162
|
+
def _get_telescope_pointing(self):
|
|
129
163
|
"""
|
|
130
|
-
|
|
164
|
+
Return telescope pointing based on light source type.
|
|
131
165
|
|
|
132
|
-
|
|
133
|
-
-------
|
|
134
|
-
dict
|
|
135
|
-
Default configuration light emission.
|
|
136
|
-
|
|
137
|
-
"""
|
|
138
|
-
return {
|
|
139
|
-
"zenith_angle": {
|
|
140
|
-
"len": 1,
|
|
141
|
-
"unit": u.Unit("deg"),
|
|
142
|
-
"default": 0.0 * u.deg,
|
|
143
|
-
"names": ["zenith", "theta"],
|
|
144
|
-
},
|
|
145
|
-
"azimuth_angle": {
|
|
146
|
-
"len": 1,
|
|
147
|
-
"unit": u.Unit("deg"),
|
|
148
|
-
"default": 0.0 * u.deg,
|
|
149
|
-
"names": ["azimuth", "phi"],
|
|
150
|
-
},
|
|
151
|
-
"source_distance": {
|
|
152
|
-
"len": 1,
|
|
153
|
-
"unit": u.Unit("m"),
|
|
154
|
-
"default": 1000 * u.m,
|
|
155
|
-
"names": ["sourcedist", "srcdist"],
|
|
156
|
-
},
|
|
157
|
-
"off_axis_angle": {
|
|
158
|
-
"len": 1,
|
|
159
|
-
"unit": u.Unit("deg"),
|
|
160
|
-
"default": 0 * u.deg,
|
|
161
|
-
"names": ["off_axis"],
|
|
162
|
-
},
|
|
163
|
-
"fadc_bins": {
|
|
164
|
-
"len": 1,
|
|
165
|
-
"unit": u.dimensionless_unscaled,
|
|
166
|
-
"default": 128,
|
|
167
|
-
"names": ["fadc_bins"],
|
|
168
|
-
},
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
@staticmethod
|
|
172
|
-
def flasher_default_configuration():
|
|
173
|
-
"""
|
|
174
|
-
Get default flasher configuration.
|
|
166
|
+
For flat_fielding sims, avoid calibration pointing entirely; default angles to (0,0).
|
|
175
167
|
|
|
176
168
|
Returns
|
|
177
169
|
-------
|
|
178
|
-
|
|
179
|
-
|
|
170
|
+
tuple
|
|
171
|
+
The telescope pointing angles (theta, phi).
|
|
172
|
+
|
|
180
173
|
"""
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"unit": None,
|
|
191
|
-
"default": 2.5e6,
|
|
192
|
-
"names": ["photons"],
|
|
193
|
-
},
|
|
194
|
-
"bunch_size": {
|
|
195
|
-
"len": 1,
|
|
196
|
-
"unit": None,
|
|
197
|
-
"default": 1.0,
|
|
198
|
-
"names": ["bunchsize"],
|
|
199
|
-
},
|
|
200
|
-
"flasher_position": {
|
|
201
|
-
"len": 2,
|
|
202
|
-
"unit": u.Unit("cm"),
|
|
203
|
-
"default": [0.0, 0.0] * u.cm,
|
|
204
|
-
"names": ["xy", "position"],
|
|
205
|
-
},
|
|
206
|
-
"flasher_depth": {
|
|
207
|
-
"len": 1,
|
|
208
|
-
"unit": u.Unit("cm"),
|
|
209
|
-
"default": 60 * u.cm,
|
|
210
|
-
"names": ["depth", "distance"],
|
|
211
|
-
},
|
|
212
|
-
"flasher_inclination": {
|
|
213
|
-
"len": 1,
|
|
214
|
-
"unit": u.Unit("deg"),
|
|
215
|
-
"default": 0.0 * u.deg,
|
|
216
|
-
"names": ["inclination"],
|
|
217
|
-
},
|
|
218
|
-
"spectrum": {
|
|
219
|
-
"len": 1,
|
|
220
|
-
"unit": u.Unit("nm"),
|
|
221
|
-
"default": 400 * u.nm,
|
|
222
|
-
"names": ["wavelength"],
|
|
223
|
-
},
|
|
224
|
-
"lightpulse": {
|
|
225
|
-
"len": 1,
|
|
226
|
-
"unit": None,
|
|
227
|
-
"default": "Simple:0",
|
|
228
|
-
"names": ["pulse"],
|
|
229
|
-
},
|
|
230
|
-
"angular_distribution": {
|
|
231
|
-
"len": 1,
|
|
232
|
-
"unit": None,
|
|
233
|
-
"default": "isotropic",
|
|
234
|
-
"names": ["angular"],
|
|
235
|
-
},
|
|
236
|
-
"flasher_pattern": {
|
|
237
|
-
"len": 1,
|
|
238
|
-
"unit": None,
|
|
239
|
-
"default": "all",
|
|
240
|
-
"names": ["fire", "pattern"],
|
|
241
|
-
},
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
def calibration_pointing_direction(self):
|
|
174
|
+
if self.light_emission_config["light_source_type"] == "flat_fielding":
|
|
175
|
+
return 0.0, 0.0
|
|
176
|
+
if self.light_emission_config.get("light_source_position") is not None:
|
|
177
|
+
self._logger.info("Using fixed (vertical up) telescope pointing.")
|
|
178
|
+
return 0.0, 0.0
|
|
179
|
+
_, angles = self._calibration_pointing_direction()
|
|
180
|
+
return angles[0], angles[1]
|
|
181
|
+
|
|
182
|
+
def _calibration_pointing_direction(self, x_cal=None, y_cal=None, z_cal=None):
|
|
245
183
|
"""
|
|
246
184
|
Calculate the pointing of the calibration device towards the telescope.
|
|
247
185
|
|
|
186
|
+
This is for calibration devices not installed on telescopes (e.g. illuminators).
|
|
187
|
+
|
|
248
188
|
Returns
|
|
249
189
|
-------
|
|
250
190
|
list
|
|
251
191
|
The pointing vector from the calibration device to the telescope.
|
|
252
192
|
"""
|
|
253
|
-
x_cal
|
|
254
|
-
|
|
255
|
-
|
|
193
|
+
if x_cal is None or y_cal is None or z_cal is None:
|
|
194
|
+
x_cal, y_cal, z_cal = self.calibration_model.get_parameter_value_with_unit(
|
|
195
|
+
"array_element_position_ground"
|
|
196
|
+
)
|
|
256
197
|
x_cal, y_cal, z_cal = [coord.to(u.m).value for coord in (x_cal, y_cal, z_cal)]
|
|
257
198
|
cal_vect = np.array([x_cal, y_cal, z_cal])
|
|
258
|
-
x_tel, y_tel, z_tel = self.
|
|
199
|
+
x_tel, y_tel, z_tel = self.telescope_model.get_parameter_value_with_unit(
|
|
259
200
|
"array_element_position_ground"
|
|
260
201
|
)
|
|
261
202
|
x_tel, y_tel, z_tel = [coord.to(u.m).value for coord in (x_tel, y_tel, z_tel)]
|
|
262
|
-
|
|
263
203
|
tel_vect = np.array([x_tel, y_tel, z_tel])
|
|
264
204
|
|
|
265
205
|
direction_vector = tel_vect - cal_vect
|
|
266
206
|
# pointing vector from calibration device to telescope
|
|
267
|
-
|
|
268
207
|
pointing_vector = np.round(direction_vector / np.linalg.norm(direction_vector), 6)
|
|
269
208
|
|
|
270
209
|
# Calculate telescope theta and phi angles
|
|
@@ -285,53 +224,52 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
285
224
|
)
|
|
286
225
|
return pointing_vector.tolist(), [tel_theta, tel_phi, source_theta, source_phi]
|
|
287
226
|
|
|
288
|
-
def
|
|
227
|
+
def _write_telescope_position_file(self):
|
|
289
228
|
"""
|
|
290
|
-
Write the telescope positions to a
|
|
229
|
+
Write the telescope positions to a telescope_position file.
|
|
291
230
|
|
|
292
231
|
The file will contain lines in the format: x y z r in cm
|
|
293
232
|
|
|
294
233
|
Returns
|
|
295
234
|
-------
|
|
296
235
|
Path
|
|
297
|
-
The path to the generated
|
|
236
|
+
The path to the generated telescope_position file.
|
|
298
237
|
"""
|
|
299
|
-
|
|
300
|
-
x_tel, y_tel, z_tel = self._telescope_model.get_parameter_value_with_unit(
|
|
238
|
+
x_tel, y_tel, z_tel = self.telescope_model.get_parameter_value_with_unit(
|
|
301
239
|
"array_element_position_ground"
|
|
302
240
|
)
|
|
303
241
|
x_tel, y_tel, z_tel = [coord.to(u.cm).value for coord in (x_tel, y_tel, z_tel)]
|
|
304
242
|
|
|
305
|
-
radius = self.
|
|
243
|
+
radius = self.telescope_model.get_parameter_value_with_unit("telescope_sphere_radius")
|
|
306
244
|
radius = radius.to(u.cm).value # Convert radius to cm
|
|
307
|
-
with telpos_file.open("w", encoding="utf-8") as file:
|
|
308
|
-
file.write(f"{x_tel} {y_tel} {z_tel} {radius}\n")
|
|
309
245
|
|
|
310
|
-
|
|
246
|
+
telescope_position_file = self.output_directory.joinpath("telescope_position.dat")
|
|
247
|
+
telescope_position_file.write_text(f"{x_tel} {y_tel} {z_tel} {radius}\n", encoding="utf-8")
|
|
248
|
+
return telescope_position_file
|
|
311
249
|
|
|
312
|
-
def _prepare_flasher_atmosphere_files(self, config_directory
|
|
313
|
-
"""
|
|
314
|
-
|
|
315
|
-
self._logger.debug(f"Using atmosphere profile: {atmo_name}")
|
|
250
|
+
def _prepare_flasher_atmosphere_files(self, config_directory, model_id=1):
|
|
251
|
+
"""
|
|
252
|
+
Prepare canonical atmosphere aliases for ff-1m and return model id.
|
|
316
253
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
254
|
+
The ff-1m tool requires atmosphere files atmprof1.dat or atm_profile_model_1.dat and
|
|
255
|
+
as configuration parameter the atmosphere id ('--atmosphere id').
|
|
256
|
+
|
|
257
|
+
"""
|
|
258
|
+
src_path = config_directory / self.site_model.get_parameter_value("atmospheric_profile")
|
|
259
|
+
self._logger.debug(f"Using atmosphere profile: {src_path}")
|
|
260
|
+
|
|
261
|
+
for name in (f"atmprof{model_id}.dat", f"atm_profile_model_{model_id}.dat"):
|
|
262
|
+
dst = config_directory / name
|
|
325
263
|
try:
|
|
326
|
-
dst.
|
|
327
|
-
|
|
264
|
+
if dst.exists() or dst.is_symlink():
|
|
265
|
+
dst.unlink()
|
|
328
266
|
try:
|
|
267
|
+
dst.symlink_to(src_path)
|
|
268
|
+
except OSError:
|
|
329
269
|
shutil.copy2(src_path, dst)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
)
|
|
334
|
-
return 1
|
|
270
|
+
except OSError as copy_err:
|
|
271
|
+
self._logger.warning(f"Failed to create atmosphere alias {dst.name}: {copy_err}")
|
|
272
|
+
return model_id
|
|
335
273
|
|
|
336
274
|
def _make_light_emission_script(self):
|
|
337
275
|
"""
|
|
@@ -345,153 +283,109 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
345
283
|
str
|
|
346
284
|
The commands to run the Light Emission package
|
|
347
285
|
"""
|
|
348
|
-
x_tel, y_tel, z_tel = self._telescope_model.get_parameter_value_with_unit(
|
|
349
|
-
"array_element_position_ground"
|
|
350
|
-
)
|
|
351
|
-
|
|
352
286
|
config_directory = self.io_handler.get_model_configuration_directory(
|
|
353
|
-
|
|
287
|
+
model_version=self.site_model.model_version
|
|
354
288
|
)
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
app_name, _ = self._infer_application()
|
|
358
|
-
|
|
359
|
-
parts: list[str] = []
|
|
360
|
-
# application path
|
|
361
|
-
parts.append(str(self._simtel_path.joinpath("sim_telarray/LightEmission/")))
|
|
362
|
-
parts.append(f"/{app_name}")
|
|
363
|
-
|
|
364
|
-
corsika_observation_level = self._site_model.get_parameter_value_with_unit(
|
|
289
|
+
app_name = self._get_light_emission_application_name()
|
|
290
|
+
corsika_observation_level = self.site_model.get_parameter_value_with_unit(
|
|
365
291
|
"corsika_observation_level"
|
|
366
292
|
)
|
|
367
|
-
parts.append(
|
|
368
|
-
self._build_altitude_atmo_block(
|
|
369
|
-
app_name, config_directory, corsika_observation_level, telpos_file
|
|
370
|
-
)
|
|
371
|
-
)
|
|
372
|
-
|
|
373
|
-
parts.append(self._build_source_specific_block(x_tel, y_tel, z_tel, config_directory))
|
|
374
|
-
|
|
375
|
-
if self.light_source_type == "illuminator":
|
|
376
|
-
parts.append(f" -A {config_directory}/")
|
|
377
|
-
parts.append(f"{self._telescope_model.get_parameter_value('atmospheric_profile')}")
|
|
378
|
-
|
|
379
|
-
parts.append(f" -o {self.output_directory}/{app_name}.iact.gz")
|
|
380
|
-
parts.append("\n")
|
|
381
293
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
self
|
|
386
|
-
|
|
387
|
-
|
|
294
|
+
parts = [str(self._simtel_path / "sim_telarray/LightEmission") + f"/{app_name}"]
|
|
295
|
+
parts.extend(self._get_site_command(app_name, config_directory, corsika_observation_level))
|
|
296
|
+
parts.extend(self._get_light_source_command())
|
|
297
|
+
if self.light_emission_config["light_source_type"] == "illuminator":
|
|
298
|
+
parts += [
|
|
299
|
+
"-A",
|
|
300
|
+
(
|
|
301
|
+
f"{config_directory}/"
|
|
302
|
+
f"{self.telescope_model.get_parameter_value('atmospheric_profile')}"
|
|
303
|
+
),
|
|
304
|
+
]
|
|
305
|
+
parts += [f"-o {self.output_directory}/{app_name}.iact.gz", "\n"]
|
|
306
|
+
return " ".join(parts)
|
|
307
|
+
|
|
308
|
+
def _get_site_command(self, app_name, config_directory, corsika_observation_level):
|
|
309
|
+
"""Return site command with altitude, atmosphere and telescope_position handling."""
|
|
388
310
|
if app_name in ("ff-1m",):
|
|
389
|
-
seg = []
|
|
390
|
-
seg.append(" -I.")
|
|
391
|
-
seg.append(f" -I{self._simtel_path.joinpath('sim_telarray/cfg')}")
|
|
392
|
-
seg.append(f" -I{config_directory}")
|
|
393
|
-
seg.append(f" --altitude {corsika_observation_level.to(u.m).value}")
|
|
394
311
|
atmo_id = self._prepare_flasher_atmosphere_files(config_directory)
|
|
395
|
-
|
|
396
|
-
|
|
312
|
+
return [
|
|
313
|
+
"-I.",
|
|
314
|
+
f"-I{self._simtel_path / 'sim_telarray/cfg'}",
|
|
315
|
+
f"-I{config_directory}",
|
|
316
|
+
f"--altitude {corsika_observation_level.to(u.m).value}",
|
|
317
|
+
f"--atmosphere {atmo_id}",
|
|
318
|
+
]
|
|
397
319
|
# default path (not used for flasher now, but kept for completeness)
|
|
398
|
-
return
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
320
|
+
return [
|
|
321
|
+
f"-h {corsika_observation_level.to(u.m).value} ",
|
|
322
|
+
f"--telpos-file {self._write_telescope_position_file()}",
|
|
323
|
+
]
|
|
324
|
+
|
|
325
|
+
def _get_light_source_command(self):
|
|
326
|
+
"""Return light-source specific command options."""
|
|
327
|
+
if self.light_emission_config["light_source_type"] == "flat_fielding":
|
|
328
|
+
return self._add_flasher_command_options()
|
|
329
|
+
if self.light_emission_config["light_source_type"] == "illuminator":
|
|
330
|
+
return self._add_illuminator_command_options()
|
|
331
|
+
raise ValueError(
|
|
332
|
+
f"Unknown light_source_type '{self.light_emission_config['light_source_type']}'"
|
|
333
|
+
)
|
|
412
334
|
|
|
413
|
-
def
|
|
335
|
+
def _add_flasher_command_options(self):
|
|
414
336
|
"""Add flasher options for all telescope types (ff-1m style)."""
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
# Camera radius required for application, Radius of fiducial sphere enclosing camera
|
|
419
|
-
camera_radius = (
|
|
420
|
-
self._telescope_model.get_parameter_value_with_unit("camera_body_diameter")
|
|
337
|
+
flasher_xyz = self.calibration_model.get_parameter_value_with_unit("flasher_position")
|
|
338
|
+
camera_radius = fiducial_radius_from_shape(
|
|
339
|
+
self.telescope_model.get_parameter_value_with_unit("camera_body_diameter")
|
|
421
340
|
.to(u.cm)
|
|
422
|
-
.value
|
|
423
|
-
|
|
341
|
+
.value,
|
|
342
|
+
self.telescope_model.get_parameter_value("camera_body_shape"),
|
|
424
343
|
)
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
command
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
"""
|
|
449
|
-
Add illuminator-specific command options to the light emission script.
|
|
450
|
-
|
|
451
|
-
Parameters
|
|
452
|
-
----------
|
|
453
|
-
command : str
|
|
454
|
-
The command string to add options to
|
|
455
|
-
|
|
456
|
-
Returns
|
|
457
|
-
-------
|
|
458
|
-
str
|
|
459
|
-
The updated command string
|
|
460
|
-
"""
|
|
461
|
-
if self.light_source_setup == "variable":
|
|
462
|
-
command += f" -x {self.light_emission_config['x_pos']['default'].to(u.cm).value}"
|
|
463
|
-
command += f" -y {self.light_emission_config['y_pos']['default'].to(u.cm).value}"
|
|
464
|
-
command += f" -z {self.light_emission_config['z_pos']['default'].to(u.cm).value}"
|
|
465
|
-
command += (
|
|
466
|
-
f" -d {','.join(map(str, self.light_emission_config['direction']['default']))}"
|
|
467
|
-
)
|
|
468
|
-
command += f" -n {self.photons_per_run}"
|
|
469
|
-
|
|
470
|
-
elif self.light_source_setup == "layout":
|
|
471
|
-
x_cal, y_cal, z_cal = self._calibration_model.get_parameter_value_with_unit(
|
|
344
|
+
flasher_wavelength = self.calibration_model.get_parameter_value_with_unit(
|
|
345
|
+
"flasher_wavelength"
|
|
346
|
+
)
|
|
347
|
+
dist_cm = self.calculate_distance_focal_plane_calibration_device().to(u.cm).value
|
|
348
|
+
angular_distribution = self._get_angular_distribution_string_for_sim_telarray()
|
|
349
|
+
|
|
350
|
+
return [
|
|
351
|
+
f"--events {self.light_emission_config['number_of_events']}",
|
|
352
|
+
f"--photons {self.light_emission_config['flasher_photons']}",
|
|
353
|
+
f"--bunchsize {self.calibration_model.get_parameter_value('flasher_bunch_size')}",
|
|
354
|
+
f"--xy {flasher_xyz[0].to(u.cm).value},{flasher_xyz[1].to(u.cm).value}",
|
|
355
|
+
f"--distance {dist_cm}",
|
|
356
|
+
f"--camera-radius {camera_radius}",
|
|
357
|
+
f"--spectrum {int(flasher_wavelength.to(u.nm).value)}",
|
|
358
|
+
f"--lightpulse {self._get_pulse_shape_string_for_sim_telarray()}",
|
|
359
|
+
f"--angular-distribution {angular_distribution}",
|
|
360
|
+
]
|
|
361
|
+
|
|
362
|
+
def _add_illuminator_command_options(self):
|
|
363
|
+
"""Get illuminator-specific command options for light emission script."""
|
|
364
|
+
pos = self.light_emission_config.get("light_source_position")
|
|
365
|
+
if pos is None:
|
|
366
|
+
pos = self.calibration_model.get_parameter_value_with_unit(
|
|
472
367
|
"array_element_position_ground"
|
|
473
368
|
)
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
)
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
)
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
return command
|
|
369
|
+
x_cal, y_cal, z_cal = pos
|
|
370
|
+
if self.light_emission_config.get("light_source_pointing"):
|
|
371
|
+
pointing_vector = self.light_emission_config["light_source_pointing"]
|
|
372
|
+
else:
|
|
373
|
+
pointing_vector = self._calibration_pointing_direction(x_cal, y_cal, z_cal)[0]
|
|
374
|
+
flasher_wavelength = self.calibration_model.get_parameter_value_with_unit(
|
|
375
|
+
"flasher_wavelength"
|
|
376
|
+
)
|
|
377
|
+
angular_distribution = self._get_angular_distribution_string_for_sim_telarray()
|
|
378
|
+
|
|
379
|
+
return [
|
|
380
|
+
f"-x {x_cal.to(u.cm).value}",
|
|
381
|
+
f"-y {y_cal.to(u.cm).value}",
|
|
382
|
+
f"-z {z_cal.to(u.cm).value}",
|
|
383
|
+
f"-d {','.join(map(str, pointing_vector))}",
|
|
384
|
+
f"-n {self.light_emission_config['flasher_photons']}",
|
|
385
|
+
f"-s {int(flasher_wavelength.to(u.nm).value)}",
|
|
386
|
+
f"-p {self._get_pulse_shape_string_for_sim_telarray()}",
|
|
387
|
+
f"-a {angular_distribution}",
|
|
388
|
+
]
|
|
495
389
|
|
|
496
390
|
def _make_simtel_script(self):
|
|
497
391
|
"""
|
|
@@ -502,291 +396,102 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
502
396
|
str
|
|
503
397
|
The command to run sim_telarray
|
|
504
398
|
"""
|
|
505
|
-
|
|
506
|
-
if self.light_source_type == "flasher":
|
|
507
|
-
angles = [0, 0]
|
|
508
|
-
else:
|
|
509
|
-
_, angles = self.calibration_pointing_direction()
|
|
399
|
+
theta, phi = self._get_telescope_pointing()
|
|
510
400
|
|
|
511
401
|
simtel_bin = self._simtel_path.joinpath("sim_telarray/bin/sim_telarray/")
|
|
512
|
-
# Build command without prefix; caller will add SIM_TELARRAY_CONFIG_PATH once
|
|
513
|
-
command = f"{simtel_bin} "
|
|
514
|
-
command += f"-I{self._telescope_model.config_file_directory} "
|
|
515
|
-
command += f"-I{simtel_bin} "
|
|
516
|
-
command += f"-c {self._telescope_model.config_file_path} "
|
|
517
|
-
self._remove_line_from_config(self._telescope_model.config_file_path, "array_triggers")
|
|
518
|
-
self._remove_line_from_config(self._telescope_model.config_file_path, "axes_offsets")
|
|
519
|
-
|
|
520
|
-
command += "-DNUM_TELESCOPES=1 "
|
|
521
|
-
|
|
522
|
-
command += super().get_config_option(
|
|
523
|
-
"altitude",
|
|
524
|
-
self._site_model.get_parameter_value_with_unit("corsika_observation_level")
|
|
525
|
-
.to(u.m)
|
|
526
|
-
.value,
|
|
527
|
-
)
|
|
528
|
-
command += super().get_config_option(
|
|
529
|
-
"atmospheric_transmission",
|
|
530
|
-
self._site_model.get_parameter_value("atmospheric_transmission"),
|
|
531
|
-
)
|
|
532
|
-
command += super().get_config_option("TRIGGER_TELESCOPES", "1")
|
|
533
|
-
|
|
534
|
-
command += super().get_config_option("TELTRIG_MIN_SIGSUM", "2")
|
|
535
|
-
command += super().get_config_option("PULSE_ANALYSIS", "-30")
|
|
536
|
-
command += super().get_config_option("MAXIMUM_TELESCOPES", 1)
|
|
537
402
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
403
|
+
parts = [
|
|
404
|
+
f"{simtel_bin}",
|
|
405
|
+
f"-I{self.telescope_model.config_file_directory}",
|
|
406
|
+
f"-I{simtel_bin}",
|
|
407
|
+
f"-c {self.telescope_model.config_file_path}",
|
|
408
|
+
"-DNUM_TELESCOPES=1",
|
|
409
|
+
super().get_config_option(
|
|
410
|
+
"altitude",
|
|
411
|
+
self.site_model.get_parameter_value_with_unit("corsika_observation_level")
|
|
412
|
+
.to(u.m)
|
|
413
|
+
.value,
|
|
414
|
+
),
|
|
415
|
+
super().get_config_option(
|
|
416
|
+
"atmospheric_transmission",
|
|
417
|
+
self.site_model.get_parameter_value("atmospheric_transmission"),
|
|
418
|
+
),
|
|
419
|
+
super().get_config_option("TRIGGER_TELESCOPES", "1"),
|
|
420
|
+
super().get_config_option("TELTRIG_MIN_SIGSUM", "2"),
|
|
421
|
+
super().get_config_option("PULSE_ANALYSIS", "-30"),
|
|
422
|
+
super().get_config_option("MAXIMUM_TELESCOPES", 1),
|
|
423
|
+
super().get_config_option("telescope_theta", f"{theta}"),
|
|
424
|
+
super().get_config_option("telescope_phi", f"{phi}"),
|
|
425
|
+
]
|
|
426
|
+
|
|
427
|
+
if self.light_emission_config["light_source_type"] == "flat_fielding":
|
|
428
|
+
parts.append(super().get_config_option("Bypass_Optics", "1"))
|
|
429
|
+
|
|
430
|
+
app_name = self._get_light_emission_application_name()
|
|
551
431
|
pref = self._get_prefix()
|
|
552
|
-
|
|
553
|
-
"
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
"output_file",
|
|
565
|
-
f"{self.output_directory}/{pref}{app_name}_{app_mode}{dist_suffix}.simtel.zst",
|
|
566
|
-
)
|
|
567
|
-
command += super().get_config_option(
|
|
568
|
-
"histogram_file",
|
|
569
|
-
f"{self.output_directory}/{pref}{app_name}_{app_mode}{dist_suffix}.ctsim.hdata\n",
|
|
570
|
-
)
|
|
571
|
-
|
|
572
|
-
# Remove the default sim_telarray configuration directories
|
|
573
|
-
return clear_default_sim_telarray_cfg_directories(command)
|
|
574
|
-
|
|
575
|
-
def _remove_line_from_config(self, file_path, line_prefix):
|
|
576
|
-
"""
|
|
577
|
-
Remove lines starting with a specific prefix from the config.
|
|
578
|
-
|
|
579
|
-
Parameters
|
|
580
|
-
----------
|
|
581
|
-
file_path : Path
|
|
582
|
-
The path to the configuration file.
|
|
583
|
-
line_prefix : str
|
|
584
|
-
The prefix of lines to be removed.
|
|
585
|
-
"""
|
|
586
|
-
file_path = Path(file_path)
|
|
587
|
-
with file_path.open("r", encoding="utf-8") as file:
|
|
588
|
-
lines = file.readlines()
|
|
589
|
-
|
|
590
|
-
with file_path.open("w", encoding="utf-8") as file:
|
|
591
|
-
for line in lines:
|
|
592
|
-
if not line.startswith(line_prefix):
|
|
593
|
-
file.write(line)
|
|
594
|
-
|
|
595
|
-
def prepare_script(self):
|
|
596
|
-
"""
|
|
597
|
-
Build and return bash run script containing the light-emission command.
|
|
598
|
-
|
|
599
|
-
Returns
|
|
600
|
-
-------
|
|
601
|
-
Path
|
|
602
|
-
Full path of the run script.
|
|
603
|
-
"""
|
|
604
|
-
self._logger.debug("Creating run bash script")
|
|
605
|
-
|
|
606
|
-
_script_dir = self.output_directory.joinpath("scripts")
|
|
607
|
-
_script_dir.mkdir(parents=True, exist_ok=True)
|
|
608
|
-
_script_file = _script_dir.joinpath(f"{self._infer_application()[0]}-lightemission.sh")
|
|
609
|
-
self._logger.debug(f"Run bash script - {_script_file}")
|
|
610
|
-
|
|
611
|
-
target_out = Path(self._get_simulation_output_filename())
|
|
612
|
-
if target_out.exists():
|
|
613
|
-
msg = f"Simtel output file exists already, cancelling simulation: {target_out}"
|
|
614
|
-
self._logger.error(msg)
|
|
615
|
-
raise FileExistsError(msg)
|
|
616
|
-
|
|
617
|
-
command_le = self._make_light_emission_script()
|
|
618
|
-
command_simtel = self._make_simtel_script()
|
|
619
|
-
|
|
620
|
-
with _script_file.open("w", encoding="utf-8") as file:
|
|
621
|
-
file.write("#!/usr/bin/env bash\n")
|
|
622
|
-
|
|
623
|
-
file.write(f"{command_le}\n\n")
|
|
624
|
-
app_name, _ = self._infer_application()
|
|
625
|
-
file.write(
|
|
626
|
-
f"[ -s '{self.output_directory}/{app_name}.iact.gz' ] || "
|
|
627
|
-
f"{{ echo 'LightEmission did not produce IACT file' >&2; exit 1; }}\n\n"
|
|
628
|
-
)
|
|
629
|
-
file.write(f"{command_simtel}\n\n")
|
|
630
|
-
|
|
631
|
-
# Cleanup intermediate IACT file at the end of the run
|
|
632
|
-
file.write(f"rm -f '{self.output_directory}/{app_name}.iact.gz'\n\n")
|
|
633
|
-
|
|
634
|
-
_script_file.chmod(_script_file.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP)
|
|
635
|
-
return _script_file
|
|
432
|
+
parts += [
|
|
433
|
+
super().get_config_option("power_law", "2.68"),
|
|
434
|
+
super().get_config_option("input_file", f"{self.output_directory}/{app_name}.iact.gz"),
|
|
435
|
+
super().get_config_option(
|
|
436
|
+
"output_file", f"{self.output_directory}/{pref}{app_name}.simtel.zst"
|
|
437
|
+
),
|
|
438
|
+
super().get_config_option(
|
|
439
|
+
"histogram_file", f"{self.output_directory}/{pref}{app_name}.ctsim.hdata\n"
|
|
440
|
+
),
|
|
441
|
+
]
|
|
442
|
+
|
|
443
|
+
return clear_default_sim_telarray_cfg_directories(" ".join(parts))
|
|
636
444
|
|
|
637
445
|
def _get_simulation_output_filename(self):
|
|
638
446
|
"""Get the filename of the simulation output."""
|
|
639
|
-
|
|
640
|
-
if self.light_source_setup == "variable":
|
|
641
|
-
try:
|
|
642
|
-
dist_val = int(self._get_distance_for_plotting().to_value(u.m))
|
|
643
|
-
dist_suffix = f"_d_{dist_val}"
|
|
644
|
-
except Exception: # pylint:disable=broad-except
|
|
645
|
-
dist_suffix = ""
|
|
646
|
-
app_name, app_mode = self._infer_application()
|
|
447
|
+
app_name = self._get_light_emission_application_name()
|
|
647
448
|
pref = self._get_prefix()
|
|
648
|
-
return f"{self.output_directory}/{pref}{app_name}
|
|
449
|
+
return f"{self.output_directory}/{pref}{app_name}.simtel.zst"
|
|
649
450
|
|
|
650
|
-
def
|
|
651
|
-
"""Get the distance to be used for plotting as an astropy Quantity.
|
|
652
|
-
|
|
653
|
-
For flasher runs, use the flasher_depth (cm) from the flasher model.
|
|
654
|
-
For illuminator runs, use the configured z_pos quantity.
|
|
655
|
-
Otherwise, fall back to self.distance if set, or 0 m.
|
|
451
|
+
def calculate_distance_focal_plane_calibration_device(self):
|
|
656
452
|
"""
|
|
657
|
-
|
|
658
|
-
return self._flasher_model.get_parameter_value_with_unit("flasher_depth").to(u.m)
|
|
453
|
+
Calculate distance between focal plane and calibration device.
|
|
659
454
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
return val.to(u.m)
|
|
663
|
-
try:
|
|
664
|
-
return float(val) * u.m
|
|
665
|
-
except (TypeError, ValueError):
|
|
666
|
-
return None
|
|
667
|
-
|
|
668
|
-
cfg = self.light_emission_config or {}
|
|
669
|
-
z = cfg.get("z_pos")
|
|
670
|
-
if isinstance(z, dict):
|
|
671
|
-
z_def = z.get("default")
|
|
672
|
-
z_val = z_def[0] if isinstance(z_def, list | tuple) and z_def else z_def
|
|
673
|
-
z_q = _as_meters(z_val)
|
|
674
|
-
if z_q is not None:
|
|
675
|
-
return z_q
|
|
676
|
-
|
|
677
|
-
d_q = _as_meters(getattr(self, "distance", None))
|
|
678
|
-
if d_q is not None:
|
|
679
|
-
return d_q
|
|
680
|
-
|
|
681
|
-
return 0 * u.m
|
|
682
|
-
|
|
683
|
-
def run_simulation(self) -> Path:
|
|
684
|
-
"""Run the light emission simulation and return the output simtel file path."""
|
|
685
|
-
run_script = self.prepare_script()
|
|
686
|
-
log_path = Path(self.output_directory) / "logfile.log"
|
|
687
|
-
with open(log_path, "w", encoding="utf-8") as fh:
|
|
688
|
-
subprocess.run(
|
|
689
|
-
run_script,
|
|
690
|
-
shell=False,
|
|
691
|
-
check=False,
|
|
692
|
-
text=True,
|
|
693
|
-
stdout=fh,
|
|
694
|
-
stderr=fh,
|
|
695
|
-
)
|
|
696
|
-
out = Path(self._get_simulation_output_filename())
|
|
697
|
-
if not out.exists():
|
|
698
|
-
self._logger.warning(f"Expected simtel output not found: {out}")
|
|
699
|
-
return out
|
|
455
|
+
For flasher-type light sources. Flasher position is given in mirror coordinates,
|
|
456
|
+
with positive z pointing towards the camera, so the distance is focal_length - flasher_z.
|
|
700
457
|
|
|
701
|
-
|
|
458
|
+
Returns
|
|
459
|
+
-------
|
|
460
|
+
astropy.units.Quantity
|
|
461
|
+
Distance between calibration device and focal plane.
|
|
702
462
|
"""
|
|
703
|
-
|
|
463
|
+
focal_length = self.telescope_model.get_parameter_value_with_unit("focal_length").to(u.m)
|
|
464
|
+
flasher_z = self.calibration_model.get_parameter_value_with_unit("flasher_position")[2].to(
|
|
465
|
+
u.m
|
|
466
|
+
)
|
|
467
|
+
return focal_length - flasher_z
|
|
704
468
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
List of distances.
|
|
469
|
+
def _get_angular_distribution_string_for_sim_telarray(self):
|
|
470
|
+
"""
|
|
471
|
+
Get the angular distribution string for sim_telarray.
|
|
709
472
|
|
|
710
473
|
Returns
|
|
711
474
|
-------
|
|
712
|
-
|
|
713
|
-
|
|
475
|
+
str
|
|
476
|
+
The angular distribution string.
|
|
714
477
|
"""
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
478
|
+
option_string = self.calibration_model.get_parameter_value(
|
|
479
|
+
"flasher_angular_distribution"
|
|
480
|
+
).lower()
|
|
481
|
+
width = self.calibration_model.get_parameter_value_with_unit(
|
|
482
|
+
"flasher_angular_distribution_width"
|
|
483
|
+
)
|
|
484
|
+
return f"{option_string}:{width.to(u.deg).value}" if width is not None else option_string
|
|
719
485
|
|
|
720
|
-
def
|
|
721
|
-
"""
|
|
722
|
-
Update the light emission configuration.
|
|
723
|
-
|
|
724
|
-
Parameters
|
|
725
|
-
----------
|
|
726
|
-
key : str
|
|
727
|
-
The key in the configuration to update.
|
|
728
|
-
value : Any
|
|
729
|
-
The new value to set for the key.
|
|
486
|
+
def _get_pulse_shape_string_for_sim_telarray(self):
|
|
730
487
|
"""
|
|
731
|
-
|
|
732
|
-
self.light_emission_config[key]["default"] = value
|
|
733
|
-
else:
|
|
734
|
-
raise KeyError(f"Key '{key}' not found in light emission configuration.")
|
|
488
|
+
Get the pulse shape string for sim_telarray.
|
|
735
489
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
x_tel, y_tel, z_tel = self._telescope_model.get_parameter_value_with_unit(
|
|
745
|
-
"array_element_position_ground"
|
|
746
|
-
)
|
|
747
|
-
x_tel, y_tel, z_tel = [coord.to(u.m).value for coord in (x_tel, y_tel, z_tel)]
|
|
748
|
-
tel_vect = np.array([x_tel, y_tel, z_tel])
|
|
749
|
-
cal_vect = np.array([x_cal, y_cal, z_cal])
|
|
750
|
-
distance = np.linalg.norm(cal_vect - tel_vect)
|
|
751
|
-
self._logger.info(f"Distance between telescope and calibration device: {distance} m")
|
|
752
|
-
return [distance * u.m]
|
|
753
|
-
|
|
754
|
-
# Variable positions: Calculate distances for all positions
|
|
755
|
-
x_tel = self.light_emission_config["x_pos"]["default"].to(u.m).value
|
|
756
|
-
y_tel = self.light_emission_config["y_pos"]["default"].to(u.m).value
|
|
757
|
-
z_positions = self.light_emission_config["z_pos"]["default"]
|
|
758
|
-
|
|
759
|
-
distances = []
|
|
760
|
-
for z in z_positions:
|
|
761
|
-
tel_vect = np.array([x_tel, y_tel, z.to(u.m).value])
|
|
762
|
-
cal_vect = np.array([0, 0, 0]) # Calibration device at origin
|
|
763
|
-
distances.append(np.linalg.norm(cal_vect - tel_vect) * u.m)
|
|
764
|
-
return distances
|
|
765
|
-
|
|
766
|
-
def simulate_variable_distances(self, args_dict):
|
|
767
|
-
"""Simulate light emission for variable distances and return output files list."""
|
|
768
|
-
if args_dict["distances_ls"] is not None:
|
|
769
|
-
self.update_light_emission_config(
|
|
770
|
-
"z_pos", self.distance_list(args_dict["distances_ls"])
|
|
771
|
-
)
|
|
772
|
-
self._logger.info(
|
|
773
|
-
f"Simulating for distances: {self.light_emission_config['z_pos']['default']}"
|
|
774
|
-
)
|
|
775
|
-
outputs: list[Path] = []
|
|
776
|
-
distances = self.calculate_distance_telescope_calibration_device()
|
|
777
|
-
|
|
778
|
-
for current_distance, z_pos in zip(
|
|
779
|
-
distances, self.light_emission_config["z_pos"]["default"]
|
|
780
|
-
):
|
|
781
|
-
self.update_light_emission_config("z_pos", z_pos)
|
|
782
|
-
self.distance = current_distance
|
|
783
|
-
outputs.append(self.run_simulation())
|
|
784
|
-
return outputs
|
|
785
|
-
|
|
786
|
-
def simulate_layout_positions(self, args_dict): # pylint: disable=unused-argument
|
|
787
|
-
"""Simulate light emission for layout positions and return output files list."""
|
|
788
|
-
# args_dict kept for API symmetry; explicitly mark as unused
|
|
789
|
-
del args_dict
|
|
790
|
-
self.distance = self.calculate_distance_telescope_calibration_device()[0]
|
|
791
|
-
# Single distance for layout
|
|
792
|
-
return [self.run_simulation()]
|
|
490
|
+
Returns
|
|
491
|
+
-------
|
|
492
|
+
str
|
|
493
|
+
The pulse shape string.
|
|
494
|
+
"""
|
|
495
|
+
option_string = self.calibration_model.get_parameter_value("flasher_pulse_shape").lower()
|
|
496
|
+
width = self.calibration_model.get_parameter_value_with_unit("flasher_pulse_width")
|
|
497
|
+
return f"{option_string}:{width.to(u.ns).value}" if width is not None else option_string
|