Project
Loading...
Searching...
No Matches
TopologyClassifier.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
16
17// Include for bitset
18#include <bitset>
19
21
22using std::array;
23
24namespace o2
25{
26namespace iotof
27{
28
29o2::iotof::Segmentation* TopologyClassifier::sSegmentation = nullptr;
30
31void TopologyClassifier::getTopology(uint16_t bitmask, uint16_t minRow, uint8_t spanRow, uint16_t minCol, uint8_t spanCol, uint32_t& topology)
32{
33
34 // 1. Guard against spans exceeding 8-bit representation for
35 // row, col span and 16-bit bitmasks
36 if (spanRow > MaxRowSpan || spanCol > MaxColSpan || bitmask > MaxBitmask) {
37 topology = Topologies::kHuge;
38 return;
39 }
40
41 const uint32_t clsTopoKey = packKey(spanRow, spanCol, bitmask);
42
43 // Check if the topology is already cached
44 auto it = mTopologyCache.find(clsTopoKey);
45 if (it != mTopologyCache.end()) {
46 topology = it->second.mTopology;
47 it->second.mFrequency++;
48 return;
49 }
50
51 // Classify the new topology and cache the result
52 accountTopology(bitmask, minRow, spanRow, minCol, spanCol);
53 topology = mTopologyCache[clsTopoKey].mTopology;
54 LOG(debug) << "Classified new topology: " << static_cast<int>(topology);
55}
56
58{
59 auto it = mTopologyCache.find(key);
60 if (it != mTopologyCache.end()) {
61 return it->second;
62 } else {
63 LOG(debug) << "No cached features found for key: " << key;
64 return TopologyInfo(); // Return default-constructed TopologyInfo if not found
65 }
66}
67
68void TopologyClassifier::accountTopology(uint16_t bitmask, uint16_t minRow, uint8_t spanRow, uint16_t minCol, uint8_t spanCol)
69{
70 LOG(debug) << "Classifying topology for bitmask: " << std::bitset<16>(bitmask) << ", minRow: "
71 << static_cast<int>(minRow) << ", spanRow: " << static_cast<int>(spanRow)
72 << ", minCol: " << static_cast<int>(minCol) << ", spanCol: " << static_cast<int>(spanCol);
73
74 // New cluster topology features
75 TopologyInfo newTopo;
76 newTopo.mFrequency = 1;
77 newTopo.mPattern = bitmask;
78 newTopo.mSizeX = spanRow;
79 newTopo.mSizeZ = spanCol;
80 float xCOG{0.f}, zCOG{0.f}, mXMean{0.f}, mZMean{0.f}, mXSigma2{0.f}, mZSigma2{0.f};
81 computeCOG(bitmask, minRow, spanRow, minCol, spanCol, newTopo);
82
83 const int maxRow = minRow + spanRow - 1;
84 const int maxCol = minCol + spanCol - 1;
85
86 const auto hasDigit = [bitmask, minRow, minCol, spanCol](int row, int col) -> bool {
87 const int bitIndex = (row - minRow) * spanCol + (col - minCol);
88 return (bitmask & (1U << bitIndex)) != 0;
89 };
90
91 // Basic shapes
92 if (spanRow == 1 && spanCol == 1) {
94 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
95 return;
96 }
97 if (spanCol == 1) {
99 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
100 return;
101 }
102 if (spanRow == 1) {
104 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
105 return;
106 }
107
108 // Calculate total active digits in the cluster mask
109 int firedDigits = 0;
110 for (int r = minRow; r <= maxRow; ++r) {
111 for (int c = minCol; c <= maxCol; ++c) {
112 if (hasDigit(r, c)) {
113 firedDigits++;
114 }
115 }
116 }
117
118 // Square and rectangles: all pixels fired
119 if (firedDigits == spanRow * spanCol && spanRow == spanCol) {
121 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
122 return;
123 }
124 if (firedDigits == spanRow * spanCol && spanRow != spanCol) {
126 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
127 return;
128 }
129
130 // Corner occupancy
131 const bool hasBottomLeft = hasDigit(minRow, minCol);
132 const bool hasBottomRight = hasDigit(minRow, maxCol);
133 const bool hasTopLeft = hasDigit(maxRow, minCol);
134 const bool hasTopRight = hasDigit(maxRow, maxCol);
135
136 // Diagonal and triangles
137 if (spanRow == spanCol) {
138
139 // Triangles
140 const int nCorners = hasTopLeft + hasTopRight + hasBottomLeft + hasBottomRight;
141 if (nCorners == 3) {
142 const int missing = !hasTopLeft ? 0 : !hasTopRight ? 1
143 : !hasBottomLeft ? 2
144 : 3;
145
146 switch (missing) {
147 case 0:
149 break;
150 case 1:
152 break;
153 case 2:
155 break;
156 case 3:
158 break;
159 }
160 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
161 return;
162 }
163
164 if ((firedDigits == spanRow && hasTopLeft && hasBottomRight && !hasTopRight && !hasBottomLeft) ||
165 (firedDigits == spanRow && hasTopRight && hasBottomLeft && !hasTopLeft && !hasBottomRight)) {
167 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
168 return;
169 }
170 }
171
172 // Snake: 3 x 2
173 if (spanRow == 3 && spanCol == 2) {
174 const bool hasMiddleMin = hasDigit(minRow, minCol + 1);
175 const bool hasMiddleMax = hasDigit(minRow, maxCol + 1);
176
177 if (hasMiddleMin && hasMiddleMax) {
178 if (!hasTopLeft && !hasBottomRight && hasTopRight && hasBottomLeft) {
180 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
181 return;
182 }
183
184 if (hasTopLeft && hasBottomRight && !hasTopRight && !hasBottomLeft) {
186 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
187 return;
188 }
189 }
190 }
191
192 // Snake rotated by 90 degrees: 2 x 3
193 if (spanRow == 2 && spanCol == 3) {
194 const bool hasMiddleLeft = hasDigit(minRow + 1, minCol);
195 const bool hasMiddleRight = hasDigit(maxRow + 1, minCol);
196
197 if (hasMiddleLeft && hasMiddleRight) {
198 if (!hasTopLeft && !hasBottomRight && hasTopRight && hasBottomLeft) {
200 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
201 return;
202 }
203
204 if (hasTopLeft && hasBottomRight && !hasTopRight && !hasBottomLeft) {
206 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
207 return;
208 }
209 }
210 }
211
212 if (newTopo.mTopology == Topologies::kNTopologies) {
214 mTopologyCache[packKey(spanRow, spanCol, bitmask)] = newTopo;
215 return;
216 }
217}
218
219void TopologyClassifier::computeCOG(uint16_t bitmask, uint16_t minRow, uint8_t spanRow, uint16_t minCol, uint8_t spanCol, TopologyInfo& topoInfo)
220{
221 int xOffsetCOG = 0;
222 int zOffsetCOG = 0;
223 int firedPixels = 0;
224
225 // Ensure nBits does not exceed the bitmask capacity (16 bits)
226 const int nBits = std::min(static_cast<int>(spanRow * spanCol), 16);
227
228 for (int iBit = 0; iBit < nBits; ++iBit) {
229 // Check if the pixel bit is set
230 if (bitmask & (1U << iBit)) {
231 int iRow = iBit / spanCol;
232 int iCol = iBit % spanCol;
233
234 xOffsetCOG += minRow + iRow;
235 zOffsetCOG += minCol + iCol;
236 ++firedPixels;
237 }
238 }
239
240 topoInfo.mOffsetXToCOG = static_cast<int>((static_cast<float>(xOffsetCOG) / firedPixels) - static_cast<float>(minRow));
241 topoInfo.mOffsetZToCOG = static_cast<int>((static_cast<float>(zOffsetCOG) / firedPixels) - static_cast<float>(minCol));
242 topoInfo.mNPixels = firedPixels;
243
244 const auto& chipSpecs = ChipSpecificsParam::Instance();
245 topoInfo.mXMean = -(static_cast<float>(xOffsetCOG) / firedPixels - minRow) * chipSpecs.PitchRow;
246 topoInfo.mZMean = (static_cast<float>(zOffsetCOG) / firedPixels - minCol) * chipSpecs.PitchCol;
247 topoInfo.mXSigma2 = chipSpecs.PitchRow * chipSpecs.PitchRow / 12. / topoInfo.mSizeX;
248 topoInfo.mZSigma2 = chipSpecs.PitchCol * chipSpecs.PitchCol / 12. / topoInfo.mSizeZ;
249
250 LOG(debug) << "Computed topology features";
251 LOG(debug) << "COG offsets: (" << topoInfo.mOffsetXToCOG << ", " << topoInfo.mOffsetZToCOG << ")";
252 LOG(debug) << "Shifts to mean: (" << topoInfo.mXMean << ", " << topoInfo.mZMean << ")";
253 LOG(debug) << "Sigmas: (" << topoInfo.mXSigma2 << ", " << topoInfo.mZSigma2 << ")";
254 LOG(debug) << "Fired Pixels: " << firedPixels;
255}
256
257math_utils::Point3D<float> TopologyClassifier::getClusterCoordinates(const Cluster& cluster)
258{
259 if (!mGeometry) {
260 LOG(fatal) << "Geometry not set in TopologyClassifier, cannot execute getClusterCoordinates!";
261 return math_utils::Point3D<float>{0.f, 0.f, 0.f};
262 }
263 if (!sSegmentation) {
264 LOG(fatal) << "Segmentation not set in TopologyClassifier, cannot execute getClusterCoordinates!";
265 return math_utils::Point3D<float>{0.f, 0.f, 0.f};
266 }
267 auto refRow = cluster.getRow();
268 auto refCol = cluster.getCol();
269 float x{0.f};
270 float z{0.f};
271 int layer = mGeometry->getIOTOFLayer(cluster.getChipID());
272 sSegmentation->detectorToLocal(cluster.getRow(), cluster.getCol(), x, z, layer);
273
274 uint32_t topoKey = makeKey(cluster.getRowSpan(), cluster.getColSpan(), cluster.getPattern());
275 x += this->getTopologyFeatures(topoKey).mXMean;
276 z += this->getTopologyFeatures(topoKey).mZMean;
277 math_utils::Point3D<float> locCl{x, 0.f, z};
278
279 return locCl;
280}
281
283{
284 TFile file(filename, "RECREATE");
285 // Write directly using TObject::Write syntax with explicit class name handling
286 file.WriteObject(&mTopologyCache, "TF3ClusterTopologies");
287 file.Close();
288}
289
291{
292 for (const auto& entry : mTopologyCache) {
293 const uint32_t key = entry.first;
294 const TopologyInfo& topoInfo = entry.second;
295
296 uint8_t spanRow = (key >> 24) & 0xFF;
297 uint8_t spanCol = (key >> 16) & 0xFF;
298 uint16_t bitmask = key & 0xFFFF;
299
300 LOG(info) << "Key: " << key
301 << ", SpanRow: " << static_cast<int>(spanRow)
302 << ", SpanCol: " << static_cast<int>(spanCol)
303 << ", Bitmask: " << std::bitset<16>(bitmask);
304 topoInfo.print();
305 }
306}
307
308} // namespace iotof
309} // namespace o2
std::ostringstream debug
std::bitset< 80 > bitmask
uint32_t col
Definition RawData.h:4
uint32_t c
Definition RawData.h:2
ClassImp(o2::iotof::TopologyClassifier)
Definition of the TopologyClassifier class.
StringRef key
uint8_t getRowSpan() const
Definition Cluster.h:132
uint32_t getRow() const
Definition Cluster.h:130
uint32_t getCol() const
Definition Cluster.h:131
uint8_t getColSpan() const
Definition Cluster.h:133
uint32_t getChipID() const
Definition Cluster.h:149
uint32_t getPattern() const
Definition Cluster.h:134
int getIOTOFLayer(int index) const
Segmentation and response for pixels in inner and outer TOF of the ALICE 3 apparatus.
bool detectorToLocal(L row, L col, T &xRow, T &zCol, const int subDetectorID) const
void saveCacheToFile(const char *filename)
void computeCOG(uint16_t bitmask, uint16_t minRow, uint8_t spanRow, uint16_t minCol, uint8_t spanCol, TopologyInfo &topoInfo)
static constexpr uint8_t MaxColSpan
void accountTopology(uint16_t bitmask, uint16_t minRow, uint8_t spanRow, uint16_t minCol, uint8_t spanCol)
void getTopology(uint16_t bitmask, uint16_t minRow, uint8_t spanRow, uint16_t minCol, uint8_t spanCol, uint32_t &topology)
static constexpr uint16_t MaxBitmask
static uint32_t makeKey(uint8_t spanRow, uint8_t spanCol, uint16_t bitmask)
math_utils::Point3D< float > getClusterCoordinates(const Cluster &cluster)
TopologyInfo getTopologyFeatures(uint32_t key)
static constexpr uint8_t MaxRowSpan
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint entry
Definition glcorearb.h:5735
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLboolean r
Definition glcorearb.h:1233
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string filename()
uint16_t mPattern
Bitmask of fired pixels.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row