CbmRoot
Loading...
Searching...
No Matches
trd/Clusterizer.cxx
Go to the documentation of this file.
1/* Copyright (C) 2024 Facility for Antiproton and Ion Research in Europe, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Dominik Smith [committer], Etienne Bechtel, Florian Uhlig */
4
5#include "Clusterizer.h"
6
7#include <algorithm>
8#include <unordered_map>
9
10namespace cbm::algo::trd
11{
12
13 //_______________________________________________________________________________
14 std::vector<Cluster> Clusterizer::operator()(const std::vector<std::pair<CbmTrdDigi, int32_t>>& inVec) const
15 {
16 std::vector<inputType> inputData; //digis storage;
17 std::vector<Cluster> clustersOut;
18 std::vector<inputType*> digiPtrVec; //digis pointer storage (kSelf only);
19 std::vector<std::vector<inputType*>> digiMapSelf; //channel-wise sorted input
20 std::vector<std::vector<inputType*>> digiMapNeig; //channel-wise sorted input
21
22 const size_t numCols = fParams.rowPar[0].padPar.size();
23 const size_t numRows = fParams.rowPar.size();
24 const size_t numChan = numCols * numRows;
25
26 for (auto& input : inVec) {
27 inputData.push_back(std::make_tuple(input.second, &input.first, input.first.GetTime()));
28 }
30
31 // Initialize the digi maps
32 digiMapSelf.resize(numChan);
33 digiMapNeig.resize(numChan);
34
35 for (auto& digidata : inputData) {
36 const CbmTrdDigi* digi = (const CbmTrdDigi*) std::get<1>(digidata);
37 if (!digi) continue; // Skip invalid digis
38 const CbmTrdDigi::eTriggerType type = static_cast<CbmTrdDigi::eTriggerType>(digi->GetTriggerType());
39 const int channel = digi->GetAddressChannel();
41 digiMapSelf[channel].push_back(&digidata);
42 digiPtrVec.push_back(&digidata);
43 }
45 digiMapNeig[channel].push_back(&digidata);
46 }
47 }
48
49 //Store last position in input channels to avoid unnecessary checks.
50 std::vector<std::vector<inputType*>::iterator> lastChanPosSelf, lastChanPosNeig;
51 for (size_t chan = 0; chan < numChan; chan++) {
52 lastChanPosSelf.push_back(digiMapSelf[chan].begin());
53 lastChanPosNeig.push_back(digiMapNeig[chan].begin());
54 }
55
56 // search for an unprocessed main triggered digi and then start a subloop to
57 // directly construct the cluster (search for main-trigger then add the neighbors)
58 for (auto mainit = digiPtrVec.begin(); mainit != digiPtrVec.end(); mainit++) {
59
60 // Skip if digi already processed
61 const CbmTrdDigi* digi = (const CbmTrdDigi*) std::get<1>(**mainit);
62 if (digi == nullptr) continue;
63
64 // get digi time
65 const double time = std::get<2>(**mainit);
66
67 // variety of neccessary address information; uses the "combiId" for the
68 // comparison of digi positions
69 const int digiId = std::get<0>(**mainit);
70 const int channel = digi->GetAddressChannel();
71 const int ncols = fParams.rowPar[0].padPar.size();
72
73 // some logic information which is used to process and find the clusters
74 int lowcol = channel;
75 int highcol = channel;
76
77 // the "seal" bools register when the logical end of the cluster was found
78 bool sealtopcol = false;
79 bool sealbotcol = false;
80
81 // already seal the cluster if the main trigger is already at the right or left padrow border
82 if (channel % ncols == ncols - 1) {
83 sealtopcol = true;
84 }
85 if (channel % ncols == 0) {
86 sealbotcol = true;
87 }
88
89 // //vector which contains the actual cluster
90 std::vector<std::pair<int, const CbmTrdDigi*>> cluster;
91 cluster.emplace_back(digiId, digi);
92 std::get<1>(**mainit) = nullptr;
93
94 // loop to find the other pads corresponding to the main trigger
95 // is exited either if the implemented trigger logic is fullfilled
96 // or if there are no more adjacend pads due to edges,etc.
97 while (true) {
98
99 // counter which is used to easily break clusters which are at the edge and
100 // therefore do not fullfill the classical look
101 const size_t oldSize = cluster.size();
102
103 const int col = channel % ncols;
104 if (col == ncols - 1) sealtopcol = true;
105 if (col == 0) sealbotcol = true;
106
107 if (!sealbotcol && 0 <= lowcol - 1) {
108 if (TryAddDigi(&digiMapSelf, lowcol - 1, &lastChanPosSelf, &cluster, time)) {
109 lowcol--;
110 }
111 }
112 if (!sealtopcol && highcol + 1 < numChan) {
113 if (TryAddDigi(&digiMapSelf, highcol + 1, &lastChanPosSelf, &cluster, time)) {
114 highcol++;
115 }
116 }
117 if (!sealbotcol && 0 <= lowcol - 1) {
118 if (TryAddDigi(&digiMapNeig, lowcol - 1, &lastChanPosNeig, &cluster, time)) {
119 sealbotcol = true;
120 }
121 }
122 if (!sealtopcol && highcol + 1 < numChan) {
123 if (TryAddDigi(&digiMapNeig, highcol + 1, &lastChanPosNeig, &cluster, time)) {
124 sealtopcol = true;
125 }
126 }
127
129
130 // some finish criteria
131 if (cluster.size() - oldSize == 0) break;
132 if (sealbotcol && sealtopcol) break;
133 }
134
135 addClusters(cluster, &clustersOut);
136 }
137
138 return clustersOut;
139 }
140
141 bool Clusterizer::TryAddDigi(std::vector<std::vector<inputType*>>* digimap, int chan,
142 std::vector<std::vector<inputType*>::iterator>* lastPos,
143 std::vector<std::pair<int, const CbmTrdDigi*>>* cluster, const double digiTime) const
144 {
146
147 // find the FN digis of main trigger or adjacent main triggers
148 for (auto FNit = (*lastPos)[chan]; FNit != (*digimap)[chan].end(); FNit++) {
149
150 // update starting time
151 const double newtime = std::get<2>(**FNit);
152 if (newtime < digiTime - interval) {
153 (*lastPos)[chan]++;
154 continue;
155 }
156
157 // break if out of range
158 if (newtime > digiTime + interval) break;
159
160 // Skip already processed digis
161 const CbmTrdDigi* d = (const CbmTrdDigi*) std::get<1>(**FNit);
162 if (d == nullptr) continue;
163
164 // add digi to cluster
165 const int digiid = std::get<0>(**FNit);
166 cluster->emplace_back(digiid, d);
167 std::get<1>(**FNit) = nullptr;
168 return true;
169 }
170 return false;
171 }
172
173 //_____________________________________________________________________
174 void Clusterizer::addClusters(std::vector<std::pair<int, const CbmTrdDigi*>> cluster,
175 std::vector<Cluster>* clustersOut) const
176 {
177 // create vector for indice matching
178 std::vector<int> digiIndices;
179 digiIndices.reserve(cluster.size());
180
181 // add digi ids to vector
182 std::transform(cluster.begin(), cluster.end(), std::back_inserter(digiIndices),
183 [](const auto& pair) { return pair.first; });
184
185 // create vector for pointers
186 std::vector<const CbmTrdDigi*> digis;
187 digis.reserve(cluster.size());
188
189 // add digi ids to vector
190 std::transform(cluster.begin(), cluster.end(), std::back_inserter(digis),
191 [](const auto& pair) { return pair.second; });
192
193 // Count rows and columns (TO DO: needs to be re-computed / moved if row merging is implemented)
194 std::unordered_map<int, bool> cols, rows;
195 for (const auto& pair : cluster) {
196 const int ncols = fParams.rowPar[0].padPar.size();
197 int digiChannel = pair.second->GetAddressChannel();
198 int colId = digiChannel % ncols;
199 int globalRow = digiChannel / ncols;
200 int combiId = globalRow * ncols + colId;
201 cols[combiId] = true;
202 rows[globalRow] = true;
203 }
204
205 // add the cluster to the Array
206 clustersOut->emplace_back(digiIndices, digis, fParams.address, cols.size(), rows.size());
207 }
208
209} // namespace cbm::algo::trd
int32_t GetTriggerType() const
Channel trigger type. SPADIC specific see CbmTrdTriggerType.
Definition CbmTrdDigi.h:163
int32_t GetAddressChannel() const
Getter read-out id.
static float Clk(eCbmTrdAsicType ty)
DAQ clock accessor for each ASIC.
Definition CbmTrdDigi.h:109
bool TryAddDigi(std::vector< std::vector< inputType * > > *digimap, int chan, std::vector< std::vector< inputType * >::iterator > *lastPos, std::vector< std::pair< int, const CbmTrdDigi * > > *cluster, const double digiTime) const
std::vector< Cluster > operator()(const std::vector< std::pair< CbmTrdDigi, int32_t > > &inVec) const
Execution.
void addClusters(std::vector< std::pair< int, const CbmTrdDigi * > > cluster, std::vector< Cluster > *clustersOut) const
HitFinderModPar fParams
Parameter container.
std::vector< HitFinderRowPar > rowPar