|
2 | 2 |
|
3 | 3 | # breaking changes in Clustering v0.14 -> v0.15 |
4 | 4 | @inline _get_clusters(clusters::Clustering.DbscanResult) = clusters.clusters |
5 | | -@inline _get_clusters(clusters::Vector{Clustering.DbscanCluster}) = clusters |
| 5 | + |
| 6 | +@inline function finalize_group!(time_groups, current_group, new_index) |
| 7 | + push!(time_groups, current_group) |
| 8 | + return [new_index] |
| 9 | +end |
6 | 10 |
|
7 | 11 | function cluster_detector_hits( |
8 | 12 | detno::AbstractVector{<:Integer}, |
9 | 13 | edep::AbstractVector{TT}, |
10 | | - pos::AbstractVector{<:CartesianPoint{PT}}, |
11 | | - cluster_radius::RealQuantity |
12 | | -) where {TT<:RealQuantity, PT <: RealQuantity} |
| 14 | + pos::AbstractVector{CartesianPoint{PT}}, |
| 15 | + thit::AbstractVector{TTT}, |
| 16 | + cluster_radius::RealQuantity, |
| 17 | + cluster_time::RealQuantity |
| 18 | +) where {TT<:RealQuantity, PT <: RealQuantity, TTT <: RealQuantity} |
13 | 19 |
|
14 | | - pos = isa(first(pos), CartesianPoint) ? [SVector(p.x, p.y, p.z) for p in pos] : pos #converting CartesianPoint to SVector |
| 20 | + pos = [SVector(p.x, p.y, p.z) for p in pos] # converting CartesianPoint to SVector |
15 | 21 |
|
16 | 22 | Table = TypedTables.Table |
17 | | - unsorted = Table(detno = detno, edep = edep, pos = pos) |
| 23 | + unsorted = Table(detno = detno, edep = edep, pos = pos, thit = thit) |
18 | 24 | sorting_idxs = sortperm(unsorted.detno) |
19 | 25 | sorted = unsorted[sorting_idxs] |
20 | 26 | grouped = Table(consgroupedview(sorted.detno, TypedTables.columns(sorted))) |
21 | 27 |
|
22 | 28 | r_detno = similar(detno, 0) |
23 | 29 | r_edep = similar(edep, 0) |
24 | 30 | r_pos = similar(pos, 0) |
| 31 | + r_thit = similar(thit, 0) |
25 | 32 |
|
26 | 33 | posunit = unit(PT) |
27 | 34 | ustripped_cradius = ustrip(posunit, cluster_radius) |
28 | | - |
| 35 | + |
| 36 | + thitunit = unit(TTT) |
| 37 | + ustripped_ctime = ustrip(thitunit, cluster_time) |
| 38 | + |
29 | 39 | for d_hits_nt in grouped |
30 | 40 | d_hits = Table(d_hits_nt) |
31 | 41 | d_detno = first(d_hits.detno) |
32 | 42 | @assert all(isequal(d_detno), d_hits.detno) |
33 | | - if length(d_hits) > 3 |
34 | | - clusters = Clustering.dbscan(ustrip.(flatview(d_hits.pos)), ustripped_cradius, leafsize = 20, min_neighbors = 1, min_cluster_size = 1) |
35 | | - for c in _get_clusters(clusters) |
36 | | - idxs = vcat(c.boundary_indices, c.core_indices) |
37 | | - @assert length(idxs) == c.size |
38 | | - c_hits = view(d_hits, idxs) |
39 | | - |
40 | | - push!(r_detno, d_detno) |
41 | | - esum_u = sum(c_hits.edep) |
42 | | - push!(r_edep, esum_u) |
43 | | - esum = ustrip(esum_u) |
44 | | - if esum ≈ 0 |
45 | | - push!(r_pos, mean(c_hits.pos)) |
46 | | - else |
47 | | - weights = ustrip.(c_hits.edep) .* inv(esum) |
48 | | - push!(r_pos, sum(c_hits.pos .* weights)) |
| 43 | + |
| 44 | + # sort hits by time |
| 45 | + t_sort_idx = sortperm(d_hits.thit) |
| 46 | + d_hits = d_hits[t_sort_idx] |
| 47 | + t_vals = ustrip.(d_hits.thit) |
| 48 | + |
| 49 | + time_groups = Vector{Vector{Int}}() |
| 50 | + current_group = [1] |
| 51 | + start_time = t_vals[1] |
| 52 | + for i in 2:length(t_vals) |
| 53 | + if t_vals[i] - start_time ≤ ustripped_ctime |
| 54 | + push!(current_group, i) |
| 55 | + else |
| 56 | + current_group = finalize_group!(time_groups, current_group, i) |
| 57 | + start_time = t_vals[i] |
| 58 | + end |
| 59 | + end |
| 60 | + current_group = finalize_group!(time_groups, current_group, nothing) |
| 61 | + |
| 62 | + |
| 63 | + # spatial clustering within each temporal cluster |
| 64 | + for tg in time_groups |
| 65 | + t_hits = view(d_hits, tg) |
| 66 | + if length(t_hits) > 3 |
| 67 | + clusters = Clustering.dbscan(ustrip.(flatview(t_hits.pos)), ustripped_cradius; |
| 68 | + leafsize = 20, min_neighbors = 1, min_cluster_size = 1) |
| 69 | + for c in _get_clusters(clusters) |
| 70 | + idxs = vcat(c.boundary_indices, c.core_indices) |
| 71 | + @assert length(idxs) == c.size |
| 72 | + c_hits = view(t_hits, idxs) |
| 73 | + |
| 74 | + push!(r_detno, d_detno) |
| 75 | + esum_u = sum(c_hits.edep) |
| 76 | + push!(r_edep, esum_u) |
| 77 | + esum = ustrip(esum_u) |
| 78 | + if esum ≈ 0 |
| 79 | + push!(r_pos, mean(c_hits.pos)) |
| 80 | + push!(r_thit, mean(c_hits.thit)) |
| 81 | + else |
| 82 | + weights = ustrip.(c_hits.edep) .* inv(esum) |
| 83 | + push!(r_pos, sum(c_hits.pos .* weights)) |
| 84 | + push!(r_thit, sum(c_hits.thit .* weights)) |
| 85 | + end |
49 | 86 | end |
| 87 | + else |
| 88 | + append!(r_detno, t_hits.detno) |
| 89 | + append!(r_edep, t_hits.edep) |
| 90 | + append!(r_pos, t_hits.pos) |
| 91 | + append!(r_thit, t_hits.thit) |
50 | 92 | end |
51 | | - else |
52 | | - append!(r_detno, d_hits.detno) |
53 | | - append!(r_edep, d_hits.edep) |
54 | | - append!(r_pos, d_hits.pos) |
55 | 93 | end |
56 | 94 | end |
57 | 95 |
|
58 | | - (detno = r_detno, edep = r_edep, pos = r_pos) |
| 96 | + r_pos = [CartesianPoint(p[1], p[2], p[3]) for p in r_pos] #converting SVector back to CartesianPoint |
| 97 | + |
| 98 | + (detno = r_detno, edep = r_edep, pos = r_pos, thit = r_thit) |
59 | 99 | end |
60 | 100 |
|
61 | 101 |
|
62 | | -function cluster_detector_hits(table::TypedTables.Table, cluster_radius::RealQuantity) |
| 102 | +function cluster_detector_hits( |
| 103 | + table::TypedTables.Table, |
| 104 | + cluster_radius::PT, |
| 105 | + cluster_time::TTT |
| 106 | +) where {PT <: RealQuantity, TTT <: RealQuantity} |
63 | 107 | @assert :pos in TypedTables.columnnames(table) "Table has no column `pos`" |
| 108 | + @assert :thit in TypedTables.columnnames(table) "Table has no column `thit`" |
64 | 109 | @assert :edep in TypedTables.columnnames(table) "Table has no column `edep`" |
65 | 110 | @assert :detno in TypedTables.columnnames(table) "Table has no column `detno`" |
66 | 111 | clustered_nt = map( |
67 | | - evt -> cluster_detector_hits(evt.detno, evt.edep, evt.pos, cluster_radius), |
| 112 | + evt -> cluster_detector_hits( |
| 113 | + evt.detno, |
| 114 | + evt.edep, |
| 115 | + [p isa CartesianPoint ? p : CartesianPoint(p...) for p in evt.pos], |
| 116 | + evt.thit, |
| 117 | + cluster_radius, |
| 118 | + cluster_time |
| 119 | + ), |
68 | 120 | table |
69 | 121 | ) |
70 | 122 | TypedTables.Table(merge( |
|
0 commit comments