Skip to content

Commit c593dc7

Browse files
committed
Update
1 parent 5a1ce86 commit c593dc7

3 files changed

Lines changed: 101 additions & 44 deletions

File tree

‎Detectors/Upgrades/ALICE3/GlobalReconstruction/reconstruction/include/ALICE3GlobalReconstruction/TrackerACTS.h‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,12 @@ class TrackerACTS
139139
/// Run track finding from seeds
140140
void findTracks();
141141

142-
/// Convert fitted ACTS states to a TrackITSExt and publish it in the TimeFrame. Also adds the corresponding MC labels if available.
142+
/// Convert fitted ACTS states to a TrackITSExt and publish it in the TimeFrame.
143143
bool acceptTrack(const Acts::BoundTrackParameters& inner,
144144
const Acts::BoundTrackParameters& outer,
145145
const SeedACTS& seed, float chi2);
146+
/// Assign one MC label per accepted track, after all ROFs have been processed.
147+
void computeTracksMClabels();
146148

147149
/// Helper: time a task
148150
template <typename Func>
@@ -161,6 +163,9 @@ class TrackerACTS
161163
std::vector<SeedACTS> mSeeds;
162164
// Avoid accepting seeds which reuse a cluster already assigned to a track.
163165
std::unordered_set<uint64_t> mAcceptedClusters;
166+
// Layer-local indices in mUnsortedClusters, in the same order as getTracks().
167+
// Keep them separate from the external indices stored in TrackITSExt.
168+
std::vector<std::array<int, nLayers>> mAcceptedTrackClusterIndices;
164169

165170
// Tracking state
166171
float mBz{0.5f}; ///< Magnetic field in Tesla

‎Detectors/Upgrades/ALICE3/GlobalReconstruction/reconstruction/src/TrackerACTS.cxx‎

Lines changed: 88 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,8 @@ bool TrackerACTS<nLayers>::acceptTrack(const Acts::BoundTrackParameters& inner,
689689
const std::array<const SpacePoint*, 3> hits{seed.bottom, seed.middle, seed.top};
690690
std::array<int, o2::its::TrackITSExt::MaxClusters> clusterIndices;
691691
clusterIndices.fill(-1);
692+
std::array<int, nLayers> internalIndices;
693+
internalIndices.fill(-1);
692694
uint32_t pattern = 0;
693695
std::array<uint64_t, 3> keys{};
694696

@@ -708,8 +710,8 @@ bool TrackerACTS<nLayers>::acceptTrack(const Acts::BoundTrackParameters& inner,
708710
if (mAcceptedClusters.contains(keys[i])) {
709711
return false;
710712
}
711-
// The output track must refer to the original input-cluster index,
712-
// not its position in the TimeFrame's unsorted collection.
713+
// Keep the internal index for later MC lookup; publish the external one.
714+
internalIndices[hit->layer] = hit->clusterId;
713715
clusterIndices[hit->layer] = mTimeFrame->getClusterExternalIndex(hit->layer, hit->clusterId);
714716
if (clusterIndices[hit->layer] < 0) {
715717
return false;
@@ -751,56 +753,99 @@ bool TrackerACTS<nLayers>::acceptTrack(const Acts::BoundTrackParameters& inner,
751753
o2Track.getTimeStamp().setTimeStampError(maxHalfROF);
752754
}
753755

754-
// Keep track-label output in lockstep with the accepted tracks.
755-
o2::MCCompLabel label;
756-
if (mTimeFrame->hasMCinformation()) {
757-
std::vector<std::pair<o2::MCCompLabel, unsigned int>> counts;
758-
for (const auto* hit : hits) {
759-
for (const auto& candidate : mTimeFrame->getClusterLabels(hit->layer, hit->clusterId)) {
756+
// Labels are computed once, after all ROFs, from the internal indices.
757+
mTimeFrame->getTracks().emplace_back(std::move(o2Track));
758+
mAcceptedTrackClusterIndices.push_back(internalIndices);
759+
for (const auto key : keys) {
760+
mAcceptedClusters.insert(key);
761+
}
762+
return true;
763+
}
764+
765+
template <int nLayers>
766+
void TrackerACTS<nLayers>::computeTracksMClabels()
767+
{
768+
if (!mTimeFrame || !mTimeFrame->hasMCinformation()) {
769+
return;
770+
}
771+
772+
auto& tracks = mTimeFrame->getTracks();
773+
auto& labels = mTimeFrame->getTracksLabel();
774+
775+
if (tracks.size() != mAcceptedTrackClusterIndices.size()) {
776+
LOGP(fatal, "ACTS MC labeling: {} tracks but {} internal cluster reference sets",
777+
tracks.size(), mAcceptedTrackClusterIndices.size());
778+
return;
779+
}
780+
781+
// There must be exactly one label for each accepted track, in track order.
782+
labels.clear();
783+
labels.reserve(tracks.size());
784+
785+
struct LabelCount {
786+
o2::MCCompLabel label;
787+
int count;
788+
int lastHit;
789+
};
790+
791+
for (size_t iTrack = 0; iTrack < tracks.size(); ++iTrack) {
792+
auto& track = tracks[iTrack];
793+
const auto& indices = mAcceptedTrackClusterIndices[iTrack];
794+
std::vector<LabelCount> counts;
795+
int nHits = 0;
796+
797+
for (int layer = 0; layer < nLayers; ++layer) {
798+
if (indices[layer] < 0) {
799+
continue;
800+
}
801+
++nHits;
802+
for (const auto& candidate : mTimeFrame->getClusterLabels(layer, indices[layer])) {
760803
if (!candidate.isValid()) {
761804
continue;
762805
}
763806

764-
auto it = std::find_if(counts.begin(), counts.end(), [&](const auto& entry) {
765-
return entry.first == candidate;
807+
auto it = std::find_if(counts.begin(), counts.end(), [&candidate](const auto& entry) {
808+
return entry.label == candidate;
766809
});
767810
if (it == counts.end()) {
768-
counts.emplace_back(candidate, 1u);
769-
} else {
770-
++it->second;
811+
counts.push_back({candidate, 1, nHits});
812+
} else if (it->lastHit != nHits) {
813+
// Count a given truth label at most once per attached cluster.
814+
++it->count;
815+
it->lastHit = nHits;
771816
}
772817
}
773818
}
774-
if (!counts.empty()) {
775-
const auto best = std::max_element(counts.begin(), counts.end(),
776-
[](const auto& a, const auto& b) {
777-
return a.second < b.second;
778-
});
779-
label = best->first;
780-
if (best->second < hits.size()) {
781-
label.setFakeFlag();
819+
o2::MCCompLabel winner;
820+
uint32_t pattern = track.getPattern() & 0x0000ffffu;
821+
if (counts.empty()) {
822+
winner.setFakeFlag();
823+
} else {
824+
const auto best = std::max_element(counts.begin(), counts.end(), [](const auto& a, const auto& b) {
825+
return a.count < b.count;
826+
});
827+
winner = best->label;
828+
if (best->count != nHits) {
829+
winner.setFakeFlag();
782830
}
783-
uint32_t correctMask = pattern;
784-
for (const auto* hit : hits) {
785-
bool correct = false;
786-
for (const auto& candidate : mTimeFrame->getClusterLabels(hit->layer, hit->clusterId)) {
787-
correct |= candidate.isValid() && candidate == best->first;
831+
// Preserve the standard TrackITS pattern convention: bits [16, 31]
832+
// indicate clusters compatible with the representative MC label.
833+
for (int layer = 0; layer < nLayers; ++layer) {
834+
if (indices[layer] < 0) {
835+
continue;
788836
}
789-
if (correct) {
790-
correctMask |= (1u << (16 + hit->layer));
837+
for (const auto& candidate : mTimeFrame->getClusterLabels(layer, indices[layer])) {
838+
if (candidate.isValid() && candidate == best->label) {
839+
pattern |= (1u << (16 + layer));
840+
break;
841+
}
791842
}
792843
}
793-
o2Track.setPattern(correctMask);
794844
}
845+
track.setPattern(pattern);
846+
labels.emplace_back(winner);
795847
}
796-
mTimeFrame->getTracks().emplace_back(std::move(o2Track));
797-
if (mTimeFrame->hasMCinformation()) {
798-
mTimeFrame->getTracksLabel().emplace_back(label);
799-
}
800-
for (const auto key : keys) {
801-
mAcceptedClusters.insert(key);
802-
}
803-
return true;
848+
LOGP(info, "ACTS MC labeling: {} tracks, {} labels", tracks.size(), labels.size());
804849
}
805850

806851
template <int nLayers>
@@ -813,9 +858,9 @@ void TrackerACTS<nLayers>::clustersToTracks()
813858

814859
double totalTime = 0.;
815860
mAcceptedClusters.clear();
861+
mAcceptedTrackClusterIndices.clear();
816862
LOG(info) << "==== TRK ACTS Tracking ====";
817863

818-
// Initialize ACTS tracking geometry
819864
auto& actsGeometryManager = o2::acts::TrackingGeometryManager::instance();
820865
const auto& trackingGeometry = actsGeometryManager.get();
821866
(void)trackingGeometry;
@@ -842,6 +887,11 @@ void TrackerACTS<nLayers>::clustersToTracks()
842887
totalTime += evaluateTask([this]() { findTracks(); }, StateNames[mCurState]);
843888
}
844889

890+
// Run MC labeling once, after every accepted track has been published.
891+
if (mTimeFrame->hasMCinformation()) {
892+
computeTracksMClabels();
893+
}
894+
845895
LOG(info) << "=== TimeFrame " << mTimeFrameCounter << " completed in: " << totalTime << " ms ===";
846896
++mTimeFrameCounter;
847897
mTotalTime += totalTime;

‎Detectors/Upgrades/ALICE3/GlobalReconstruction/workflow/include/ALICE3GlobalReconstructionWorkflow/TrackerSpecImpl.h‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,19 @@ void TrackerDPL::runTracking(framework::ProcessingContext& pc, TimeFrameT& timeF
145145
trackerTraits.findRoads(iter);
146146
LOGP(info, "Number of roads in iteration {}: {}", iter, timeFrame.getNumberOfTracks());
147147
}
148+
if (mIsMC) {
149+
itsTracker.computeTracksMClabels();
150+
}
148151
}
149152
const auto trackingLoopElapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - trackingLoopStart).count();
150153
LOGP(info, "Tracking iterations block took {} ms", trackingLoopElapsedMs);
151154

152-
if (mIsMC) {
153-
itsTracker.computeTracksMClabels();
154-
}
155-
156155
const auto& tracks = timeFrame.getTracks();
157156
const auto& labels = timeFrame.getTracksLabel();
158-
const std::vector<o2::its::TrackITS> allTracks(tracks.begin(), tracks.end());
157+
if (mIsMC && tracks.size() != labels.size()) {
158+
LOGP(fatal, "TRK: {} reconstructed tracks but {} MC labels", tracks.size(), labels.size());
159+
}
160+
std::vector<o2::its::TrackITS> allTracks(tracks.begin(), tracks.end());
159161
std::vector<o2::MCCompLabel> allLabels;
160162

161163
const int totalTracks = allTracks.size();

0 commit comments

Comments
 (0)