Skip to content

Commit da4ef84

Browse files
committed
Add ACTS clusterer
1 parent c223a47 commit da4ef84

File tree

2 files changed

+147
-25
lines changed

2 files changed

+147
-25
lines changed

Detectors/Upgrades/ALICE3/TRK/reconstruction/src/ClustererACTS.cxx

Lines changed: 145 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414

1515
#include "TRKReconstruction/ClustererACTS.h"
1616
#include "TRKBase/GeometryTGeo.h"
17+
#include "DataFormatsITSMFT/ClusterPattern.h"
1718
#include <Acts/Clusterization/Clusterization.hpp>
1819

1920
#include <algorithm>
21+
#include <array>
2022
#include <numeric>
2123

2224
using namespace o2::trk;
@@ -176,29 +178,6 @@ void ClustererACTS::process(gsl::span<const Digit> digits,
176178
continue;
177179
}
178180

179-
// template <typename CellCollection, typename ClusterCollection,
180-
// std::size_t GridDim = 2,
181-
// typename Connect = DefaultConnect<typename CellCollection::value_type, GridDim>>
182-
// requires(GridDim == 1 || GridDim == 2)
183-
// void createClusters(Acts::Ccl::ClusteringData& data,
184-
// CellCollection& cells,
185-
// ClusterCollection& clusters,
186-
// Connect&& connect = Connect());
187-
using Cell = Cell2D;
188-
using CellCollection = std::vector<Cell>;
189-
using Cluster = Cluster2D;
190-
using ClusterCollection = std::vector<Cluster>;
191-
CellCollection cells;
192-
Acts::Ccl::ClusteringData data;
193-
ClusterCollection collection;
194-
195-
Acts::Ccl::createClusters<CellCollection, ClusterCollection, 2>(data,
196-
cells,
197-
collection,
198-
Acts::Ccl::DefaultConnect<Cell, 2>(false));
199-
200-
LOG(debug) << "Clustering with ACTS, found " << collection.size() << " clusters in ROF " << iROF;
201-
202181
// Sort digit indices within this ROF by (chipID, col, row) so we can process
203182
// chip by chip, column by column -- the same ordering the ALPIDE scanner expects.
204183
mSortIdx.resize(nEntries);
@@ -215,6 +194,17 @@ void ClustererACTS::process(gsl::span<const Digit> digits,
215194
return da.getRow() < db.getRow();
216195
});
217196

197+
// Type aliases for ACTS clustering
198+
using Cell = Cell2D;
199+
using CellCollection = std::vector<Cell>;
200+
using Cluster = Cluster2D;
201+
using ClusterCollection = std::vector<Cluster>;
202+
static constexpr int GridDim = 2; ///< Dimensionality of the clustering grid (2D for pixel detectors)
203+
204+
CellCollection cells; // Input collection of cells (pixels) to be clustered
205+
Acts::Ccl::ClusteringData data; // Internal data structure used by ACTS clustering algorithm
206+
ClusterCollection clsCollection; // Output collection of clusters found by the algorithm
207+
218208
// Process one chip at a time
219209
int sliceStart = 0;
220210
while (sliceStart < nEntries) {
@@ -225,9 +215,139 @@ void ClustererACTS::process(gsl::span<const Digit> digits,
225215
}
226216
const int chipN = sliceStart - chipFirst;
227217

228-
mThread->processChip(digits, chipFirst, chipN, &clusters, &patterns, digitLabels, clusterLabels, geom);
229-
}
218+
// Fill cells from digits for this chip
219+
cells.clear();
220+
data.clear();
221+
clsCollection.clear();
222+
cells.reserve(chipN);
223+
for (int i = chipFirst; i < chipFirst + chipN; ++i) {
224+
const auto& digit = digits[mSortIdx[i]];
225+
cells.emplace_back(digit.getRow(), digit.getColumn());
226+
}
227+
228+
LOG(debug) << "Clustering with ACTS on chip " << chipID << " " << cells.size() << " digits";
229+
Acts::Ccl::createClusters<CellCollection, ClusterCollection, GridDim>(data,
230+
cells,
231+
clsCollection,
232+
Acts::Ccl::DefaultConnect<Cell, GridDim>(false));
233+
234+
LOG(debug) << " found " << clsCollection.size() << " clusters";
235+
236+
// Convert ACTS clusters to O2 clusters
237+
for (const auto& actsCluster : clsCollection) {
238+
if (actsCluster.cells.empty()) {
239+
continue;
240+
}
241+
242+
// Calculate bounding box
243+
uint16_t rowMin = static_cast<uint16_t>(actsCluster.cells[0].row);
244+
uint16_t rowMax = rowMin;
245+
uint16_t colMin = static_cast<uint16_t>(actsCluster.cells[0].col);
246+
uint16_t colMax = colMin;
247+
248+
for (const auto& cell : actsCluster.cells) {
249+
rowMin = std::min(rowMin, static_cast<uint16_t>(cell.row));
250+
rowMax = std::max(rowMax, static_cast<uint16_t>(cell.row));
251+
colMin = std::min(colMin, static_cast<uint16_t>(cell.col));
252+
colMax = std::max(colMax, static_cast<uint16_t>(cell.col));
253+
}
254+
255+
const uint16_t rowSpan = rowMax - rowMin + 1;
256+
const uint16_t colSpan = colMax - colMin + 1;
257+
258+
// Check if cluster needs splitting (too large for pattern encoding)
259+
const bool isHuge = rowSpan > o2::itsmft::ClusterPattern::MaxRowSpan ||
260+
colSpan > o2::itsmft::ClusterPattern::MaxColSpan;
261+
262+
if (isHuge) {
263+
// Split huge cluster into MaxRowSpan x MaxColSpan tiles
264+
LOG(warning) << "Splitting huge TRK cluster: chipID " << chipID
265+
<< ", rows " << rowMin << ":" << rowMax
266+
<< " cols " << colMin << ":" << colMax;
267+
268+
for (uint16_t tileColMin = colMin; tileColMin <= colMax;
269+
tileColMin = static_cast<uint16_t>(tileColMin + o2::itsmft::ClusterPattern::MaxColSpan)) {
270+
uint16_t tileColMax = std::min(colMax, static_cast<uint16_t>(tileColMin + o2::itsmft::ClusterPattern::MaxColSpan - 1));
271+
272+
for (uint16_t tileRowMin = rowMin; tileRowMin <= rowMax;
273+
tileRowMin = static_cast<uint16_t>(tileRowMin + o2::itsmft::ClusterPattern::MaxRowSpan)) {
274+
uint16_t tileRowMax = std::min(rowMax, static_cast<uint16_t>(tileRowMin + o2::itsmft::ClusterPattern::MaxRowSpan - 1));
275+
276+
// Collect cells in this tile
277+
std::vector<std::pair<uint16_t, uint16_t>> tileCells;
278+
for (const auto& cell : actsCluster.cells) {
279+
uint16_t r = static_cast<uint16_t>(cell.row);
280+
uint16_t c = static_cast<uint16_t>(cell.col);
281+
if (r >= tileRowMin && r <= tileRowMax && c >= tileColMin && c <= tileColMax) {
282+
tileCells.emplace_back(r, c);
283+
}
284+
}
285+
286+
if (tileCells.empty()) {
287+
continue;
288+
}
289+
290+
uint16_t tileRowSpan = tileRowMax - tileRowMin + 1;
291+
uint16_t tileColSpan = tileColMax - tileColMin + 1;
292+
293+
// Encode pattern for this tile
294+
std::array<unsigned char, o2::itsmft::ClusterPattern::MaxPatternBytes> patt{};
295+
for (const auto& [r, c] : tileCells) {
296+
uint32_t ir = r - tileRowMin;
297+
uint32_t ic = c - tileColMin;
298+
int nbit = ir * tileColSpan + ic;
299+
patt[nbit >> 3] |= (0x1 << (7 - (nbit % 8)));
300+
}
301+
patterns.emplace_back(static_cast<unsigned char>(tileRowSpan));
302+
patterns.emplace_back(static_cast<unsigned char>(tileColSpan));
303+
const int nBytes = (tileRowSpan * tileColSpan + 7) / 8;
304+
patterns.insert(patterns.end(), patt.begin(), patt.begin() + nBytes);
305+
306+
// Create O2 cluster for this tile
307+
o2::trk::Cluster cluster;
308+
cluster.chipID = chipID;
309+
cluster.row = tileRowMin;
310+
cluster.col = tileColMin;
311+
cluster.size = static_cast<uint16_t>(tileCells.size());
312+
if (geom) {
313+
cluster.subDetID = static_cast<int16_t>(geom->getSubDetID(chipID));
314+
cluster.layer = static_cast<int16_t>(geom->getLayer(chipID));
315+
cluster.disk = static_cast<int16_t>(geom->getDisk(chipID));
316+
}
317+
clusters.emplace_back(cluster);
318+
}
319+
}
320+
} else {
321+
// Normal cluster - encode directly
322+
std::array<unsigned char, o2::itsmft::ClusterPattern::MaxPatternBytes> patt{};
323+
for (const auto& cell : actsCluster.cells) {
324+
uint32_t ir = static_cast<uint32_t>(cell.row - rowMin);
325+
uint32_t ic = static_cast<uint32_t>(cell.col - colMin);
326+
int nbit = ir * colSpan + ic;
327+
patt[nbit >> 3] |= (0x1 << (7 - (nbit % 8)));
328+
}
329+
patterns.emplace_back(static_cast<unsigned char>(rowSpan));
330+
patterns.emplace_back(static_cast<unsigned char>(colSpan));
331+
const int nBytes = (rowSpan * colSpan + 7) / 8;
332+
patterns.insert(patterns.end(), patt.begin(), patt.begin() + nBytes);
333+
334+
// Create O2 cluster
335+
o2::trk::Cluster cluster;
336+
cluster.chipID = chipID;
337+
cluster.row = rowMin;
338+
cluster.col = colMin;
339+
cluster.size = static_cast<uint16_t>(actsCluster.cells.size());
340+
if (geom) {
341+
cluster.subDetID = static_cast<int16_t>(geom->getSubDetID(chipID));
342+
cluster.layer = static_cast<int16_t>(geom->getLayer(chipID));
343+
cluster.disk = static_cast<int16_t>(geom->getDisk(chipID));
344+
}
345+
clusters.emplace_back(cluster);
346+
}
347+
}
230348

349+
LOG(debug) << " clusterization of chip " << chipID << " completed!";
350+
}
231351
clusterROFs.emplace_back(inROF.getBCData(), inROF.getROFrame(),
232352
outFirst, static_cast<int>(clusters.size()) - outFirst);
233353
}

Detectors/Upgrades/ALICE3/TRK/workflow/src/ClustererSpec.cxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ void ClustererDPL::run(o2::framework::ProcessingContext& pc)
5353

5454
#ifdef O2_WITH_ACTS
5555
if (mUseACTS) {
56+
LOG(info) << "Running TRKClusterer with ACTS";
5657
mClustererACTS.process(digits,
5758
rofs,
5859
clusters,
@@ -65,6 +66,7 @@ void ClustererDPL::run(o2::framework::ProcessingContext& pc)
6566
} else
6667
#endif
6768
{
69+
LOG(info) << "Running TRKClusterer";
6870
mClusterer.process(digits,
6971
rofs,
7072
clusters,

0 commit comments

Comments
 (0)