gammasimtools 0.20.0__py3-none-any.whl → 0.22.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.20.0.dist-info → gammasimtools-0.22.0.dist-info}/METADATA +2 -3
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/RECORD +313 -296
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/entry_points.txt +3 -2
- simtools/_version.py +2 -2
- simtools/applications/calculate_incident_angles.py +1 -4
- simtools/applications/convert_all_model_parameters_from_simtel.py +1 -2
- simtools/applications/convert_model_parameter_from_simtel.py +0 -1
- simtools/applications/db_generate_compound_indexes.py +4 -17
- simtools/applications/db_upload_model_repository.py +122 -0
- simtools/applications/derive_psf_parameters.py +71 -42
- simtools/applications/docs_produce_array_element_report.py +1 -1
- simtools/applications/docs_produce_calibration_reports.py +1 -1
- simtools/applications/docs_produce_model_parameter_reports.py +1 -1
- simtools/applications/docs_produce_simulation_configuration_report.py +1 -1
- simtools/applications/generate_corsika_histograms.py +8 -185
- simtools/applications/maintain_simulation_model_add_production.py +81 -0
- simtools/applications/merge_tables.py +1 -1
- simtools/applications/plot_array_layout.py +1 -2
- simtools/applications/plot_simtel_events.py +2 -228
- simtools/applications/print_version.py +8 -7
- simtools/applications/production_derive_statistics.py +1 -2
- simtools/applications/production_generate_grid.py +1 -1
- simtools/applications/simulate_flasher.py +74 -72
- simtools/applications/simulate_illuminator.py +52 -186
- simtools/applications/{simulate_calibration_events.py → simulate_pedestals.py} +9 -55
- simtools/applications/submit_model_parameter_from_external.py +0 -1
- simtools/applications/validate_camera_efficiency.py +0 -1
- simtools/applications/validate_camera_fov.py +1 -2
- simtools/applications/validate_cumulative_psf.py +2 -3
- simtools/applications/validate_file_using_schema.py +20 -12
- simtools/applications/validate_optics.py +2 -2
- simtools/camera/camera_efficiency.py +8 -11
- simtools/configuration/commandline_parser.py +1 -7
- simtools/configuration/configurator.py +0 -2
- simtools/corsika/corsika_config.py +9 -11
- simtools/corsika/corsika_histograms.py +82 -1
- simtools/data_model/model_data_writer.py +87 -25
- simtools/data_model/schema.py +61 -2
- simtools/data_model/validate_data.py +1 -1
- simtools/db/db_handler.py +103 -48
- simtools/db/db_model_upload.py +247 -16
- simtools/io/io_handler.py +31 -83
- simtools/job_execution/job_manager.py +45 -0
- simtools/layout/array_layout_utils.py +1 -5
- simtools/model/array_model.py +93 -42
- simtools/model/model_parameter.py +20 -9
- simtools/model/model_repository.py +197 -109
- simtools/model/model_utils.py +21 -6
- simtools/model/telescope_model.py +20 -0
- simtools/production_configuration/derive_corsika_limits.py +1 -1
- simtools/ray_tracing/incident_angles.py +7 -7
- simtools/ray_tracing/mirror_panel_psf.py +1 -1
- simtools/ray_tracing/psf_parameter_optimisation.py +1106 -565
- simtools/ray_tracing/ray_tracing.py +1 -3
- simtools/reporting/docs_read_parameters.py +171 -101
- simtools/resources/array_elements.yml +26 -0
- simtools/runners/corsika_simtel_runner.py +11 -17
- simtools/runners/runner_services.py +5 -6
- 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/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_writer.py +88 -14
- simtools/simtel/simulator_array.py +44 -74
- simtools/simtel/simulator_light_emission.py +336 -629
- simtools/simtel/simulator_ray_tracing.py +2 -2
- simtools/simulator.py +46 -18
- simtools/testing/configuration.py +4 -2
- simtools/testing/sim_telarray_metadata.py +4 -4
- simtools/utils/geometry.py +34 -0
- simtools/version.py +111 -0
- simtools/{corsika/corsika_histograms_visualize.py → visualization/plot_corsika_histograms.py} +109 -0
- simtools/visualization/plot_psf.py +775 -0
- simtools/visualization/plot_simtel_events.py +284 -87
- simtools/applications/maintain_simulation_model_add_production_table.py +0 -71
- simtools/model/flasher_model.py +0 -106
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.22.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,202 @@ 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
|
|
16
|
+
from simtools.utils.geometry import fiducial_radius_from_shape
|
|
15
17
|
|
|
16
18
|
__all__ = ["SimulatorLightEmission"]
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class SimulatorLightEmission(SimtelRunner):
|
|
20
22
|
"""
|
|
21
|
-
|
|
23
|
+
Light emission simulation (e.g. illuminators or flashers).
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
"""
|
|
25
|
+
Uses the sim_telarray LightEmission package to simulate the light emission.
|
|
25
26
|
|
|
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)
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
light_emission_config : dict, optional
|
|
30
|
+
Configuration for the light emission (e.g. number of events, model names)
|
|
31
|
+
label : str, optional
|
|
32
|
+
Label for the simulation
|
|
33
|
+
"""
|
|
66
34
|
|
|
35
|
+
def __init__(self, light_emission_config, db_config=None, label=None):
|
|
36
|
+
"""Initialize SimulatorLightEmission."""
|
|
67
37
|
self._logger = logging.getLogger(__name__)
|
|
38
|
+
self.io_handler = io_handler.IOHandler()
|
|
68
39
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
40
|
+
super().__init__(
|
|
41
|
+
simtel_path=light_emission_config.get("simtel_path"), label=label, corsika_config=None
|
|
42
|
+
)
|
|
77
43
|
|
|
78
|
-
|
|
79
|
-
self.io_handler = io_handler.IOHandler()
|
|
80
|
-
self.output_directory = self.io_handler.get_output_directory(self.label)
|
|
44
|
+
self.output_directory = self.io_handler.get_output_directory(label)
|
|
81
45
|
|
|
82
|
-
self.
|
|
46
|
+
self.telescope_model, self.site_model, self.calibration_model = (
|
|
47
|
+
initialize_simulation_models(
|
|
48
|
+
label=label,
|
|
49
|
+
db_config=db_config,
|
|
50
|
+
site=light_emission_config.get("site"),
|
|
51
|
+
telescope_name=light_emission_config.get("telescope"),
|
|
52
|
+
calibration_device_name=light_emission_config.get("light_source"),
|
|
53
|
+
model_version=light_emission_config.get("model_version"),
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
self.telescope_model.write_sim_telarray_config_file(additional_models=self.site_model)
|
|
57
|
+
|
|
58
|
+
self.light_emission_config = self._initialize_light_emission_configuration(
|
|
59
|
+
light_emission_config
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def _initialize_light_emission_configuration(self, config):
|
|
63
|
+
"""Initialize light emission configuration."""
|
|
64
|
+
if self.calibration_model.get_parameter_value("flasher_type"):
|
|
65
|
+
config["light_source_type"] = self.calibration_model.get_parameter_value(
|
|
66
|
+
"flasher_type"
|
|
67
|
+
).lower()
|
|
68
|
+
|
|
69
|
+
config["flasher_photons"] = (
|
|
70
|
+
self.calibration_model.get_parameter_value("flasher_photons")
|
|
71
|
+
if not config.get("test", False)
|
|
72
|
+
else 1e8
|
|
73
|
+
)
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
self._calibration_model.get_parameter_value("photons_per_run")
|
|
88
|
-
if not self.test
|
|
89
|
-
else 1e8
|
|
75
|
+
if config.get("light_source_position") is not None:
|
|
76
|
+
config["light_source_position"] = (
|
|
77
|
+
np.array(config["light_source_position"], dtype=float) * u.m
|
|
90
78
|
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
79
|
+
|
|
80
|
+
return config
|
|
81
|
+
|
|
82
|
+
def simulate(self):
|
|
83
|
+
"""
|
|
84
|
+
Simulate light emission.
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
Path
|
|
89
|
+
The output simtel file path.
|
|
90
|
+
"""
|
|
91
|
+
run_script = self.prepare_script()
|
|
92
|
+
log_path = Path(self.output_directory) / "logfile.log"
|
|
93
|
+
with open(log_path, "w", encoding="utf-8") as fh:
|
|
94
|
+
subprocess.run(
|
|
95
|
+
run_script,
|
|
96
|
+
shell=False,
|
|
97
|
+
check=False,
|
|
98
|
+
text=True,
|
|
99
|
+
stdout=fh,
|
|
100
|
+
stderr=fh,
|
|
101
|
+
)
|
|
102
|
+
out = Path(self._get_simulation_output_filename())
|
|
103
|
+
if not out.exists():
|
|
104
|
+
self._logger.warning(f"Expected sim_telarray output not found: {out}")
|
|
105
|
+
return out
|
|
106
|
+
|
|
107
|
+
def prepare_script(self):
|
|
108
|
+
"""
|
|
109
|
+
Build and return bash run script containing the light-emission command.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
Path
|
|
114
|
+
Full path of the run script.
|
|
115
|
+
"""
|
|
116
|
+
script_dir = self.output_directory.joinpath("scripts")
|
|
117
|
+
script_dir.mkdir(parents=True, exist_ok=True)
|
|
118
|
+
|
|
119
|
+
app_name = self._get_light_emission_application_name()
|
|
120
|
+
script_file = script_dir / f"{app_name}-light_emission.sh"
|
|
121
|
+
self._logger.debug(f"Run bash script - {script_file}")
|
|
122
|
+
|
|
123
|
+
target_out = Path(self._get_simulation_output_filename())
|
|
124
|
+
if target_out.exists():
|
|
125
|
+
raise FileExistsError(
|
|
126
|
+
f"sim_telarray output file exists, cancelling simulation: {target_out}"
|
|
96
127
|
)
|
|
97
|
-
else:
|
|
98
|
-
self.photons_per_run = 1e8
|
|
99
128
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
self.
|
|
129
|
+
lines = [
|
|
130
|
+
"#!/usr/bin/env bash\n",
|
|
131
|
+
f"{self._make_light_emission_script()}\n\n",
|
|
132
|
+
(
|
|
133
|
+
f"[ -s '{self.output_directory}/{app_name}.iact.gz' ] || "
|
|
134
|
+
f"{{ echo 'LightEmission did not produce IACT file' >&2; exit 1; }}\n\n"
|
|
135
|
+
),
|
|
136
|
+
f"{self._make_simtel_script()}\n\n",
|
|
137
|
+
f"rm -f '{self.output_directory}/{app_name}.iact.gz'\n\n",
|
|
138
|
+
]
|
|
103
139
|
|
|
104
|
-
|
|
105
|
-
|
|
140
|
+
script_file.write_text("".join(lines), encoding="utf-8")
|
|
141
|
+
script_file.chmod(script_file.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP)
|
|
142
|
+
return script_file
|
|
106
143
|
|
|
107
|
-
def _get_prefix(self)
|
|
144
|
+
def _get_prefix(self):
|
|
108
145
|
prefix = self.light_emission_config.get("output_prefix", "")
|
|
109
146
|
if prefix is not None:
|
|
110
147
|
return f"{prefix}_"
|
|
111
148
|
return ""
|
|
112
149
|
|
|
113
|
-
def
|
|
114
|
-
"""
|
|
150
|
+
def _get_light_emission_application_name(self):
|
|
151
|
+
"""
|
|
152
|
+
Return the LightEmission application and mode from type.
|
|
115
153
|
|
|
116
154
|
Returns
|
|
117
155
|
-------
|
|
118
|
-
|
|
119
|
-
|
|
156
|
+
str
|
|
157
|
+
app_name
|
|
120
158
|
"""
|
|
121
|
-
if self.light_source_type == "
|
|
122
|
-
return
|
|
159
|
+
if self.light_emission_config["light_source_type"] == "flat_fielding":
|
|
160
|
+
return "ff-1m"
|
|
123
161
|
# default to illuminator xyzls, mode from setup
|
|
124
|
-
|
|
125
|
-
return ("xyzls", mode)
|
|
162
|
+
return "xyzls"
|
|
126
163
|
|
|
127
|
-
|
|
128
|
-
def light_emission_default_configuration():
|
|
164
|
+
def _get_telescope_pointing(self):
|
|
129
165
|
"""
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
Returns
|
|
133
|
-
-------
|
|
134
|
-
dict
|
|
135
|
-
Default configuration light emission.
|
|
166
|
+
Return telescope pointing based on light source type.
|
|
136
167
|
|
|
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.
|
|
168
|
+
For flat_fielding sims, avoid calibration pointing entirely; default angles to (0,0).
|
|
175
169
|
|
|
176
170
|
Returns
|
|
177
171
|
-------
|
|
178
|
-
|
|
179
|
-
|
|
172
|
+
tuple
|
|
173
|
+
The telescope pointing angles (theta, phi).
|
|
174
|
+
|
|
180
175
|
"""
|
|
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):
|
|
176
|
+
if self.light_emission_config["light_source_type"] == "flat_fielding":
|
|
177
|
+
return 0.0, 0.0
|
|
178
|
+
if self.light_emission_config.get("light_source_position") is not None:
|
|
179
|
+
self._logger.info("Using fixed (vertical up) telescope pointing.")
|
|
180
|
+
return 0.0, 0.0
|
|
181
|
+
_, angles = self._calibration_pointing_direction()
|
|
182
|
+
return angles[0], angles[1]
|
|
183
|
+
|
|
184
|
+
def _calibration_pointing_direction(self, x_cal=None, y_cal=None, z_cal=None):
|
|
245
185
|
"""
|
|
246
186
|
Calculate the pointing of the calibration device towards the telescope.
|
|
247
187
|
|
|
188
|
+
This is for calibration devices not installed on telescopes (e.g. illuminators).
|
|
189
|
+
|
|
248
190
|
Returns
|
|
249
191
|
-------
|
|
250
192
|
list
|
|
251
193
|
The pointing vector from the calibration device to the telescope.
|
|
252
194
|
"""
|
|
253
|
-
x_cal
|
|
254
|
-
|
|
255
|
-
|
|
195
|
+
if x_cal is None or y_cal is None or z_cal is None:
|
|
196
|
+
x_cal, y_cal, z_cal = self.calibration_model.get_parameter_value_with_unit(
|
|
197
|
+
"array_element_position_ground"
|
|
198
|
+
)
|
|
256
199
|
x_cal, y_cal, z_cal = [coord.to(u.m).value for coord in (x_cal, y_cal, z_cal)]
|
|
257
200
|
cal_vect = np.array([x_cal, y_cal, z_cal])
|
|
258
|
-
x_tel, y_tel, z_tel = self.
|
|
201
|
+
x_tel, y_tel, z_tel = self.telescope_model.get_parameter_value_with_unit(
|
|
259
202
|
"array_element_position_ground"
|
|
260
203
|
)
|
|
261
204
|
x_tel, y_tel, z_tel = [coord.to(u.m).value for coord in (x_tel, y_tel, z_tel)]
|
|
262
|
-
|
|
263
205
|
tel_vect = np.array([x_tel, y_tel, z_tel])
|
|
264
206
|
|
|
265
207
|
direction_vector = tel_vect - cal_vect
|
|
266
208
|
# pointing vector from calibration device to telescope
|
|
267
|
-
|
|
268
209
|
pointing_vector = np.round(direction_vector / np.linalg.norm(direction_vector), 6)
|
|
269
210
|
|
|
270
211
|
# Calculate telescope theta and phi angles
|
|
@@ -285,53 +226,52 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
285
226
|
)
|
|
286
227
|
return pointing_vector.tolist(), [tel_theta, tel_phi, source_theta, source_phi]
|
|
287
228
|
|
|
288
|
-
def
|
|
229
|
+
def _write_telescope_position_file(self):
|
|
289
230
|
"""
|
|
290
|
-
Write the telescope positions to a
|
|
231
|
+
Write the telescope positions to a telescope_position file.
|
|
291
232
|
|
|
292
233
|
The file will contain lines in the format: x y z r in cm
|
|
293
234
|
|
|
294
235
|
Returns
|
|
295
236
|
-------
|
|
296
237
|
Path
|
|
297
|
-
The path to the generated
|
|
238
|
+
The path to the generated telescope_position file.
|
|
298
239
|
"""
|
|
299
|
-
|
|
300
|
-
x_tel, y_tel, z_tel = self._telescope_model.get_parameter_value_with_unit(
|
|
240
|
+
x_tel, y_tel, z_tel = self.telescope_model.get_parameter_value_with_unit(
|
|
301
241
|
"array_element_position_ground"
|
|
302
242
|
)
|
|
303
243
|
x_tel, y_tel, z_tel = [coord.to(u.cm).value for coord in (x_tel, y_tel, z_tel)]
|
|
304
244
|
|
|
305
|
-
radius = self.
|
|
245
|
+
radius = self.telescope_model.get_parameter_value_with_unit("telescope_sphere_radius")
|
|
306
246
|
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
247
|
|
|
310
|
-
|
|
248
|
+
telescope_position_file = self.output_directory.joinpath("telescope_position.dat")
|
|
249
|
+
telescope_position_file.write_text(f"{x_tel} {y_tel} {z_tel} {radius}\n", encoding="utf-8")
|
|
250
|
+
return telescope_position_file
|
|
311
251
|
|
|
312
|
-
def _prepare_flasher_atmosphere_files(self, config_directory
|
|
313
|
-
"""
|
|
314
|
-
|
|
315
|
-
self._logger.debug(f"Using atmosphere profile: {atmo_name}")
|
|
252
|
+
def _prepare_flasher_atmosphere_files(self, config_directory, model_id=1):
|
|
253
|
+
"""
|
|
254
|
+
Prepare canonical atmosphere aliases for ff-1m and return model id.
|
|
316
255
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
256
|
+
The ff-1m tool requires atmosphere files atmprof1.dat or atm_profile_model_1.dat and
|
|
257
|
+
as configuration parameter the atmosphere id ('--atmosphere id').
|
|
258
|
+
|
|
259
|
+
"""
|
|
260
|
+
src_path = config_directory / self.site_model.get_parameter_value("atmospheric_profile")
|
|
261
|
+
self._logger.debug(f"Using atmosphere profile: {src_path}")
|
|
262
|
+
|
|
263
|
+
for name in (f"atmprof{model_id}.dat", f"atm_profile_model_{model_id}.dat"):
|
|
264
|
+
dst = config_directory / name
|
|
325
265
|
try:
|
|
326
|
-
dst.
|
|
327
|
-
|
|
266
|
+
if dst.exists() or dst.is_symlink():
|
|
267
|
+
dst.unlink()
|
|
328
268
|
try:
|
|
269
|
+
dst.symlink_to(src_path)
|
|
270
|
+
except OSError:
|
|
329
271
|
shutil.copy2(src_path, dst)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
)
|
|
334
|
-
return 1
|
|
272
|
+
except OSError as copy_err:
|
|
273
|
+
self._logger.warning(f"Failed to create atmosphere alias {dst.name}: {copy_err}")
|
|
274
|
+
return model_id
|
|
335
275
|
|
|
336
276
|
def _make_light_emission_script(self):
|
|
337
277
|
"""
|
|
@@ -345,153 +285,109 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
345
285
|
str
|
|
346
286
|
The commands to run the Light Emission package
|
|
347
287
|
"""
|
|
348
|
-
x_tel, y_tel, z_tel = self._telescope_model.get_parameter_value_with_unit(
|
|
349
|
-
"array_element_position_ground"
|
|
350
|
-
)
|
|
351
|
-
|
|
352
288
|
config_directory = self.io_handler.get_model_configuration_directory(
|
|
353
|
-
|
|
289
|
+
model_version=self.site_model.model_version
|
|
354
290
|
)
|
|
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(
|
|
291
|
+
app_name = self._get_light_emission_application_name()
|
|
292
|
+
corsika_observation_level = self.site_model.get_parameter_value_with_unit(
|
|
365
293
|
"corsika_observation_level"
|
|
366
294
|
)
|
|
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
|
-
|
|
382
|
-
return "".join(parts)
|
|
383
295
|
|
|
384
|
-
|
|
385
|
-
self
|
|
386
|
-
|
|
387
|
-
""
|
|
296
|
+
parts = [str(self._simtel_path / "sim_telarray/LightEmission") + f"/{app_name}"]
|
|
297
|
+
parts.extend(self._get_site_command(app_name, config_directory, corsika_observation_level))
|
|
298
|
+
parts.extend(self._get_light_source_command())
|
|
299
|
+
if self.light_emission_config["light_source_type"] == "illuminator":
|
|
300
|
+
parts += [
|
|
301
|
+
"-A",
|
|
302
|
+
(
|
|
303
|
+
f"{config_directory}/"
|
|
304
|
+
f"{self.telescope_model.get_parameter_value('atmospheric_profile')}"
|
|
305
|
+
),
|
|
306
|
+
]
|
|
307
|
+
parts += [f"-o {self.output_directory}/{app_name}.iact.gz", "\n"]
|
|
308
|
+
return " ".join(parts)
|
|
309
|
+
|
|
310
|
+
def _get_site_command(self, app_name, config_directory, corsika_observation_level):
|
|
311
|
+
"""Return site command with altitude, atmosphere and telescope_position handling."""
|
|
388
312
|
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
313
|
atmo_id = self._prepare_flasher_atmosphere_files(config_directory)
|
|
395
|
-
|
|
396
|
-
|
|
314
|
+
return [
|
|
315
|
+
"-I.",
|
|
316
|
+
f"-I{self._simtel_path / 'sim_telarray/cfg'}",
|
|
317
|
+
f"-I{config_directory}",
|
|
318
|
+
f"--altitude {corsika_observation_level.to(u.m).value}",
|
|
319
|
+
f"--atmosphere {atmo_id}",
|
|
320
|
+
]
|
|
397
321
|
# 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
|
-
|
|
322
|
+
return [
|
|
323
|
+
f"-h {corsika_observation_level.to(u.m).value} ",
|
|
324
|
+
f"--telpos-file {self._write_telescope_position_file()}",
|
|
325
|
+
]
|
|
326
|
+
|
|
327
|
+
def _get_light_source_command(self):
|
|
328
|
+
"""Return light-source specific command options."""
|
|
329
|
+
if self.light_emission_config["light_source_type"] == "flat_fielding":
|
|
330
|
+
return self._add_flasher_command_options()
|
|
331
|
+
if self.light_emission_config["light_source_type"] == "illuminator":
|
|
332
|
+
return self._add_illuminator_command_options()
|
|
333
|
+
raise ValueError(
|
|
334
|
+
f"Unknown light_source_type '{self.light_emission_config['light_source_type']}'"
|
|
335
|
+
)
|
|
412
336
|
|
|
413
|
-
def
|
|
337
|
+
def _add_flasher_command_options(self):
|
|
414
338
|
"""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")
|
|
339
|
+
flasher_xyz = self.calibration_model.get_parameter_value_with_unit("flasher_position")
|
|
340
|
+
camera_radius = fiducial_radius_from_shape(
|
|
341
|
+
self.telescope_model.get_parameter_value_with_unit("camera_body_diameter")
|
|
421
342
|
.to(u.cm)
|
|
422
|
-
.value
|
|
423
|
-
|
|
343
|
+
.value,
|
|
344
|
+
self.telescope_model.get_parameter_value("camera_body_shape"),
|
|
424
345
|
)
|
|
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(
|
|
346
|
+
flasher_wavelength = self.calibration_model.get_parameter_value_with_unit(
|
|
347
|
+
"flasher_wavelength"
|
|
348
|
+
)
|
|
349
|
+
dist_cm = self.calculate_distance_focal_plane_calibration_device().to(u.cm).value
|
|
350
|
+
angular_distribution = self._get_angular_distribution_string_for_sim_telarray()
|
|
351
|
+
|
|
352
|
+
return [
|
|
353
|
+
f"--events {self.light_emission_config['number_of_events']}",
|
|
354
|
+
f"--photons {self.light_emission_config['flasher_photons']}",
|
|
355
|
+
f"--bunchsize {self.calibration_model.get_parameter_value('flasher_bunch_size')}",
|
|
356
|
+
f"--xy {flasher_xyz[0].to(u.cm).value},{flasher_xyz[1].to(u.cm).value}",
|
|
357
|
+
f"--distance {dist_cm}",
|
|
358
|
+
f"--camera-radius {camera_radius}",
|
|
359
|
+
f"--spectrum {int(flasher_wavelength.to(u.nm).value)}",
|
|
360
|
+
f"--lightpulse {self._get_pulse_shape_string_for_sim_telarray()}",
|
|
361
|
+
f"--angular-distribution {angular_distribution}",
|
|
362
|
+
]
|
|
363
|
+
|
|
364
|
+
def _add_illuminator_command_options(self):
|
|
365
|
+
"""Get illuminator-specific command options for light emission script."""
|
|
366
|
+
pos = self.light_emission_config.get("light_source_position")
|
|
367
|
+
if pos is None:
|
|
368
|
+
pos = self.calibration_model.get_parameter_value_with_unit(
|
|
472
369
|
"array_element_position_ground"
|
|
473
370
|
)
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
)
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
)
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
return command
|
|
371
|
+
x_cal, y_cal, z_cal = pos
|
|
372
|
+
if self.light_emission_config.get("light_source_pointing"):
|
|
373
|
+
pointing_vector = self.light_emission_config["light_source_pointing"]
|
|
374
|
+
else:
|
|
375
|
+
pointing_vector = self._calibration_pointing_direction(x_cal, y_cal, z_cal)[0]
|
|
376
|
+
flasher_wavelength = self.calibration_model.get_parameter_value_with_unit(
|
|
377
|
+
"flasher_wavelength"
|
|
378
|
+
)
|
|
379
|
+
angular_distribution = self._get_angular_distribution_string_for_sim_telarray()
|
|
380
|
+
|
|
381
|
+
return [
|
|
382
|
+
f"-x {x_cal.to(u.cm).value}",
|
|
383
|
+
f"-y {y_cal.to(u.cm).value}",
|
|
384
|
+
f"-z {z_cal.to(u.cm).value}",
|
|
385
|
+
f"-d {','.join(map(str, pointing_vector))}",
|
|
386
|
+
f"-n {self.light_emission_config['flasher_photons']}",
|
|
387
|
+
f"-s {int(flasher_wavelength.to(u.nm).value)}",
|
|
388
|
+
f"-p {self._get_pulse_shape_string_for_sim_telarray()}",
|
|
389
|
+
f"-a {angular_distribution}",
|
|
390
|
+
]
|
|
495
391
|
|
|
496
392
|
def _make_simtel_script(self):
|
|
497
393
|
"""
|
|
@@ -502,291 +398,102 @@ class SimulatorLightEmission(SimtelRunner):
|
|
|
502
398
|
str
|
|
503
399
|
The command to run sim_telarray
|
|
504
400
|
"""
|
|
505
|
-
|
|
506
|
-
if self.light_source_type == "flasher":
|
|
507
|
-
angles = [0, 0]
|
|
508
|
-
else:
|
|
509
|
-
_, angles = self.calibration_pointing_direction()
|
|
401
|
+
theta, phi = self._get_telescope_pointing()
|
|
510
402
|
|
|
511
403
|
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
|
-
|
|
538
|
-
if self.light_source_type == "variable":
|
|
539
|
-
command += super().get_config_option("telescope_theta", 0)
|
|
540
|
-
command += super().get_config_option("telescope_phi", 0)
|
|
541
|
-
else:
|
|
542
|
-
command += super().get_config_option("telescope_theta", f"{angles[0]}")
|
|
543
|
-
command += super().get_config_option("telescope_phi", f"{angles[1]}")
|
|
544
|
-
|
|
545
|
-
# For flasher runs, bypass reflections on primary mirror
|
|
546
|
-
if self.light_source_type == "flasher":
|
|
547
|
-
command += super().get_config_option("Bypass_Optics", "1")
|
|
548
404
|
|
|
549
|
-
|
|
550
|
-
|
|
405
|
+
parts = [
|
|
406
|
+
f"{simtel_bin}",
|
|
407
|
+
f"-I{self.telescope_model.config_file_directory}",
|
|
408
|
+
f"-I{simtel_bin}",
|
|
409
|
+
f"-c {self.telescope_model.config_file_path}",
|
|
410
|
+
"-DNUM_TELESCOPES=1",
|
|
411
|
+
super().get_config_option(
|
|
412
|
+
"altitude",
|
|
413
|
+
self.site_model.get_parameter_value_with_unit("corsika_observation_level")
|
|
414
|
+
.to(u.m)
|
|
415
|
+
.value,
|
|
416
|
+
),
|
|
417
|
+
super().get_config_option(
|
|
418
|
+
"atmospheric_transmission",
|
|
419
|
+
self.site_model.get_parameter_value("atmospheric_transmission"),
|
|
420
|
+
),
|
|
421
|
+
super().get_config_option("TRIGGER_TELESCOPES", "1"),
|
|
422
|
+
super().get_config_option("TELTRIG_MIN_SIGSUM", "2"),
|
|
423
|
+
super().get_config_option("PULSE_ANALYSIS", "-30"),
|
|
424
|
+
super().get_config_option("MAXIMUM_TELESCOPES", 1),
|
|
425
|
+
super().get_config_option("telescope_theta", f"{theta}"),
|
|
426
|
+
super().get_config_option("telescope_phi", f"{phi}"),
|
|
427
|
+
]
|
|
428
|
+
|
|
429
|
+
if self.light_emission_config["light_source_type"] == "flat_fielding":
|
|
430
|
+
parts.append(super().get_config_option("Bypass_Optics", "1"))
|
|
431
|
+
|
|
432
|
+
app_name = self._get_light_emission_application_name()
|
|
551
433
|
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
|
|
434
|
+
parts += [
|
|
435
|
+
super().get_config_option("power_law", "2.68"),
|
|
436
|
+
super().get_config_option("input_file", f"{self.output_directory}/{app_name}.iact.gz"),
|
|
437
|
+
super().get_config_option(
|
|
438
|
+
"output_file", f"{self.output_directory}/{pref}{app_name}.simtel.zst"
|
|
439
|
+
),
|
|
440
|
+
super().get_config_option(
|
|
441
|
+
"histogram_file", f"{self.output_directory}/{pref}{app_name}.ctsim.hdata\n"
|
|
442
|
+
),
|
|
443
|
+
]
|
|
444
|
+
|
|
445
|
+
return clear_default_sim_telarray_cfg_directories(" ".join(parts))
|
|
636
446
|
|
|
637
447
|
def _get_simulation_output_filename(self):
|
|
638
448
|
"""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()
|
|
449
|
+
app_name = self._get_light_emission_application_name()
|
|
647
450
|
pref = self._get_prefix()
|
|
648
|
-
return f"{self.output_directory}/{pref}{app_name}
|
|
649
|
-
|
|
650
|
-
def _get_distance_for_plotting(self):
|
|
651
|
-
"""Get the distance to be used for plotting as an astropy Quantity.
|
|
451
|
+
return f"{self.output_directory}/{pref}{app_name}.simtel.zst"
|
|
652
452
|
|
|
653
|
-
|
|
654
|
-
For illuminator runs, use the configured z_pos quantity.
|
|
655
|
-
Otherwise, fall back to self.distance if set, or 0 m.
|
|
453
|
+
def calculate_distance_focal_plane_calibration_device(self):
|
|
656
454
|
"""
|
|
657
|
-
|
|
658
|
-
return self._flasher_model.get_parameter_value_with_unit("flasher_depth").to(u.m)
|
|
455
|
+
Calculate distance between focal plane and calibration device.
|
|
659
456
|
|
|
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
|
|
457
|
+
For flasher-type light sources. Flasher position is given in mirror coordinates,
|
|
458
|
+
with positive z pointing towards the camera, so the distance is focal_length - flasher_z.
|
|
700
459
|
|
|
701
|
-
|
|
460
|
+
Returns
|
|
461
|
+
-------
|
|
462
|
+
astropy.units.Quantity
|
|
463
|
+
Distance between calibration device and focal plane.
|
|
702
464
|
"""
|
|
703
|
-
|
|
465
|
+
focal_length = self.telescope_model.get_parameter_value_with_unit("focal_length").to(u.m)
|
|
466
|
+
flasher_z = self.calibration_model.get_parameter_value_with_unit("flasher_position")[2].to(
|
|
467
|
+
u.m
|
|
468
|
+
)
|
|
469
|
+
return focal_length - flasher_z
|
|
704
470
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
List of distances.
|
|
471
|
+
def _get_angular_distribution_string_for_sim_telarray(self):
|
|
472
|
+
"""
|
|
473
|
+
Get the angular distribution string for sim_telarray.
|
|
709
474
|
|
|
710
475
|
Returns
|
|
711
476
|
-------
|
|
712
|
-
|
|
713
|
-
|
|
477
|
+
str
|
|
478
|
+
The angular distribution string.
|
|
714
479
|
"""
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
480
|
+
option_string = self.calibration_model.get_parameter_value(
|
|
481
|
+
"flasher_angular_distribution"
|
|
482
|
+
).lower()
|
|
483
|
+
width = self.calibration_model.get_parameter_value_with_unit(
|
|
484
|
+
"flasher_angular_distribution_width"
|
|
485
|
+
)
|
|
486
|
+
return f"{option_string}:{width.to(u.deg).value}" if width is not None else option_string
|
|
719
487
|
|
|
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.
|
|
488
|
+
def _get_pulse_shape_string_for_sim_telarray(self):
|
|
730
489
|
"""
|
|
731
|
-
|
|
732
|
-
self.light_emission_config[key]["default"] = value
|
|
733
|
-
else:
|
|
734
|
-
raise KeyError(f"Key '{key}' not found in light emission configuration.")
|
|
490
|
+
Get the pulse shape string for sim_telarray.
|
|
735
491
|
|
|
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()]
|
|
492
|
+
Returns
|
|
493
|
+
-------
|
|
494
|
+
str
|
|
495
|
+
The pulse shape string.
|
|
496
|
+
"""
|
|
497
|
+
option_string = self.calibration_model.get_parameter_value("flasher_pulse_shape").lower()
|
|
498
|
+
width = self.calibration_model.get_parameter_value_with_unit("flasher_pulse_width")
|
|
499
|
+
return f"{option_string}:{width.to(u.ns).value}" if width is not None else option_string
|