Source code for simtel.simulator_array

"""Simulation runner for array simulations."""

import logging

from simtools.io import io_handler
from simtools.runners.simtel_runner import InvalidOutputFileError, SimtelRunner
from simtools.utils.general import clear_default_sim_telarray_cfg_directories

__all__ = ["SimulatorArray"]


[docs] class SimulatorArray(SimtelRunner): """ SimulatorArray is the interface with sim_telarray to perform array simulations. Parameters ---------- corsika_config_data: CorsikaConfig CORSIKA configuration. simtel_path: str or Path Location of source of the sim_telarray/CORSIKA package. label: str Instance label. use_multipipe: bool Use multipipe to run CORSIKA and sim_telarray. sim_telarray_seeds: dict Dictionary with configuration for sim_telarray random instrument setup. """ def __init__( self, corsika_config, simtel_path, label=None, use_multipipe=False, sim_telarray_seeds=None, ): """Initialize SimulatorArray.""" self._logger = logging.getLogger(__name__) self._logger.debug("Init SimulatorArray") super().__init__( label=label, simtel_path=simtel_path, corsika_config=corsika_config, use_multipipe=use_multipipe, ) self.sim_telarray_seeds = sim_telarray_seeds self.corsika_config = corsika_config self.io_handler = io_handler.IOHandler() self._log_file = None
[docs] def make_run_command(self, run_number=None, input_file=None, weak_pointing=None): """ Build and return the command to run sim_telarray. Parameters ---------- input_file: str Full path of the input CORSIKA file run_number: int (optional) run number weak_pointing: bool (optional) Specify weak pointing option for sim_telarray. Returns ------- str Command to run sim_telarray. """ command = self._common_run_command(run_number, weak_pointing) command += f" {input_file}" command += f" | gzip > {self._log_file} 2>&1 || exit" command += super().get_config_option( "power_law", SimulatorArray.get_power_law_for_sim_telarray_histograms( self.corsika_config.primary_particle ), ) return clear_default_sim_telarray_cfg_directories(command)
[docs] def make_run_command_for_calibration_simulations( self, run_number=None, input_file=None, calibration_runner_args=None ): """ Build and return the command to run sim_telarray for calibration simulations. Parameters ---------- calibration_runner_args: dict Dictionary with calibration runner arguments. input_file: str Full path of the input CORSIKA file run_number: int (optional) run number Returns ------- str Command to run sim_telarray for pedestal simulations. """ command = self._common_run_command(run_number) command += super().get_config_option( "Altitude", self.corsika_config.array_model.site_model.get_parameter_value_with_unit( "reference_point_altitude" ).to_value("m"), ) command += super().get_config_option( "nsb_scaling_factor", calibration_runner_args["nsb_scaling_factor"] ) if calibration_runner_args.get("stars"): command += super().get_config_option("stars", calibration_runner_args["stars"]) if calibration_runner_args.get("run_mode") in ("pedestals", "nsb_only_pedestals"): command += super().get_config_option( "pedestal_events", calibration_runner_args["number_of_events"] ) if calibration_runner_args.get("run_mode") == "nsb_only_pedestals": command += self._nsb_only_pedestals_command() if calibration_runner_args.get("run_mode") == "dark_pedestals": command += super().get_config_option( "dark_events", calibration_runner_args["number_of_events"] ) if calibration_runner_args.get("run_mode") == "flasher": command += self._flasher_command(calibration_runner_args) command += f" {input_file}" command += f" | gzip > {self._log_file} 2>&1 || exit" return clear_default_sim_telarray_cfg_directories(command)
def _common_run_command(self, run_number, weak_pointing=None): """Build generic run command for sim_telarray.""" config_dir = self.corsika_config.array_model.get_config_directory() self._log_file = self.get_file_name(file_type="log", run_number=run_number) histogram_file = self.get_file_name(file_type="histogram", run_number=run_number) output_file = self.get_file_name(file_type="simtel_output", run_number=run_number) self.corsika_config.array_model.export_all_simtel_config_files() command = str(self._simtel_path.joinpath("sim_telarray/bin/sim_telarray")) command += f" -c {self.corsika_config.array_model.config_file_path}" command += f" -I{config_dir}" command += super().get_config_option( "telescope_theta", self.corsika_config.zenith_angle, weak_pointing ) command += super().get_config_option( "telescope_phi", self.corsika_config.azimuth_angle, weak_pointing ) command += super().get_config_option("histogram_file", histogram_file) command += super().get_config_option("random_state", "none") if self.sim_telarray_seeds and self.sim_telarray_seeds.get("random_instrument_instances"): command += super().get_config_option( "random_seed", f"file-by-run:{config_dir}/{self.sim_telarray_seeds['seed_file_name']},auto", ) elif self.sim_telarray_seeds and self.sim_telarray_seeds.get("seed"): command += super().get_config_option("random_seed", self.sim_telarray_seeds["seed"]) command += super().get_config_option("show", "all") command += super().get_config_option("output_file", output_file) return command def _flasher_command(self, calibration_runner_args): """ Generate the command to run sim_telarray for flasher simulations. Parameters ---------- calibration_runner_args: dict Dictionary with calibration runner arguments. Returns ------- str Command to run sim_telarray for flasher simulations. """ command = super().get_config_option( "laser_events", calibration_runner_args["number_of_events"] ) command += super().get_config_option( "laser_photons", calibration_runner_args["flasher_photons"] ) command += super().get_config_option( "laser_var_photons", calibration_runner_args["flasher_var_photons"] ) command += super().get_config_option( "laser_pulse_exptime", calibration_runner_args["flasher_exp_time"] ) command += super().get_config_option( "laser_pulse_sigtime", calibration_runner_args["flasher_sig_time"] ) command += super().get_config_option("laser_external_trigger", 1) return command def _nsb_only_pedestals_command(self): """ Generate the command to run sim_telarray for nsb-only pedestal simulations. Returns ------- str Command to run sim_telarray. """ null_values = [ "fadc_noise", "fadc_lg_noise", "qe_variation", "gain_variation", "fadc_var_pedestal", "fadc_err_pedestal", "fadc_sysvar_pedestal", "fadc_dev_pedestal", ] null_command_parts = [] for param in null_values: null_command_parts.append(super().get_config_option(param, 0.0)) command = " ".join(null_command_parts) one_values = [ "fadc_lg_var_pedestal", "fadc_lg_err_pedestal", "fadc_lg_dev_pedestal", "fadc_lg_sysvar_pedestal", ] one_command_parts = [] for param in one_values: one_command_parts.append(super().get_config_option(param, -1.0)) command += " " + " ".join(one_command_parts) return command def _check_run_result(self, run_number=None): """ Check if simtel output file exists. Parameters ---------- run_number: int Run number. Returns ------- bool True if simtel output file exists. Raises ------ InvalidOutputFileError If simtel output file does not exist. """ output_file = self.get_file_name(file_type="simtel_output", run_number=run_number) if not output_file.exists(): msg = f"sim_telarray output file {output_file} does not exist." self._logger.error(msg) raise InvalidOutputFileError(msg) self._logger.debug(f"sim_telarray output file {output_file} exists.") return True
[docs] @staticmethod def get_power_law_for_sim_telarray_histograms(primary): """ Get the power law index for sim_telarray. Events will be histogrammed in sim_telarray with a weight according to the difference between this exponent and the one used for the shower simulations. Parameters ---------- primary: str Primary particle. Returns ------- float Power law index. """ power_laws = { "gamma": 2.5, "electron": 3.3, } if primary.name in power_laws: return power_laws[primary.name] return 2.68