gammasimtools 0.19.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.19.0.dist-info → gammasimtools-0.21.0.dist-info}/METADATA +1 -3
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/RECORD +54 -51
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/entry_points.txt +3 -3
- simtools/_version.py +2 -2
- simtools/applications/calculate_incident_angles.py +182 -0
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +17 -14
- simtools/applications/db_add_value_from_json_to_db.py +6 -9
- simtools/applications/db_generate_compound_indexes.py +7 -3
- simtools/applications/db_get_file_from_db.py +11 -23
- simtools/applications/derive_psf_parameters.py +58 -39
- simtools/applications/derive_trigger_rates.py +91 -0
- simtools/applications/generate_corsika_histograms.py +7 -184
- simtools/applications/maintain_simulation_model_add_production.py +105 -0
- simtools/applications/plot_simtel_events.py +5 -189
- simtools/applications/print_version.py +8 -7
- simtools/applications/validate_file_using_schema.py +7 -4
- simtools/configuration/commandline_parser.py +17 -11
- simtools/corsika/corsika_histograms.py +81 -0
- simtools/data_model/validate_data.py +8 -3
- simtools/db/db_handler.py +122 -31
- simtools/db/db_model_upload.py +51 -30
- simtools/dependencies.py +10 -5
- simtools/layout/array_layout_utils.py +37 -5
- simtools/model/array_model.py +18 -1
- simtools/model/model_repository.py +118 -63
- simtools/model/site_model.py +25 -0
- simtools/production_configuration/derive_corsika_limits.py +9 -34
- simtools/ray_tracing/incident_angles.py +706 -0
- simtools/ray_tracing/psf_parameter_optimisation.py +999 -565
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +2 -2
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_spectrum.schema.yml +22 -29
- simtools/schemas/model_parameters/stars.schema.yml +1 -1
- simtools/schemas/production_tables.schema.yml +5 -0
- simtools/simtel/simtel_config_writer.py +18 -20
- simtools/simtel/simtel_io_event_histograms.py +253 -516
- simtools/simtel/simtel_io_event_reader.py +51 -2
- simtools/simtel/simtel_io_event_writer.py +31 -11
- simtools/simtel/simtel_io_metadata.py +1 -1
- simtools/simtel/simtel_table_reader.py +3 -3
- simtools/simulator.py +1 -4
- simtools/telescope_trigger_rates.py +119 -0
- simtools/testing/log_inspector.py +13 -11
- simtools/utils/geometry.py +20 -0
- simtools/version.py +89 -0
- simtools/{corsika/corsika_histograms_visualize.py → visualization/plot_corsika_histograms.py} +109 -0
- simtools/visualization/plot_incident_angles.py +431 -0
- simtools/visualization/plot_psf.py +673 -0
- simtools/visualization/plot_simtel_event_histograms.py +376 -0
- simtools/visualization/{simtel_event_plots.py → plot_simtel_events.py} +284 -87
- simtools/visualization/visualize.py +1 -3
- simtools/applications/calculate_trigger_rate.py +0 -187
- simtools/applications/generate_sim_telarray_histograms.py +0 -196
- simtools/applications/maintain_simulation_model_add_production_table.py +0 -71
- simtools/simtel/simtel_io_histogram.py +0 -623
- simtools/simtel/simtel_io_histograms.py +0 -556
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.21.0.dist-info}/top_level.txt +0 -0
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
r"""
|
|
4
4
|
Plot simulated events.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
Produces figures from one or more sim_telarray (.simtel.zst) files
|
|
7
|
+
It is meant to run after simulations (e.g., simtools-simulate-flasher,
|
|
8
|
+
simtools-simulate-illuminator).
|
|
9
9
|
|
|
10
10
|
What it does
|
|
11
11
|
------------
|
|
@@ -81,29 +81,8 @@ from pathlib import Path
|
|
|
81
81
|
|
|
82
82
|
import simtools.utils.general as gen
|
|
83
83
|
from simtools.configuration import configurator
|
|
84
|
-
from simtools.corsika.corsika_histograms_visualize import save_figs_to_pdf
|
|
85
|
-
from simtools.data_model.metadata_collector import MetadataCollector
|
|
86
84
|
from simtools.io import io_handler
|
|
87
|
-
from simtools.visualization.
|
|
88
|
-
plot_simtel_event_image,
|
|
89
|
-
plot_simtel_integrated_pedestal_image,
|
|
90
|
-
plot_simtel_integrated_signal_image,
|
|
91
|
-
plot_simtel_peak_timing,
|
|
92
|
-
plot_simtel_step_traces,
|
|
93
|
-
plot_simtel_time_traces,
|
|
94
|
-
plot_simtel_waveform_matrix,
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
PLOT_CHOICES = {
|
|
98
|
-
"event_image": "event_image",
|
|
99
|
-
"time_traces": "time_traces",
|
|
100
|
-
"waveform_matrix": "waveform_matrix",
|
|
101
|
-
"step_traces": "step_traces",
|
|
102
|
-
"integrated_signal_image": "integrated_signal_image",
|
|
103
|
-
"integrated_pedestal_image": "integrated_pedestal_image",
|
|
104
|
-
"peak_timing": "peak_timing",
|
|
105
|
-
"all": "all",
|
|
106
|
-
}
|
|
85
|
+
from simtools.visualization.plot_simtel_events import PLOT_CHOICES, generate_and_save_plots
|
|
107
86
|
|
|
108
87
|
|
|
109
88
|
def _parse(label: str):
|
|
@@ -128,7 +107,6 @@ def _parse(label: str):
|
|
|
128
107
|
default=["event_image"],
|
|
129
108
|
choices=sorted(PLOT_CHOICES),
|
|
130
109
|
)
|
|
131
|
-
# common plotting options
|
|
132
110
|
config.parser.add_argument("--tel_id", type=int, default=None, help="Telescope ID")
|
|
133
111
|
config.parser.add_argument(
|
|
134
112
|
"--n_pixels", type=int, default=3, help="For time_traces: number of pixel traces"
|
|
@@ -179,7 +157,6 @@ def _parse(label: str):
|
|
|
179
157
|
default=None,
|
|
180
158
|
help="0-based index of the event to plot; default is the first event",
|
|
181
159
|
)
|
|
182
|
-
# outputs
|
|
183
160
|
config.parser.add_argument(
|
|
184
161
|
"--output_file",
|
|
185
162
|
type=str,
|
|
@@ -199,139 +176,6 @@ def _parse(label: str):
|
|
|
199
176
|
return config.initialize(db_config=False, require_command_line=True)
|
|
200
177
|
|
|
201
178
|
|
|
202
|
-
def _save_png(fig, out_dir: Path, stem: str, suffix: str, dpi: int):
|
|
203
|
-
"""Save ``fig`` as a PNG into ``out_dir`` using ``stem`` and ``suffix``.
|
|
204
|
-
|
|
205
|
-
Errors during saving are logged as warnings and otherwise ignored.
|
|
206
|
-
"""
|
|
207
|
-
png_path = out_dir.joinpath(f"{stem}_{suffix}.png")
|
|
208
|
-
try:
|
|
209
|
-
fig.savefig(png_path, dpi=dpi, bbox_inches="tight")
|
|
210
|
-
except Exception as ex: # pylint:disable=broad-except
|
|
211
|
-
logging.getLogger(__name__).warning("Failed to save PNG %s: %s", png_path, ex)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def _make_output_paths(
|
|
215
|
-
ioh: io_handler.IOHandler, base: str | None, input_file: Path
|
|
216
|
-
) -> tuple[Path, Path]:
|
|
217
|
-
"""Return (out_dir, pdf_path) based on base and input_file."""
|
|
218
|
-
out_dir = ioh.get_output_directory(label=Path(__file__).stem)
|
|
219
|
-
if base:
|
|
220
|
-
pdf_path = ioh.get_output_file(f"{base}_{input_file.stem}")
|
|
221
|
-
else:
|
|
222
|
-
pdf_path = ioh.get_output_file(input_file.stem)
|
|
223
|
-
pdf_path = Path(f"{pdf_path}.pdf") if pdf_path.suffix != ".pdf" else Path(pdf_path)
|
|
224
|
-
return out_dir, pdf_path
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
def _collect_figures_for_file(
|
|
228
|
-
filename: Path,
|
|
229
|
-
plots: list[str],
|
|
230
|
-
args: dict,
|
|
231
|
-
out_dir: Path,
|
|
232
|
-
base_stem: str,
|
|
233
|
-
save_pngs: bool,
|
|
234
|
-
dpi: int,
|
|
235
|
-
):
|
|
236
|
-
"""Generate the selected plots for a single sim_telarray file.
|
|
237
|
-
|
|
238
|
-
Returns a list of figures. If ``save_pngs`` is True, also writes PNGs to
|
|
239
|
-
``out_dir`` using ``base_stem`` for filenames.
|
|
240
|
-
"""
|
|
241
|
-
logger = logging.getLogger(__name__)
|
|
242
|
-
figures: list[object] = []
|
|
243
|
-
|
|
244
|
-
def add(fig, tag: str):
|
|
245
|
-
if fig is not None:
|
|
246
|
-
figures.append(fig)
|
|
247
|
-
if save_pngs:
|
|
248
|
-
_save_png(fig, out_dir, base_stem, tag, dpi)
|
|
249
|
-
else:
|
|
250
|
-
logger.warning("Plot '%s' returned no figure for %s", tag, filename)
|
|
251
|
-
|
|
252
|
-
plots_to_run = (
|
|
253
|
-
[
|
|
254
|
-
"event_image",
|
|
255
|
-
"time_traces",
|
|
256
|
-
"waveform_matrix",
|
|
257
|
-
"step_traces",
|
|
258
|
-
"integrated_signal_image",
|
|
259
|
-
"integrated_pedestal_image",
|
|
260
|
-
"peak_timing",
|
|
261
|
-
]
|
|
262
|
-
if "all" in plots
|
|
263
|
-
else list(plots)
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
def _call_peak_timing():
|
|
267
|
-
try:
|
|
268
|
-
fig_stats = plot_simtel_peak_timing(
|
|
269
|
-
filename,
|
|
270
|
-
tel_id=args.get("tel_id"),
|
|
271
|
-
sum_threshold=args.get("sum_threshold", 10.0),
|
|
272
|
-
peak_width=args.get("peak_width", 8),
|
|
273
|
-
examples=args.get("examples", 3),
|
|
274
|
-
timing_bins=args.get("timing_bins"),
|
|
275
|
-
return_stats=True,
|
|
276
|
-
event_index=args.get("event_index"),
|
|
277
|
-
)
|
|
278
|
-
return fig_stats[0] if isinstance(fig_stats, tuple) else fig_stats
|
|
279
|
-
except TypeError:
|
|
280
|
-
return plot_simtel_peak_timing(
|
|
281
|
-
filename,
|
|
282
|
-
tel_id=args.get("tel_id"),
|
|
283
|
-
sum_threshold=args.get("sum_threshold", 10.0),
|
|
284
|
-
peak_width=args.get("peak_width", 8),
|
|
285
|
-
examples=args.get("examples", 3),
|
|
286
|
-
timing_bins=args.get("timing_bins"),
|
|
287
|
-
event_index=args.get("event_index"),
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
# function name -> (callable, defaults)
|
|
291
|
-
dispatch: dict[str, tuple[object, dict[str, object]]] = {
|
|
292
|
-
"event_image": (
|
|
293
|
-
plot_simtel_event_image,
|
|
294
|
-
{"distance": None, "event_index": None},
|
|
295
|
-
),
|
|
296
|
-
"time_traces": (
|
|
297
|
-
plot_simtel_time_traces,
|
|
298
|
-
{"tel_id": None, "n_pixels": 3, "event_index": None},
|
|
299
|
-
),
|
|
300
|
-
"waveform_matrix": (
|
|
301
|
-
plot_simtel_waveform_matrix,
|
|
302
|
-
{"tel_id": None, "vmax": None, "event_index": None},
|
|
303
|
-
),
|
|
304
|
-
"step_traces": (
|
|
305
|
-
plot_simtel_step_traces,
|
|
306
|
-
{"tel_id": None, "pixel_step": None, "max_pixels": None, "event_index": None},
|
|
307
|
-
),
|
|
308
|
-
"integrated_signal_image": (
|
|
309
|
-
plot_simtel_integrated_signal_image,
|
|
310
|
-
{"tel_id": None, "half_width": 8, "event_index": None},
|
|
311
|
-
),
|
|
312
|
-
"integrated_pedestal_image": (
|
|
313
|
-
plot_simtel_integrated_pedestal_image,
|
|
314
|
-
{"tel_id": None, "half_width": 8, "offset": 16, "event_index": None},
|
|
315
|
-
),
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
for plot_name in plots_to_run:
|
|
319
|
-
if plot_name == "peak_timing":
|
|
320
|
-
add(_call_peak_timing(), "peak_timing")
|
|
321
|
-
continue
|
|
322
|
-
entry = dispatch.get(plot_name)
|
|
323
|
-
if entry is None:
|
|
324
|
-
logger.warning("Unknown plot selection '%s'", plot_name)
|
|
325
|
-
continue
|
|
326
|
-
func, defaults = entry
|
|
327
|
-
# Build kwargs with user args overriding defaults
|
|
328
|
-
kwargs = {k: args.get(k, v) for k, v in defaults.items()}
|
|
329
|
-
fig = func(filename, **kwargs) # type: ignore[misc]
|
|
330
|
-
add(fig, plot_name)
|
|
331
|
-
|
|
332
|
-
return figures
|
|
333
|
-
|
|
334
|
-
|
|
335
179
|
def main():
|
|
336
180
|
"""Generate plots from sim_telarray files."""
|
|
337
181
|
label = Path(__file__).stem
|
|
@@ -341,38 +185,10 @@ def main():
|
|
|
341
185
|
logger.setLevel(gen.get_log_level_from_user(args.get("log_level", "INFO")))
|
|
342
186
|
|
|
343
187
|
ioh = io_handler.IOHandler()
|
|
344
|
-
|
|
345
188
|
simtel_files = [Path(p).expanduser() for p in gen.ensure_iterable(args["simtel_files"])]
|
|
346
189
|
plots = list(gen.ensure_iterable(args.get("plots")))
|
|
347
190
|
|
|
348
|
-
|
|
349
|
-
out_dir, pdf_path = _make_output_paths(ioh, args.get("output_file"), simtel)
|
|
350
|
-
figures = _collect_figures_for_file(
|
|
351
|
-
filename=simtel,
|
|
352
|
-
plots=plots,
|
|
353
|
-
args=args,
|
|
354
|
-
out_dir=out_dir,
|
|
355
|
-
base_stem=simtel.stem,
|
|
356
|
-
save_pngs=bool(args.get("save_pngs", False)),
|
|
357
|
-
dpi=int(args.get("dpi", 300)),
|
|
358
|
-
)
|
|
359
|
-
|
|
360
|
-
if not figures:
|
|
361
|
-
logger.warning("No figures produced for %s", simtel)
|
|
362
|
-
continue
|
|
363
|
-
|
|
364
|
-
# Save a multipage PDF
|
|
365
|
-
try:
|
|
366
|
-
save_figs_to_pdf(figures, pdf_path)
|
|
367
|
-
logger.info("Saved PDF: %s", pdf_path)
|
|
368
|
-
except Exception as ex: # pylint:disable=broad-except
|
|
369
|
-
logger.error("Failed to save PDF %s: %s", pdf_path, ex)
|
|
370
|
-
|
|
371
|
-
# Dump run metadata alongside PDF
|
|
372
|
-
try:
|
|
373
|
-
MetadataCollector.dump(args, pdf_path, add_activity_name=True)
|
|
374
|
-
except Exception as ex: # pylint:disable=broad-except
|
|
375
|
-
logger.warning("Failed to write metadata for %s: %s", pdf_path, ex)
|
|
191
|
+
generate_and_save_plots(simtel_files=simtel_files, plots=plots, args=args, ioh=ioh)
|
|
376
192
|
|
|
377
193
|
|
|
378
194
|
if __name__ == "__main__":
|
|
@@ -39,7 +39,7 @@ def _parse(label, description, usage):
|
|
|
39
39
|
"""
|
|
40
40
|
config = configurator.Configurator(label=label, description=description, usage=usage)
|
|
41
41
|
|
|
42
|
-
return config.initialize(db_config=True, output=True)
|
|
42
|
+
return config.initialize(db_config=True, output=True, require_command_line=False)
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
def main():
|
|
@@ -68,12 +68,13 @@ def main():
|
|
|
68
68
|
key, value = version_entry.split(": ", 1)
|
|
69
69
|
version_dict[key] = value
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
if not args_dict.get("output_file_from_default", False):
|
|
72
|
+
ascii_handler.write_data_to_file(
|
|
73
|
+
data=version_dict,
|
|
74
|
+
output_file=io_handler_instance.get_output_file(
|
|
75
|
+
args_dict.get("output_file", "simtools_version.json"), label=label
|
|
76
|
+
),
|
|
77
|
+
)
|
|
77
78
|
|
|
78
79
|
|
|
79
80
|
if __name__ == "__main__":
|
|
@@ -145,10 +145,13 @@ def validate_dict_using_schema(args_dict, logger):
|
|
|
145
145
|
except FileNotFoundError as exc:
|
|
146
146
|
raise FileNotFoundError(f"Error reading schema file from {file_name}") from exc
|
|
147
147
|
data = data if isinstance(data, list) else [data]
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
try:
|
|
149
|
+
for data_dict in data:
|
|
150
|
+
schema.validate_dict_using_schema(
|
|
151
|
+
data_dict, _get_schema_file_name(args_dict, data_dict)
|
|
152
|
+
)
|
|
153
|
+
except Exception as exc:
|
|
154
|
+
raise ValueError(f"Validation of file {file_name} failed") from exc
|
|
152
155
|
logger.info(f"Successful validation of file {file_name}")
|
|
153
156
|
|
|
154
157
|
|
|
@@ -222,6 +222,13 @@ class CommandLineParser(argparse.ArgumentParser):
|
|
|
222
222
|
required=False,
|
|
223
223
|
default=None,
|
|
224
224
|
)
|
|
225
|
+
_job_group.add_argument(
|
|
226
|
+
"--db_simulation_model_version",
|
|
227
|
+
help="version of simulation model database",
|
|
228
|
+
type=str.strip,
|
|
229
|
+
required=False,
|
|
230
|
+
default=None,
|
|
231
|
+
)
|
|
225
232
|
|
|
226
233
|
def initialize_simulation_model_arguments(self, model_options):
|
|
227
234
|
"""
|
|
@@ -740,28 +747,27 @@ class CommandLineParser(argparse.ArgumentParser):
|
|
|
740
747
|
@staticmethod
|
|
741
748
|
def parse_quantity_pair(string):
|
|
742
749
|
"""
|
|
743
|
-
Parse a string representing a pair of astropy quantities
|
|
744
|
-
|
|
745
|
-
Args:
|
|
746
|
-
string: The input string (e.g., "0 deg 1.5 deg").
|
|
750
|
+
Parse a string representing a pair of astropy quantities.
|
|
747
751
|
|
|
748
752
|
Returns
|
|
749
753
|
-------
|
|
750
|
-
|
|
754
|
+
tuple
|
|
755
|
+
A tuple of two astropy.units.Quantity objects.
|
|
751
756
|
|
|
752
757
|
Raises
|
|
753
758
|
------
|
|
754
|
-
|
|
759
|
+
ValueError
|
|
760
|
+
If the string cannot be parsed into exactly two quantities.
|
|
755
761
|
"""
|
|
756
|
-
pattern = r"(\d
|
|
762
|
+
pattern = r"(?>[\d\.eE+-]+)\s*(?>[A-Za-z]+)"
|
|
757
763
|
matches = re.findall(pattern, string)
|
|
758
764
|
if len(matches) != 2:
|
|
759
765
|
raise ValueError("Input string does not contain exactly two quantities.")
|
|
760
766
|
|
|
761
|
-
|
|
762
|
-
u.Quantity(
|
|
763
|
-
|
|
764
|
-
|
|
767
|
+
try:
|
|
768
|
+
return tuple(u.Quantity(m) for m in matches)
|
|
769
|
+
except Exception as exc:
|
|
770
|
+
raise ValueError(f"Could not parse quantities: {exc}") from exc
|
|
765
771
|
|
|
766
772
|
@staticmethod
|
|
767
773
|
def parse_integer_and_quantity(input_string):
|
|
@@ -22,6 +22,7 @@ from simtools.io.ascii_handler import collect_data_from_file
|
|
|
22
22
|
from simtools.io.hdf5_handler import fill_hdf5_table
|
|
23
23
|
from simtools.utils.geometry import convert_2d_to_radial_distr, rotate
|
|
24
24
|
from simtools.utils.names import sanitize_name
|
|
25
|
+
from simtools.visualization import plot_corsika_histograms as visualize
|
|
25
26
|
|
|
26
27
|
X_AXIS_STRING = "x axis"
|
|
27
28
|
Y_AXIS_STRING = "y axis"
|
|
@@ -111,6 +112,86 @@ class CorsikaHistograms:
|
|
|
111
112
|
self.read_event_information()
|
|
112
113
|
self._initialize_header()
|
|
113
114
|
|
|
115
|
+
def parse_telescope_indices(self, indices_arg):
|
|
116
|
+
"""Return telescope indices as ndarray[int] or None.
|
|
117
|
+
|
|
118
|
+
Accepts None, a sequence of strings/ints. Raises ValueError on invalid input.
|
|
119
|
+
"""
|
|
120
|
+
if indices_arg is None:
|
|
121
|
+
return None
|
|
122
|
+
try:
|
|
123
|
+
return np.array(indices_arg).astype(int)
|
|
124
|
+
except ValueError as exc:
|
|
125
|
+
msg = (
|
|
126
|
+
f"{indices_arg} not a valid input. Please use integer numbers for telescope_indices"
|
|
127
|
+
)
|
|
128
|
+
self._logger.error(msg)
|
|
129
|
+
raise ValueError(msg) from exc
|
|
130
|
+
|
|
131
|
+
def should_overwrite(
|
|
132
|
+
self, write_hdf5: bool, event1d: list | None, event2d: list | None
|
|
133
|
+
) -> bool:
|
|
134
|
+
"""Return True if output HDF5 exists and any writing flag is requested."""
|
|
135
|
+
exists = Path(self.hdf5_file_name).exists()
|
|
136
|
+
if exists and (write_hdf5 or bool(event1d) or bool(event2d)):
|
|
137
|
+
self._logger.warning(
|
|
138
|
+
f"Output hdf5 file {self.hdf5_file_name} already exists. Overwriting it."
|
|
139
|
+
)
|
|
140
|
+
return True
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
def run_export_pipeline(
|
|
144
|
+
self,
|
|
145
|
+
*,
|
|
146
|
+
individual_telescopes: bool,
|
|
147
|
+
hist_config,
|
|
148
|
+
indices_arg,
|
|
149
|
+
write_pdf: bool,
|
|
150
|
+
write_hdf5: bool,
|
|
151
|
+
event1d: list | None,
|
|
152
|
+
event2d: list | None,
|
|
153
|
+
test: bool = False,
|
|
154
|
+
) -> dict:
|
|
155
|
+
"""Run the full histogram export pipeline and return output artifact paths.
|
|
156
|
+
|
|
157
|
+
Returns a dict with optional keys: pdf_photons, pdf_event1d, pdf_event2d.
|
|
158
|
+
"""
|
|
159
|
+
outputs: dict[str, Path | None] = {
|
|
160
|
+
"pdf_photons": None,
|
|
161
|
+
"pdf_event_1d": None,
|
|
162
|
+
"pdf_event_2d": None,
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
indices = self.parse_telescope_indices(indices_arg)
|
|
166
|
+
overwrite = self.should_overwrite(write_hdf5, event1d, event2d)
|
|
167
|
+
|
|
168
|
+
self.set_histograms(
|
|
169
|
+
telescope_indices=indices,
|
|
170
|
+
individual_telescopes=individual_telescopes,
|
|
171
|
+
hist_config=hist_config,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if write_pdf:
|
|
175
|
+
pdf_path = visualize.export_all_photon_figures_pdf(self, test=test)
|
|
176
|
+
outputs["pdf_photons"] = pdf_path
|
|
177
|
+
if write_hdf5:
|
|
178
|
+
self.export_histograms(overwrite=overwrite)
|
|
179
|
+
|
|
180
|
+
if event1d is not None:
|
|
181
|
+
outputs["pdf_event_1d"] = visualize.derive_event_1d_histograms(
|
|
182
|
+
self, event1d, pdf=write_pdf, hdf5=write_hdf5, overwrite=not write_hdf5
|
|
183
|
+
)
|
|
184
|
+
if event2d is not None:
|
|
185
|
+
outputs["pdf_event_2d"] = visualize.derive_event_2d_histograms(
|
|
186
|
+
self,
|
|
187
|
+
event2d,
|
|
188
|
+
pdf=write_pdf,
|
|
189
|
+
hdf5=write_hdf5,
|
|
190
|
+
overwrite=not (write_hdf5 or bool(event1d)),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return outputs
|
|
194
|
+
|
|
114
195
|
@property
|
|
115
196
|
def hdf5_file_name(self):
|
|
116
197
|
"""
|
|
@@ -187,9 +187,14 @@ class DataValidator:
|
|
|
187
187
|
value_as_list, unit_as_list = self._get_value_and_units_as_lists()
|
|
188
188
|
|
|
189
189
|
for index, (value, unit) in enumerate(zip(value_as_list, unit_as_list)):
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
try:
|
|
191
|
+
value_as_list[index], unit_as_list[index] = self._validate_value_and_unit(
|
|
192
|
+
value, unit, index
|
|
193
|
+
)
|
|
194
|
+
except TypeError as ex:
|
|
195
|
+
raise TypeError(
|
|
196
|
+
f"Error validating dictionary using {self.schema_file_name}"
|
|
197
|
+
) from ex
|
|
193
198
|
|
|
194
199
|
if len(value_as_list) == 1:
|
|
195
200
|
self.data_dict["value"], self.data_dict["unit"] = value_as_list[0], unit_as_list[0]
|