Source code for runners.corsika_simtel_runner

"""Run simulations with CORSIKA and pipe it to sim_telarray using the multipipe functionality."""

import logging
import stat
from pathlib import Path

from simtools.runners.corsika_runner import CorsikaRunner
from simtools.simtel.simulator_array import SimulatorArray

__all__ = ["CorsikaSimtelRunner"]


[docs] class CorsikaSimtelRunner: """ Run simulations with CORSIKA and pipe it to sim_telarray using the multipipe functionality. Uses CorsikaConfig to manage the CORSIKA configuration and SimulatorArray for the sim_telarray configuration. Parameters ---------- corsika_config : CorsikaConfig Configuration parameters for CORSIKA. simtel_path : str or Path Location of the sim_telarray package. label : str Label. keep_seeds : bool Use seeds based on run number and primary particle. If False, use sim_telarray seeds. use_multipipe : bool Use multipipe to run CORSIKA and sim_telarray. """ def __init__( self, corsika_config, simtel_path, label=None, keep_seeds=False, use_multipipe=False, sim_telarray_seeds=None, ): self._logger = logging.getLogger(__name__) self.corsika_config = corsika_config self._simtel_path = simtel_path self.sim_telarray_seeds = sim_telarray_seeds self.label = label self.corsika_config.set_output_file_and_directory(use_multipipe) self.corsika_runner = CorsikaRunner( corsika_config=corsika_config, simtel_path=simtel_path, label=label, keep_seeds=keep_seeds, use_multipipe=use_multipipe, ) self.simulator_array = SimulatorArray( corsika_config=corsika_config, simtel_path=simtel_path, label=label, use_multipipe=use_multipipe, sim_telarray_seeds=sim_telarray_seeds, )
[docs] def prepare_run_script( self, run_number=None, input_file=None, extra_commands=None, use_pfp=False ): """ Get the full path of the run script file for a given run number. Parameters ---------- run_number: int Run number. use_pfp: bool Whether to use the preprocessor in preparing the CORSIKA input file Returns ------- Path: Full path of the run script file. """ self._export_multipipe_script(run_number) return self.corsika_runner.prepare_run_script( run_number=run_number, input_file=input_file, extra_commands=extra_commands, use_pfp=use_pfp, )
def _export_multipipe_script(self, run_number): """ Write the multipipe script used in piping CORSIKA to sim_telarray. Parameters ---------- run_number: int Run number. Returns ------- Path: Full path of the run script file. """ run_command = self._make_run_command( run_number=run_number, input_file="-", # instruct sim_telarray to take input from standard output ) multipipe_file = Path(self.corsika_config.config_file_path.parent).joinpath( self.corsika_config.get_corsika_config_file_name("multipipe") ) with open(multipipe_file, "w", encoding="utf-8") as file: file.write(f"{run_command}") self._logger.info(f"Multipipe script: {multipipe_file}") self._write_multipipe_script(multipipe_file) def _write_multipipe_script(self, multipipe_file): """ Write script used to call the multipipe_corsika command. Parameters ---------- multipipe_file: str or Path The name of the multipipe file which contains all of the multipipe commands. """ multipipe_script = Path(self.corsika_config.config_file_path.parent).joinpath( "run_cta_multipipe" ) with open(multipipe_script, "w", encoding="utf-8") as file: multipipe_command = Path(self._simtel_path).joinpath( "sim_telarray/bin/multipipe_corsika " f"-c {multipipe_file}" " || echo 'Fan-out failed'" ) file.write(f"{multipipe_command}") multipipe_script.chmod(multipipe_script.stat().st_mode | stat.S_IEXEC) def _make_run_command(self, run_number=None, input_file=None): """ Build and return the command to run simtel_array. Parameters ---------- run_number: int Run number. input_file: str Full path of the input CORSIKA file. Use '-' to tell sim_telarray to read from standard output Returns ------- str: Command to run sim_telarray. """ try: weak_pointing = any(pointing in self.label for pointing in ["divergent", "convergent"]) except TypeError: # allow for self.label to be None weak_pointing = False command = str(self._simtel_path.joinpath("sim_telarray/bin/sim_telarray")) command += f" -c {self.corsika_config.array_model.get_config_file()}" command += f" -I{self.corsika_config.array_model.get_config_directory()}" command += self.simulator_array.get_config_option( "telescope_theta", self.corsika_config.zenith_angle, weak_option=weak_pointing ) command += self.simulator_array.get_config_option( "telescope_phi", self.corsika_config.azimuth_angle, weak_option=weak_pointing ) command += self.simulator_array.get_config_option( "power_law", SimulatorArray.get_power_law_for_sim_telarray_histograms( self.corsika_config.primary_particle ), ) command += self.simulator_array.get_config_option( "histogram_file", self.get_file_name( simulation_software="simtel", file_type="histogram", run_number=run_number ), ) command += self.simulator_array.get_config_option("random_state", "none") if self.sim_telarray_seeds: command += self.simulator_array.get_config_option( "random_seed", self.sim_telarray_seeds ) command += self.simulator_array.get_config_option("show", "all") command += self.simulator_array.get_config_option( "output_file", self.simulator_array.get_file_name( simulation_software="simtel", file_type="output", run_number=run_number ), ) command += f" {input_file}" _log_file = self.simulator_array.get_file_name( simulation_software="simtel", file_type="log", run_number=run_number ) command += f" | gzip > {_log_file} 2>&1 || exit" return command
[docs] def get_file_name(self, simulation_software=None, file_type=None, run_number=None, mode=None): """ Get the full path of a file for a given run number. Parameters ---------- simulation_software: str Simulation software. file_type: str File type. run_number: int Run number. Returns ------- str File name with full path. """ if simulation_software is None: # preference to simtel output (multipipe) simulation_software = "simtel" if self.simulator_array else "corsika" runner = self.corsika_runner if simulation_software == "corsika" else self.simulator_array return runner.get_file_name(file_type=file_type, run_number=run_number, mode=mode)