Source code for plot_simtel_events

#!/usr/bin/python3

r"""
Plot simulated events.

Produces figures from one or more sim_telarray (.simtel.zst) files
It is meant to run after simulations (e.g., simtools-simulate-flasher,
simtools-simulate-illuminator).

What it does
------------
- Loads each provided sim_telarray file
- Generates selected plots (camera image, time traces, waveform matrices, peak timing, etc.)
- Optionally saves all figures to a single multi-page PDF per input file
- Optionally also saves individual PNGs

Command line arguments
----------------------
simtel_files (list, required)
    One or more sim_telarray files to visualize (.simtel.zst).
plots (list, optional)
    Which plots to generate. Choose from: event_image, time_traces, waveform_matrix,
    step_traces, integrated_signal_image, integrated_pedestal_image, peak_timing, all.
    Default: event_image.
tel_id (int, optional)
    Telescope ID to visualize. If omitted, the first available telescope will be used.
n_pixels (int, optional)
    For time_traces: number of pixel traces to draw. Default: 3.
pixel_step (int, optional)
    For step_traces and waveform_matrix: step between pixel indices. Default: 100.
max_pixels (int, optional)
    For step_traces: cap the number of plotted pixels. Default: None.
vmax (float, optional)
    For waveform_matrix: upper limit of color scale. Default: None.
half_width (int, optional)
    For integrated_*_image: half window width in samples. Default: 8.
offset (int, optional)
    For integrated_pedestal_image: offset between pedestal and peak windows. Default: 16.
sum_threshold (float, optional)
    For peak_timing: minimum pixel sum to consider a pixel. Default: 10.0.
peak_width (int, optional)
    For peak_timing: expected peak width in samples. Default: 8.
examples (int, optional)
    For peak_timing: show example traces. Default: 3.
timing_bins (int, optional)
    For peak_timing: number of histogram bins for peak sample. Default: None (contiguous bins).
distance (float, optional)
    Optional distance annotation for event_image.
output_file (str, optional)
    Base name for output. If provided, outputs will be placed under the standard IOHandler
    output directory and named ``<base>_<inputstem>.pdf``. If omitted, defaults are derived
    from each input file name.
save_pngs (flag, optional)
    Also save individual PNG files per figure.
dpi (int, optional)
    DPI for PNG outputs. Default: 300.
output_path (str, optional)
    Path to save the output files.

Examples
--------
1) Camera image and time traces for a single file, save a PDF:

   simtools-plot-simtel-events \
     --simtel_files tests/resources/ff-1m_flasher.simtel.zst \
     --plots event_image time_traces \
     --tel_id 1 \
     --output_file simulate_illuminator_inspect

2) All plots for multiple files, PNGs and PDFs:

   simtools-plot-simtel-events \
     --simtel_files f1.simtel.zst f2.simtel.zst \
     --plots all \
     --save_pngs --dpi 200

"""

from pathlib import Path

import simtools.utils.general as gen
from simtools.application_control import get_application_label, startup_application
from simtools.configuration import configurator
from simtools.visualization.plot_simtel_events import PLOT_CHOICES, generate_and_save_plots


def _parse():
    """Parse command line configuration."""
    config = configurator.Configurator(
        label=get_application_label(__file__),
        description=(
            "Create diagnostic plots from sim_telarray files using simtools visualization."
        ),
    )

    config.parser.add_argument(
        "--simtel_files",
        help="One or more sim_telarray files (.simtel.zst)",
        nargs="+",
        required=True,
    )
    config.parser.add_argument(
        "--plots",
        help=f"Plots to generate. Choices: {', '.join(sorted(PLOT_CHOICES))}",
        nargs="+",
        default=["event_image"],
        choices=sorted(PLOT_CHOICES),
    )
    config.parser.add_argument("--tel_id", type=int, default=None, help="Telescope ID")
    config.parser.add_argument(
        "--n_pixels", type=int, default=3, help="For time_traces: number of pixel traces"
    )
    config.parser.add_argument(
        "--pixel_step", type=int, default=100, help="Step between pixel ids for step plots"
    )
    config.parser.add_argument(
        "--max_pixels", type=int, default=None, help="Cap number of pixels for step traces"
    )
    config.parser.add_argument("--vmax", type=float, default=None, help="Color scale vmax")
    config.parser.add_argument(
        "--half_width", type=int, default=8, help="Half window width for integrated images"
    )
    config.parser.add_argument(
        "--offset",
        type=int,
        default=16,
        help="offset between pedestal and peak windows (integrated_pedestal_image)",
    )
    config.parser.add_argument(
        "--sum_threshold",
        type=float,
        default=10.0,
        help="Minimum pixel sum to consider in peak timing",
    )
    config.parser.add_argument(
        "--peak_width", type=int, default=8, help="Expected peak width in samples"
    )
    config.parser.add_argument(
        "--examples", type=int, default=3, help="Number of example traces to draw"
    )
    config.parser.add_argument(
        "--timing_bins",
        type=int,
        default=None,
        help="Number of bins for timing histogram (contiguous if not set)",
    )
    config.parser.add_argument(
        "--distance",
        type=float,
        default=None,
        help="Optional distance annotation for event_image (same units as input expects)",
    )
    config.parser.add_argument(
        "--event_index",
        type=int,
        default=None,
        help="0-based index of the event to plot; default is the first event",
    )
    config.parser.add_argument(
        "--output_file",
        type=str,
        default=None,
        help=(
            "Base name for output. If set, PDFs will be named '<base>_<inputstem>.pdf' "
            "in the standard output directory"
        ),
    )
    config.parser.add_argument(
        "--save_pngs",
        action="store_true",
        help="Also save individual PNG images per plot",
    )
    config.parser.add_argument("--dpi", type=int, default=300, help="PNG dpi")

    return config.initialize(db_config=False, require_command_line=True)


[docs] def main(): """Generate plots from sim_telarray files.""" app_context = startup_application(_parse) simtel_files = [ Path(p).expanduser() for p in gen.ensure_iterable(app_context.args["simtel_files"]) ] plots = list(gen.ensure_iterable(app_context.args.get("plots"))) generate_and_save_plots( simtel_files=simtel_files, plots=plots, args=app_context.args, ioh=app_context.io_handler )
if __name__ == "__main__": main()