From 6a5cb6900338f15620aa8ad54b933f9716285f88 Mon Sep 17 00:00:00 2001
From: Tamas Gal <himself@tamasgal.com>
Date: Fri, 14 Jun 2024 14:32:39 +0200
Subject: [PATCH] Add getevent

---
 docs/src/api.md                  |  1 +
 docs/src/examples/online_data.md |  2 +-
 src/exports.jl                   |  1 +
 src/root/offline.jl              |  4 +++-
 src/root/online.jl               |  4 +++-
 src/tools/helpers.jl             | 40 ++++++++++++++++++++++++++++++++
 6 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/docs/src/api.md b/docs/src/api.md
index 71e90560..48b31501 100644
--- a/docs/src/api.md
+++ b/docs/src/api.md
@@ -126,6 +126,7 @@ CHClient
 
 ### General tools
 ```@docs
+getevent
 categorize
 nthbitset
 most_frequent
diff --git a/docs/src/examples/online_data.md b/docs/src/examples/online_data.md
index 34b07e46..ce1f62c7 100644
--- a/docs/src/examples/online_data.md
+++ b/docs/src/examples/online_data.md
@@ -57,7 +57,7 @@ event = getevent(f.online, 2)
 when two numbers are passed, the first one is interpreted as `frame_index` and the second one as `trigger_counter`:
 
 ```@example 1
-event = getevent(f.offline, 127, 2)
+event = getevent(f.online, 127, 1)
 ```
 
 !!! note
diff --git a/src/exports.jl b/src/exports.jl
index a4b7b646..0446c61c 100644
--- a/src/exports.jl
+++ b/src/exports.jl
@@ -117,6 +117,7 @@ isnb,
 most_frequent,
 nthbitset,
 triggered,
+getevent,
 
 # Physics and math helpers
 CherenkovPhoton,
diff --git a/src/root/offline.jl b/src/root/offline.jl
index 6b40407b..5dadd79c 100644
--- a/src/root/offline.jl
+++ b/src/root/offline.jl
@@ -152,6 +152,7 @@ end
 struct OfflineTree{T}
     _fobj::UnROOT.ROOTFile
     header::Union{MCHeader, Missing}
+    _frame_index_trigger_counter_lookup_map::Dict{Tuple{Int, Int}, Int}
     _t::T  # carry the type to ensure type-safety
 
     function OfflineTree(fobj::UnROOT.ROOTFile)
@@ -201,7 +202,7 @@ struct OfflineTree{T}
 
         header = "Head" ∈ keys(fobj) ? MCHeader(fobj["Head"]) : missing
 
-        new{typeof(t)}(fobj, header, t)
+        new{typeof(t)}(fobj, header, Dict{Tuple{Int, Int}, Int}(), t)
     end
 end
 OfflineTree(filename::AbstractString) = OfflineTree(UnROOT.ROOTFile(filename))
@@ -221,6 +222,7 @@ end
 Base.getindex(f::OfflineTree, r::UnitRange) = [f[idx] for idx ∈ r]
 Base.getindex(f::OfflineTree, mask::BitArray) = [f[idx] for (idx, selected) ∈ enumerate(mask) if selected]
 function Base.getindex(f::OfflineTree, idx::Integer)
+    idx > length(f) && throw(BoundsError(f, idx))
     e = f._t[idx]  # the event as NamedTuple: struct of arrays
 
     skip_mc_event_time = !hasproperty(e, :mc_event_time_Sec)
diff --git a/src/root/online.jl b/src/root/online.jl
index 248b8a5b..aa91483a 100644
--- a/src/root/online.jl
+++ b/src/root/online.jl
@@ -141,6 +141,7 @@ struct OnlineTree
     _fobj::UnROOT.ROOTFile
     events::EventContainer
     summaryslices::SummarysliceContainer
+    _frame_index_trigger_counter_lookup_map::Dict{Tuple{Int, Int}, Int}
 
     function OnlineTree(fobj::UnROOT.ROOTFile)
         new(fobj,
@@ -152,7 +153,8 @@ struct OnlineTree
             SummarysliceContainer(
                 UnROOT.LazyBranch(fobj, "KM3NET_SUMMARYSLICE/KM3NET_SUMMARYSLICE/KM3NETDAQ::JDAQSummarysliceHeader"),
                 UnROOT.LazyBranch(fobj, "KM3NET_SUMMARYSLICE/KM3NET_SUMMARYSLICE/vector<KM3NETDAQ::JDAQSummaryFrame>")
-            )
+            ),
+            Dict{Tuple{Int, Int}, Int}()
         )
 
     end
diff --git a/src/tools/helpers.jl b/src/tools/helpers.jl
index cfaa44c7..d8149848 100644
--- a/src/tools/helpers.jl
+++ b/src/tools/helpers.jl
@@ -18,3 +18,43 @@ function Base.iterate(itr::MCEventMatcher, state=1)
     state > length(itr) && return nothing
     (itr[state], state + 1)
 end
+
+
+countevents(tree::OfflineTree) = length(tree)
+countevents(tree::OnlineTree) = length(tree.events)
+triggercounterof(e::Evt) = e.trigger_counter
+frameindexof(e::Evt) = e.frame_index
+triggercounterof(e::DAQEvent) = e.header.trigger_counter
+frameindexof(e::DAQEvent) = e.header.frame_index
+
+"""
+
+Retrieves the event with for a given `frame_index` and `trigger_counter`.
+
+"""
+function getevent(tree::T, frame_index, trigger_counter) where T<:Union{OnlineTree, OfflineTree}
+    lookup = tree._frame_index_trigger_counter_lookup_map
+    key = (frame_index, trigger_counter)
+    if haskey(lookup, key)
+        event_idx = lookup[key]
+        return getevent(tree, event_idx)
+    end
+
+    highest_event_idx = length(lookup) == 0 ? 0 : maximum(values(lookup))
+
+    for event_idx in (highest_event_idx+1):countevents(tree)
+        event = getevent(tree, event_idx)
+
+        fi = frameindexof(event)
+        tc = triggercounterof(event)
+        lookup[(fi, tc)] = event_idx
+
+        if fi == frame_index && tc == trigger_counter
+            return event
+        end
+    end
+
+    error("No online event found for frame_index=$(frame_index) and trigger_counter=$(trigger_counter).")
+end
+getevent(tree::OfflineTree, idx) = tree[idx]
+getevent(tree::OnlineTree, idx) = tree.events[idx]
-- 
GitLab