gammasimtools 0.20.0__py3-none-any.whl → 0.21.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.21.0.dist-info}/METADATA +1 -1
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.21.0.dist-info}/RECORD +24 -23
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.21.0.dist-info}/entry_points.txt +1 -1
- simtools/_version.py +2 -2
- simtools/applications/db_generate_compound_indexes.py +1 -1
- simtools/applications/derive_psf_parameters.py +58 -39
- simtools/applications/generate_corsika_histograms.py +7 -184
- simtools/applications/maintain_simulation_model_add_production.py +105 -0
- simtools/applications/plot_simtel_events.py +2 -228
- simtools/applications/print_version.py +8 -7
- simtools/corsika/corsika_histograms.py +81 -0
- simtools/db/db_handler.py +45 -11
- simtools/db/db_model_upload.py +40 -14
- simtools/model/model_repository.py +118 -63
- simtools/ray_tracing/psf_parameter_optimisation.py +999 -565
- simtools/simtel/simtel_config_writer.py +1 -1
- simtools/simulator.py +1 -4
- simtools/version.py +89 -0
- simtools/{corsika/corsika_histograms_visualize.py → visualization/plot_corsika_histograms.py} +109 -0
- simtools/visualization/plot_psf.py +673 -0
- simtools/visualization/plot_simtel_events.py +284 -87
- simtools/applications/maintain_simulation_model_add_production_table.py +0 -71
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.21.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.21.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.20.0.dist-info → gammasimtools-0.21.0.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""Plots for light emission (flasher/calibration) sim_telarray events."""
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
import astropy.units as u
|
|
7
8
|
import matplotlib.pyplot as plt
|
|
@@ -11,7 +12,12 @@ from ctapipe.io import EventSource
|
|
|
11
12
|
from ctapipe.visualization import CameraDisplay
|
|
12
13
|
from scipy import signal as _signal
|
|
13
14
|
|
|
15
|
+
from simtools.data_model.metadata_collector import MetadataCollector
|
|
16
|
+
from simtools.visualization.plot_corsika_histograms import save_figs_to_pdf
|
|
17
|
+
from simtools.visualization.visualize import save_figure
|
|
18
|
+
|
|
14
19
|
__all__ = [
|
|
20
|
+
"generate_and_save_plots",
|
|
15
21
|
"plot_simtel_event_image",
|
|
16
22
|
"plot_simtel_integrated_pedestal_image",
|
|
17
23
|
"plot_simtel_integrated_signal_image",
|
|
@@ -29,10 +35,45 @@ NO_R1_WAVEFORMS_MSG = "No R1 waveforms available in event"
|
|
|
29
35
|
TIME_NS_LABEL = "time [ns]"
|
|
30
36
|
R1_SAMPLES_LABEL = "R1 samples [d.c.]"
|
|
31
37
|
|
|
38
|
+
# Choices understood by the dispatcher used below
|
|
39
|
+
PLOT_CHOICES = {
|
|
40
|
+
"event_image": "event_image",
|
|
41
|
+
"time_traces": "time_traces",
|
|
42
|
+
"waveform_matrix": "waveform_matrix",
|
|
43
|
+
"step_traces": "step_traces",
|
|
44
|
+
"integrated_signal_image": "integrated_signal_image",
|
|
45
|
+
"integrated_pedestal_image": "integrated_pedestal_image",
|
|
46
|
+
"peak_timing": "peak_timing",
|
|
47
|
+
"all": "all",
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _get_event_source_and_r1_tel(filename, event_index=None, warn_context=None):
|
|
52
|
+
"""Return (source, event, first_r1_tel_id) or None if unavailable.
|
|
32
53
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
54
|
+
Centralizes creation of EventSource, event selection, and first R1 tel-id lookup.
|
|
55
|
+
|
|
56
|
+
When no event exists, logs a standard warning. When the event has no R1 tel data,
|
|
57
|
+
logs either a contextual message ("Event has no R1 data for <context>") if
|
|
58
|
+
warn_context is provided, or the generic "First event has no R1 telescope data".
|
|
59
|
+
"""
|
|
60
|
+
source = EventSource(filename, max_events=None)
|
|
61
|
+
event = _select_event_by_type(source)(event_index=event_index)
|
|
62
|
+
if not event:
|
|
63
|
+
_logger.warning("No event found in the file.")
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
tel_ids = sorted(getattr(event.r1, "tel", {}).keys())
|
|
67
|
+
if not tel_ids:
|
|
68
|
+
if warn_context:
|
|
69
|
+
_logger.warning("Event has no R1 data for %s", warn_context)
|
|
70
|
+
else:
|
|
71
|
+
_logger.warning("First event has no R1 telescope data")
|
|
72
|
+
return None
|
|
73
|
+
return source, event, int(tel_ids[0])
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _compute_integration_window(peak_idx, n_samp, half_width, mode, offset):
|
|
36
77
|
"""Return [a, b) window bounds for integration for signal/pedestal modes."""
|
|
37
78
|
hw = int(half_width)
|
|
38
79
|
win_len = 2 * hw + 1
|
|
@@ -53,9 +94,7 @@ def _compute_integration_window(
|
|
|
53
94
|
return a, b
|
|
54
95
|
|
|
55
96
|
|
|
56
|
-
def _format_integrated_title(
|
|
57
|
-
tel_label: str, et_name: str, half_width: int, mode: str, offset: int | None
|
|
58
|
-
) -> str:
|
|
97
|
+
def _format_integrated_title(tel_label, et_name, half_width, mode, offset):
|
|
59
98
|
win_len = 2 * int(half_width) + 1
|
|
60
99
|
if mode == "signal":
|
|
61
100
|
return f"{tel_label} integrated signal (win {win_len}) ({et_name})"
|
|
@@ -138,17 +177,10 @@ def plot_simtel_event_image(filename, distance=None, event_index=None):
|
|
|
138
177
|
matplotlib.figure.Figure | None
|
|
139
178
|
The created figure, or ``None`` if no suitable event/image is available.
|
|
140
179
|
"""
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if not event:
|
|
144
|
-
_logger.warning("No event found in the file.")
|
|
145
|
-
return None
|
|
146
|
-
|
|
147
|
-
tel_ids = sorted(getattr(event.r1, "tel", {}).keys())
|
|
148
|
-
if not tel_ids:
|
|
149
|
-
_logger.warning("First event has no R1 telescope data")
|
|
180
|
+
prepared = _get_event_source_and_r1_tel(filename, event_index=event_index, warn_context=None)
|
|
181
|
+
if prepared is None:
|
|
150
182
|
return None
|
|
151
|
-
tel_id =
|
|
183
|
+
source, event, tel_id = prepared
|
|
152
184
|
|
|
153
185
|
calib = CameraCalibrator(subarray=source.subarray)
|
|
154
186
|
calib(event)
|
|
@@ -198,9 +230,9 @@ def plot_simtel_event_image(filename, distance=None, event_index=None):
|
|
|
198
230
|
|
|
199
231
|
def plot_simtel_time_traces(
|
|
200
232
|
filename,
|
|
201
|
-
tel_id
|
|
202
|
-
n_pixels
|
|
203
|
-
event_index
|
|
233
|
+
tel_id=None,
|
|
234
|
+
n_pixels=3,
|
|
235
|
+
event_index=None,
|
|
204
236
|
):
|
|
205
237
|
"""
|
|
206
238
|
Plot R1 time traces for a few pixels of one event.
|
|
@@ -221,15 +253,13 @@ def plot_simtel_time_traces(
|
|
|
221
253
|
matplotlib.figure.Figure | None
|
|
222
254
|
The created figure, or ``None`` if R1 waveforms are unavailable.
|
|
223
255
|
"""
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
dl1_tel_ids = sorted(getattr(event.dl1, "tel", {}).keys())
|
|
232
|
-
tel_id = tel_id or dl1_tel_ids[0]
|
|
256
|
+
prepared = _get_event_source_and_r1_tel(
|
|
257
|
+
filename, event_index=event_index, warn_context="time traces plot"
|
|
258
|
+
)
|
|
259
|
+
if prepared is None:
|
|
260
|
+
return None
|
|
261
|
+
source, event, tel_id_default = prepared
|
|
262
|
+
tel_id = tel_id or tel_id_default
|
|
233
263
|
|
|
234
264
|
calib = CameraCalibrator(subarray=source.subarray)
|
|
235
265
|
try:
|
|
@@ -273,10 +303,10 @@ def plot_simtel_time_traces(
|
|
|
273
303
|
|
|
274
304
|
def plot_simtel_waveform_matrix(
|
|
275
305
|
filename,
|
|
276
|
-
tel_id
|
|
277
|
-
vmax
|
|
278
|
-
event_index
|
|
279
|
-
pixel_step
|
|
306
|
+
tel_id=None,
|
|
307
|
+
vmax=None,
|
|
308
|
+
event_index=None,
|
|
309
|
+
pixel_step=None,
|
|
280
310
|
):
|
|
281
311
|
"""
|
|
282
312
|
Create a pseudocolor image of R1 waveforms (sample index vs. pixel id).
|
|
@@ -299,15 +329,13 @@ def plot_simtel_waveform_matrix(
|
|
|
299
329
|
matplotlib.figure.Figure | None
|
|
300
330
|
The created figure, or ``None`` if R1 waveforms are unavailable.
|
|
301
331
|
"""
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if r1_tel_ids:
|
|
307
|
-
tel_id = tel_id or r1_tel_ids[0]
|
|
308
|
-
else:
|
|
309
|
-
_logger.warning("Event has no R1 data for waveform plot")
|
|
332
|
+
prepared = _get_event_source_and_r1_tel(
|
|
333
|
+
filename, event_index=event_index, warn_context="waveform plot"
|
|
334
|
+
)
|
|
335
|
+
if prepared is None:
|
|
310
336
|
return None
|
|
337
|
+
source, event, tel_id_default = prepared
|
|
338
|
+
tel_id = tel_id or tel_id_default
|
|
311
339
|
|
|
312
340
|
waveforms = getattr(event.r1.tel.get(tel_id, None), "waveform", None)
|
|
313
341
|
if waveforms is None:
|
|
@@ -342,10 +370,10 @@ def plot_simtel_waveform_matrix(
|
|
|
342
370
|
|
|
343
371
|
def plot_simtel_step_traces(
|
|
344
372
|
filename,
|
|
345
|
-
tel_id
|
|
346
|
-
pixel_step
|
|
347
|
-
max_pixels
|
|
348
|
-
event_index
|
|
373
|
+
tel_id=None,
|
|
374
|
+
pixel_step=100,
|
|
375
|
+
max_pixels=None,
|
|
376
|
+
event_index=None,
|
|
349
377
|
):
|
|
350
378
|
"""
|
|
351
379
|
Plot step-style R1 traces for regularly sampled pixels (0, N, 2N, ...).
|
|
@@ -368,15 +396,13 @@ def plot_simtel_step_traces(
|
|
|
368
396
|
matplotlib.figure.Figure | None
|
|
369
397
|
The created figure, or ``None`` if R1 waveforms are unavailable.
|
|
370
398
|
"""
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if r1_tel_ids:
|
|
376
|
-
tel_id = tel_id or r1_tel_ids[0]
|
|
377
|
-
else:
|
|
378
|
-
_logger.warning("Event has no R1 data for traces plot")
|
|
399
|
+
prepared = _get_event_source_and_r1_tel(
|
|
400
|
+
filename, event_index=event_index, warn_context="traces plot"
|
|
401
|
+
)
|
|
402
|
+
if prepared is None:
|
|
379
403
|
return None
|
|
404
|
+
source, event, tel_id_default = prepared
|
|
405
|
+
tel_id = tel_id or tel_id_default
|
|
380
406
|
|
|
381
407
|
waveforms = getattr(event.r1.tel.get(tel_id, None), "waveform", None)
|
|
382
408
|
if waveforms is None:
|
|
@@ -583,13 +609,13 @@ def _draw_peak_hist(
|
|
|
583
609
|
|
|
584
610
|
def plot_simtel_peak_timing(
|
|
585
611
|
filename,
|
|
586
|
-
tel_id
|
|
587
|
-
sum_threshold
|
|
588
|
-
peak_width
|
|
589
|
-
examples
|
|
590
|
-
timing_bins
|
|
591
|
-
return_stats
|
|
592
|
-
event_index
|
|
612
|
+
tel_id=None,
|
|
613
|
+
sum_threshold=10.0,
|
|
614
|
+
peak_width=8,
|
|
615
|
+
examples=3,
|
|
616
|
+
timing_bins=None,
|
|
617
|
+
return_stats=False,
|
|
618
|
+
event_index=None,
|
|
593
619
|
):
|
|
594
620
|
"""
|
|
595
621
|
Peak finding per pixel; report mean/std of peak sample and plot a histogram.
|
|
@@ -620,15 +646,13 @@ def plot_simtel_peak_timing(
|
|
|
620
646
|
``return_stats`` is True, a tuple ``(fig, stats)`` is returned, where
|
|
621
647
|
``stats`` has keys ``{"considered", "found", "mean", "std"}``.
|
|
622
648
|
"""
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
if r1_tel_ids:
|
|
628
|
-
tel_id = tel_id or r1_tel_ids[0]
|
|
629
|
-
else:
|
|
630
|
-
_logger.warning("Event has no R1 data for peak timing plot")
|
|
649
|
+
prepared = _get_event_source_and_r1_tel(
|
|
650
|
+
filename, event_index=event_index, warn_context="peak timing plot"
|
|
651
|
+
)
|
|
652
|
+
if prepared is None:
|
|
631
653
|
return None
|
|
654
|
+
source, event, tel_id_default = prepared
|
|
655
|
+
tel_id = tel_id or tel_id_default
|
|
632
656
|
|
|
633
657
|
waveforms = getattr(event.r1.tel.get(tel_id, None), "waveform", None)
|
|
634
658
|
if waveforms is None:
|
|
@@ -718,15 +742,13 @@ def _prepare_waveforms_for_image(filename, tel_id, context_no_r1, event_index=No
|
|
|
718
742
|
``n_samp`` are integers, and ``source``, ``event`` and ``tel_id`` are
|
|
719
743
|
the ctapipe objects used. Returns ``None`` on failure.
|
|
720
744
|
"""
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
if r1_tel_ids:
|
|
726
|
-
tel_id = tel_id or r1_tel_ids[0]
|
|
727
|
-
else:
|
|
728
|
-
_logger.warning(f"Event has no R1 data for {context_no_r1}")
|
|
745
|
+
prepared = _get_event_source_and_r1_tel(
|
|
746
|
+
filename, event_index=event_index, warn_context=context_no_r1
|
|
747
|
+
)
|
|
748
|
+
if prepared is None:
|
|
729
749
|
return None
|
|
750
|
+
source, event, tel_id_default = prepared
|
|
751
|
+
tel_id = tel_id or tel_id_default
|
|
730
752
|
|
|
731
753
|
waveforms = getattr(event.r1.tel.get(tel_id, None), "waveform", None)
|
|
732
754
|
if waveforms is None:
|
|
@@ -742,9 +764,9 @@ def _prepare_waveforms_for_image(filename, tel_id, context_no_r1, event_index=No
|
|
|
742
764
|
|
|
743
765
|
def plot_simtel_integrated_signal_image(
|
|
744
766
|
filename,
|
|
745
|
-
tel_id
|
|
746
|
-
half_width
|
|
747
|
-
event_index
|
|
767
|
+
tel_id=None,
|
|
768
|
+
half_width=8,
|
|
769
|
+
event_index=None,
|
|
748
770
|
):
|
|
749
771
|
"""Plot camera image of integrated signal per pixel around the flasher peak."""
|
|
750
772
|
return _plot_simtel_integrated_image(
|
|
@@ -758,10 +780,10 @@ def plot_simtel_integrated_signal_image(
|
|
|
758
780
|
|
|
759
781
|
def plot_simtel_integrated_pedestal_image(
|
|
760
782
|
filename,
|
|
761
|
-
tel_id
|
|
762
|
-
half_width
|
|
763
|
-
offset
|
|
764
|
-
event_index
|
|
783
|
+
tel_id=None,
|
|
784
|
+
half_width=8,
|
|
785
|
+
offset=16,
|
|
786
|
+
event_index=None,
|
|
765
787
|
):
|
|
766
788
|
"""Plot camera image of integrated pedestal per pixel away from the flasher peak."""
|
|
767
789
|
return _plot_simtel_integrated_image(
|
|
@@ -776,11 +798,11 @@ def plot_simtel_integrated_pedestal_image(
|
|
|
776
798
|
|
|
777
799
|
def _plot_simtel_integrated_image(
|
|
778
800
|
filename,
|
|
779
|
-
tel_id
|
|
780
|
-
half_width
|
|
781
|
-
event_index
|
|
782
|
-
mode
|
|
783
|
-
offset
|
|
801
|
+
tel_id,
|
|
802
|
+
half_width,
|
|
803
|
+
event_index,
|
|
804
|
+
mode,
|
|
805
|
+
offset=None,
|
|
784
806
|
):
|
|
785
807
|
"""Shared implementation for integrated signal/pedestal images.
|
|
786
808
|
|
|
@@ -814,3 +836,178 @@ def _plot_simtel_integrated_image(
|
|
|
814
836
|
ax.set_axis_off()
|
|
815
837
|
fig.tight_layout()
|
|
816
838
|
return fig
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def _make_output_paths(ioh, base, input_file):
|
|
842
|
+
"""Return (out_dir, pdf_path) based on base name and input file."""
|
|
843
|
+
out_dir = ioh.get_output_directory(label=Path(__file__).stem)
|
|
844
|
+
pdf_path = ioh.get_output_file(f"{base}_{input_file.stem}" if base else input_file.stem)
|
|
845
|
+
pdf_path = Path(f"{pdf_path}.pdf") if Path(pdf_path).suffix != ".pdf" else Path(pdf_path)
|
|
846
|
+
return out_dir, pdf_path
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
def _call_peak_timing(
|
|
850
|
+
filename,
|
|
851
|
+
tel_id=None,
|
|
852
|
+
sum_threshold=10.0,
|
|
853
|
+
peak_width=8,
|
|
854
|
+
examples=3,
|
|
855
|
+
timing_bins=None,
|
|
856
|
+
event_index=None,
|
|
857
|
+
):
|
|
858
|
+
"""Call plot_simtel_peak_timing while tolerating older signature.
|
|
859
|
+
|
|
860
|
+
Returns a matplotlib Figure or None.
|
|
861
|
+
"""
|
|
862
|
+
try:
|
|
863
|
+
fig_stats = plot_simtel_peak_timing(
|
|
864
|
+
filename,
|
|
865
|
+
tel_id=tel_id,
|
|
866
|
+
sum_threshold=sum_threshold,
|
|
867
|
+
peak_width=peak_width,
|
|
868
|
+
examples=examples,
|
|
869
|
+
timing_bins=timing_bins,
|
|
870
|
+
return_stats=True,
|
|
871
|
+
event_index=event_index,
|
|
872
|
+
)
|
|
873
|
+
return fig_stats[0] if isinstance(fig_stats, tuple) else fig_stats
|
|
874
|
+
except TypeError:
|
|
875
|
+
return plot_simtel_peak_timing(
|
|
876
|
+
filename,
|
|
877
|
+
tel_id=tel_id,
|
|
878
|
+
sum_threshold=sum_threshold,
|
|
879
|
+
peak_width=peak_width,
|
|
880
|
+
examples=examples,
|
|
881
|
+
timing_bins=timing_bins,
|
|
882
|
+
event_index=event_index,
|
|
883
|
+
)
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def _collect_figures_for_file(
|
|
887
|
+
filename,
|
|
888
|
+
plots,
|
|
889
|
+
args,
|
|
890
|
+
out_dir,
|
|
891
|
+
base_stem,
|
|
892
|
+
save_pngs,
|
|
893
|
+
dpi,
|
|
894
|
+
):
|
|
895
|
+
"""Generate selected plots for a single sim_telarray file.
|
|
896
|
+
|
|
897
|
+
Returns a list of figures. If ``save_pngs`` is True, also writes PNGs to ``out_dir``.
|
|
898
|
+
"""
|
|
899
|
+
figures = []
|
|
900
|
+
|
|
901
|
+
def add(fig, tag):
|
|
902
|
+
if fig is not None:
|
|
903
|
+
figures.append(fig)
|
|
904
|
+
if save_pngs:
|
|
905
|
+
base_path = out_dir / f"{base_stem}_{tag}"
|
|
906
|
+
try:
|
|
907
|
+
save_figure(fig, base_path, figure_format=["png"], dpi=int(dpi))
|
|
908
|
+
except Exception as ex: # pylint:disable=broad-except
|
|
909
|
+
_logger.warning("Failed to save PNG %s: %s", base_path.with_suffix(".png"), ex)
|
|
910
|
+
else:
|
|
911
|
+
_logger.warning("Plot '%s' returned no figure for %s", tag, filename)
|
|
912
|
+
|
|
913
|
+
plots_to_run = (
|
|
914
|
+
[
|
|
915
|
+
"event_image",
|
|
916
|
+
"time_traces",
|
|
917
|
+
"waveform_matrix",
|
|
918
|
+
"step_traces",
|
|
919
|
+
"integrated_signal_image",
|
|
920
|
+
"integrated_pedestal_image",
|
|
921
|
+
"peak_timing",
|
|
922
|
+
]
|
|
923
|
+
if "all" in plots
|
|
924
|
+
else list(plots)
|
|
925
|
+
)
|
|
926
|
+
|
|
927
|
+
dispatch = {
|
|
928
|
+
"event_image": (
|
|
929
|
+
plot_simtel_event_image,
|
|
930
|
+
{"distance": None, "event_index": None},
|
|
931
|
+
),
|
|
932
|
+
"time_traces": (
|
|
933
|
+
plot_simtel_time_traces,
|
|
934
|
+
{"tel_id": None, "n_pixels": 3, "event_index": None},
|
|
935
|
+
),
|
|
936
|
+
"waveform_matrix": (
|
|
937
|
+
plot_simtel_waveform_matrix,
|
|
938
|
+
{"tel_id": None, "vmax": None, "event_index": None},
|
|
939
|
+
),
|
|
940
|
+
"step_traces": (
|
|
941
|
+
plot_simtel_step_traces,
|
|
942
|
+
{"tel_id": None, "pixel_step": None, "max_pixels": None, "event_index": None},
|
|
943
|
+
),
|
|
944
|
+
"integrated_signal_image": (
|
|
945
|
+
plot_simtel_integrated_signal_image,
|
|
946
|
+
{"tel_id": None, "half_width": 8, "event_index": None},
|
|
947
|
+
),
|
|
948
|
+
"integrated_pedestal_image": (
|
|
949
|
+
plot_simtel_integrated_pedestal_image,
|
|
950
|
+
{"tel_id": None, "half_width": 8, "offset": 16, "event_index": None},
|
|
951
|
+
),
|
|
952
|
+
"peak_timing": (
|
|
953
|
+
_call_peak_timing,
|
|
954
|
+
{
|
|
955
|
+
"tel_id": None,
|
|
956
|
+
"sum_threshold": 10.0,
|
|
957
|
+
"peak_width": 8,
|
|
958
|
+
"examples": 3,
|
|
959
|
+
"timing_bins": None,
|
|
960
|
+
"event_index": None,
|
|
961
|
+
},
|
|
962
|
+
),
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
for plot_name in plots_to_run:
|
|
966
|
+
entry = dispatch.get(plot_name)
|
|
967
|
+
if entry is None:
|
|
968
|
+
_logger.warning("Unknown plot selection '%s'", plot_name)
|
|
969
|
+
continue
|
|
970
|
+
func, defaults = entry
|
|
971
|
+
kwargs = {k: args.get(k, v) for k, v in defaults.items()}
|
|
972
|
+
fig = func(filename, **kwargs) # type: ignore[misc]
|
|
973
|
+
add(fig, plot_name)
|
|
974
|
+
|
|
975
|
+
return figures
|
|
976
|
+
|
|
977
|
+
|
|
978
|
+
def generate_and_save_plots(
|
|
979
|
+
simtel_files,
|
|
980
|
+
plots,
|
|
981
|
+
args,
|
|
982
|
+
ioh,
|
|
983
|
+
):
|
|
984
|
+
"""Generate plots for files and save a multi-page PDF per input.
|
|
985
|
+
|
|
986
|
+
Also writes metadata JSON next to the PDF.
|
|
987
|
+
"""
|
|
988
|
+
for simtel in simtel_files:
|
|
989
|
+
out_dir, pdf_path = _make_output_paths(ioh, args.get("output_file"), simtel)
|
|
990
|
+
figures = _collect_figures_for_file(
|
|
991
|
+
filename=simtel,
|
|
992
|
+
plots=plots,
|
|
993
|
+
args=args,
|
|
994
|
+
out_dir=out_dir,
|
|
995
|
+
base_stem=simtel.stem,
|
|
996
|
+
save_pngs=bool(args.get("save_pngs", False)),
|
|
997
|
+
dpi=int(args.get("dpi", 300)),
|
|
998
|
+
)
|
|
999
|
+
|
|
1000
|
+
if not figures:
|
|
1001
|
+
_logger.warning("No figures produced for %s", simtel)
|
|
1002
|
+
continue
|
|
1003
|
+
|
|
1004
|
+
try:
|
|
1005
|
+
save_figs_to_pdf(figures, pdf_path)
|
|
1006
|
+
_logger.info("Saved PDF: %s", pdf_path)
|
|
1007
|
+
except Exception as ex: # pylint:disable=broad-except
|
|
1008
|
+
_logger.error("Failed to save PDF %s: %s", pdf_path, ex)
|
|
1009
|
+
|
|
1010
|
+
try:
|
|
1011
|
+
MetadataCollector.dump(args, pdf_path, add_activity_name=True)
|
|
1012
|
+
except Exception as ex: # pylint:disable=broad-except
|
|
1013
|
+
_logger.warning("Failed to write metadata for %s: %s", pdf_path, ex)
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
r"""
|
|
2
|
-
Generate new simulation model production tables by copying existing table and apply modifications.
|
|
3
|
-
|
|
4
|
-
This script should be used to maintain the simulation model repository. It allow to create a
|
|
5
|
-
new production table by copying an existing base version and apply modification defined in a YAML
|
|
6
|
-
file (see the example file listed below).
|
|
7
|
-
|
|
8
|
-
Example
|
|
9
|
-
-------
|
|
10
|
-
.. code-block:: console
|
|
11
|
-
|
|
12
|
-
simtools-maintain-simulation-model-add-production-table \\
|
|
13
|
-
--simulation_models_path ../simulation-models-dev/simulation-models/ \\
|
|
14
|
-
--source_prod_table_dir 6.0.0 \\
|
|
15
|
-
--modifications tests/resources/production_tables_changes_for_threshold_study_6.2.0.yml
|
|
16
|
-
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
import logging
|
|
20
|
-
from pathlib import Path
|
|
21
|
-
|
|
22
|
-
import simtools.utils.general as gen
|
|
23
|
-
from simtools.configuration import configurator
|
|
24
|
-
from simtools.model import model_repository
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def _parse(label, description):
|
|
28
|
-
"""
|
|
29
|
-
Parse command line arguments.
|
|
30
|
-
|
|
31
|
-
Returns
|
|
32
|
-
-------
|
|
33
|
-
dict
|
|
34
|
-
Parsed command-line arguments.
|
|
35
|
-
"""
|
|
36
|
-
config = configurator.Configurator(label=label, description=description)
|
|
37
|
-
config.parser.add_argument(
|
|
38
|
-
"--simulation_models_path",
|
|
39
|
-
type=str,
|
|
40
|
-
required=True,
|
|
41
|
-
help="Path to the simulation models repository.",
|
|
42
|
-
)
|
|
43
|
-
config.parser.add_argument(
|
|
44
|
-
"--source_prod_table_dir",
|
|
45
|
-
type=str,
|
|
46
|
-
required=True,
|
|
47
|
-
help="The source production table directory to copy from.",
|
|
48
|
-
)
|
|
49
|
-
config.parser.add_argument(
|
|
50
|
-
"--modifications",
|
|
51
|
-
type=str,
|
|
52
|
-
required=True,
|
|
53
|
-
help="File containing the list of changes to apply.",
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
return config.initialize(db_config=False, output=False)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def main(): # noqa: D103
|
|
60
|
-
label = Path(__file__).stem
|
|
61
|
-
args_dict, _ = _parse(
|
|
62
|
-
label=label, description=("Copy and update simulation model production tables.")
|
|
63
|
-
)
|
|
64
|
-
logger = logging.getLogger()
|
|
65
|
-
logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
|
|
66
|
-
|
|
67
|
-
model_repository.copy_and_update_production_table(args_dict)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if __name__ == "__main__":
|
|
71
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|