Skip to content

Commit 5929433

Browse files
authored
Merge pull request #2735 from cta-observatory/simtel_true_image
Improve handling of missing true images
2 parents 074173d + d18de27 commit 5929433

File tree

3 files changed

+87
-4
lines changed

3 files changed

+87
-4
lines changed

docs/changes/2735.bugfix.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Improve heuristic in ``SimTelEventSource`` when true Cherenkov
2+
images are expected to be present in the input file to fix missing
3+
true images in output files when the first event of a run
4+
had missing true images.

src/ctapipe/io/simteleventsource.py

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,57 @@ def _clip_altitude_if_close(altitude):
121121
return altitude
122122

123123

124+
def _split_history(history):
125+
tel_history = {0: []}
126+
tel = 0
127+
128+
for timestamp, line in history:
129+
line = line.decode("utf-8").strip()
130+
131+
if line.startswith("# Telescope-specific configuration follows"):
132+
tel += 1
133+
tel_history[tel] = []
134+
135+
tel_history[tel].append((timestamp, line))
136+
137+
global_history = tel_history.pop(0)
138+
return global_history, tel_history
139+
140+
141+
def _has_true_image(history):
142+
global_history, tel_history = _split_history(history)
143+
144+
# merge_simtel does not include photoelectrons, so always missing
145+
if "merge_simtel" in global_history[0][1]:
146+
return False
147+
148+
# first, check for global default
149+
save_photons = 0
150+
global_store_pe = -1
151+
for _, line in global_history:
152+
if line.lower().startswith("save_photons"):
153+
save_photons = int(line.split()[1])
154+
155+
if line.lower().startswith("store_photoelectrons"):
156+
global_store_pe = int(line.split()[1])
157+
158+
if (save_photons & 0b10) > 0:
159+
return True
160+
161+
if global_store_pe > 0:
162+
return True
163+
164+
# if global default is not set, we still might have true images
165+
# via the telescope configuration
166+
store_photoelectrons = {}
167+
for tel, config in tel_history.items():
168+
for _, line in config:
169+
if "store_photoelectrons" in line.lower():
170+
store_photoelectrons[tel] = int(line.split()[1])
171+
172+
return any(v > 0 for v in store_photoelectrons.values())
173+
174+
124175
@enum.unique
125176
class MirrorClass(enum.Enum):
126177
"""Enum for the sim_telarray MIRROR_CLASS values"""
@@ -575,7 +626,13 @@ def __init__(self, input_url=Undefined, config=None, parent=None, **kwargs):
575626
self.file_, kind=self.atmosphere_profile_choice
576627
)
577628

578-
self._has_true_image = None
629+
try:
630+
self._has_true_image = _has_true_image(self.file_.history)
631+
except Exception:
632+
self.log.exception(
633+
"Error trying to determine whether file has true_image, assuming yes"
634+
)
635+
self._has_true_image = True
579636
self.log.debug(f"Using gain selector {self.gain_selector}")
580637

581638
def __exit__(self, exc_type, exc_val, exc_tb):
@@ -895,9 +952,6 @@ def _generate_events(self):
895952
self.telescope_indices_original[tel_id]
896953
]
897954

898-
if self._has_true_image is None:
899-
self._has_true_image = true_image is not None
900-
901955
if self._has_true_image and true_image is None:
902956
if true_image_sum > MISSING_IMAGE_BRIGHTNESS_LIMIT:
903957
self.log.warning(

src/ctapipe/io/tests/test_simteleventsource.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,3 +688,28 @@ def test_prod6_issues():
688688

689689
assert strange_trigger_events.keys() == events_checked_trigger
690690
assert missing_true_images.keys() == events_checked_image
691+
692+
693+
@pytest.mark.parametrize(
694+
("path", "expected", "kwargs"),
695+
[
696+
("dataset://gamma_prod5.simtel.zst", True, {}),
697+
("dataset://test_pe_first_missing.simtel.zst", True, {}),
698+
(gamma_test_large_path, False, {"focal_length_choice": "EQUIVALENT"}),
699+
],
700+
)
701+
def test_has_true_image(path, expected, kwargs):
702+
with SimTelEventSource(path, **kwargs) as source:
703+
assert source._has_true_image == expected
704+
705+
706+
def test_has_true_image_first_missing():
707+
"""Check that we have true images even if the first event is missing it"""
708+
input_url = "dataset://test_pe_first_missing.simtel.zst"
709+
710+
with SimTelEventSource(input_url) as source:
711+
n_found = 0
712+
for event in source:
713+
assert event.simulation.tel[1].true_image is not None
714+
n_found += 1
715+
assert n_found == 2

0 commit comments

Comments
 (0)