Skip to content

Commit d00a745

Browse files
committed
ITS: fix time assignment
1 parent 7b71064 commit d00a745

File tree

7 files changed

+224
-19
lines changed

7 files changed

+224
-19
lines changed

DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ namespace its
3737
class TrackITS : public o2::track::TrackParCov
3838
{
3939
enum UserBits {
40-
kSharedClusters = 1 << 29
40+
kSharedClusters = 1 << 28
4141
};
4242

4343
using Cluster = o2::itsmft::Cluster;
@@ -93,7 +93,7 @@ class TrackITS : public o2::track::TrackParCov
9393

9494
GPUhdi() void setChi2(float chi2) { mChi2 = chi2; }
9595

96-
bool isBetter(const TrackITS& best, float maxChi2) const;
96+
bool isBetter(const TrackITS& best, float maxChi2 = o2::constants::math::VeryBig) const;
9797

9898
auto& getTimeStamp() { return mTime; }
9999
const auto& getTimeStamp() const { return mTime; }

Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class TrackerTraits
116116

117117
std::shared_ptr<BoundedMemoryResource> mMemoryPool;
118118
std::shared_ptr<tbb::task_arena> mTaskArena;
119-
dbscan::DBSCAN mDBScan;
119+
dbscan::DBSCAN mDBScan{};
120120

121121
protected:
122122
o2::gpu::GPUChainITS* mChain = nullptr;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
12+
#include <vector>
13+
#include <array>
14+
#include <algorithm>
15+
#include <limits>
16+
#include <cstdint>
17+
18+
namespace o2::its::utils
19+
{
20+
21+
using Bracket = std::pair<int32_t, int32_t>;
22+
constexpr Bracket InvalidBracket{std::numeric_limits<int32_t>::min(), std::numeric_limits<int32_t>::min()};
23+
24+
template <size_t N>
25+
Bracket computeSmallestBracket(const std::array<Bracket, N>& intervals)
26+
{
27+
// Collect valid intervals
28+
std::vector<Bracket> validIntervals;
29+
for (const auto& inter : intervals) {
30+
if (inter != InvalidBracket) {
31+
validIntervals.push_back(inter);
32+
}
33+
}
34+
35+
if (validIntervals.empty()) {
36+
return InvalidBracket;
37+
}
38+
39+
// Check for gaps: sort by start, verify each overlaps/touches the next
40+
std::sort(validIntervals.begin(), validIntervals.end());
41+
for (size_t i = 1; i < validIntervals.size(); ++i) {
42+
if (validIntervals[i].first > validIntervals[i - 1].second) {
43+
// Gap found: intervals are disconnected
44+
return InvalidBracket;
45+
}
46+
}
47+
48+
// Collect unique endpoints
49+
std::array<int32_t, 2 * N> ends;
50+
size_t count = 0;
51+
for (const auto& inter : validIntervals) {
52+
ends[count++] = inter.first;
53+
ends[count++] = inter.second;
54+
}
55+
56+
std::sort(ends.begin(), ends.begin() + count);
57+
auto last = std::unique(ends.begin(), ends.begin() + count);
58+
count = last - ends.begin();
59+
60+
int32_t bestLength = std::numeric_limits<int32_t>::max();
61+
Bracket bestBracket{InvalidBracket};
62+
63+
for (size_t i = 0; i < count; ++i) {
64+
const int32_t L = ends[i];
65+
for (size_t j = i + 1; j < count; ++j) {
66+
const int32_t R = ends[j];
67+
int32_t length = R - L;
68+
if (length >= bestLength) {
69+
break;
70+
}
71+
72+
bool overlaps = true;
73+
for (const auto& inter : validIntervals) {
74+
if (L >= inter.second || R <= inter.first) {
75+
overlaps = false;
76+
break;
77+
}
78+
}
79+
80+
if (overlaps) {
81+
bestLength = length;
82+
bestBracket = {L, R};
83+
break;
84+
}
85+
}
86+
}
87+
88+
return bestBracket;
89+
}
90+
91+
} // namespace o2::its::utils

Detectors/ITSMFT/ITS/tracking/src/Configuration.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ using namespace o2::its;
2424

2525
std::string TrackingParameters::asString() const
2626
{
27-
std::string str = std::format("NZb:{} NPhB:{} PerVtx:{} DropFail:{} ClSh:{} TrklMinPt:{:.2f} MinCl:{}", ZBins, PhiBins, PerPrimaryVertexProcessing, DropTFUponFailure, ClusterSharing, TrackletMinPt, MinTrackLength);
27+
std::string str = std::format("NZb:{} NPhB:{} PerVtx:{} DropFail:{} ClSh:{} TrklMinPt:{:.2f} MinCl:{} NSigma:{}", ZBins, PhiBins, PerPrimaryVertexProcessing, DropTFUponFailure, ClusterSharing, TrackletMinPt, MinTrackLength, NSigmaCut);
2828
bool first = true;
2929
for (int il = NLayers; il >= MinTrackLength; il--) {
3030
int slot = NLayers - il;

Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <oneapi/tbb/parallel_sort.h>
1919

2020
#include <algorithm>
21+
#include <cstddef>
2122
#include <iterator>
2223
#include <limits>
2324
#include <ranges>
@@ -40,6 +41,7 @@
4041
#include "ITStracking/BoundedAllocator.h"
4142
#include "ITStracking/IndexTableUtils.h"
4243
#include "ITStracking/Tracklet.h"
44+
#include "ITStracking/Utils.h"
4345
#include "ReconstructionDataFormats/Track.h"
4446

4547
/// optimization output
@@ -58,7 +60,7 @@ namespace o2::its
5860
{
5961
namespace
6062
{
61-
utils::TreeStreamRedirector* sDBGOut{nullptr};
63+
o2::utils::TreeStreamRedirector* sDBGOut{nullptr};
6264
}
6365

6466
struct PassMode {
@@ -570,8 +572,9 @@ void TrackerTraits<NLayers>::findCellSeeds(const int iteration)
570572
int rof = mTimeFrame->getClusterROF(i, cls[i]);
571573
int rofStartBC = mTimeFrame->getROFOverlapTableView().getLayer(i).getROFStartInBC(rof);
572574
int rofEndBC = mTimeFrame->getROFOverlapTableView().getLayer(i).getROFEndInBC(rof);
573-
startBC = o2::gpu::CAMath::Min(startBC, rofStartBC);
574-
endBC = o2::gpu::CAMath::Max(endBC, rofEndBC);
575+
// if the start/end of the cluster is after/before the current bracket need to enlarge
576+
startBC = (rofStartBC <= startBC) ? rofStartBC : o2::gpu::CAMath::Max(startBC, rofStartBC);
577+
endBC = (rofEndBC >= endBC) ? rofEndBC : o2::gpu::CAMath::Min(endBC, rofEndBC);
575578
}
576579
if (endBC - startBC < 0) { // this should not happen
577580
ltracks[iCell].markDead();
@@ -946,10 +949,10 @@ void TrackerTraits<NLayers>::processNeighbours(int iteration, int iLayer, int iL
946949
if (neighbourCell.getSecondTrackletIndex() != currentCell.getFirstTrackletIndex()) {
947950
continue;
948951
}
949-
if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) {
952+
if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
950953
continue;
951954
}
952-
if (currentCell.getLevel() - 1 != neighbourCell.getLevel()) {
955+
if (mTimeFrame->isClusterUsed(iLayer - 1, neighbourCell.getFirstClusterIndex())) {
953956
continue;
954957
}
955958

@@ -1143,15 +1146,17 @@ void TrackerTraits<NLayers>::findRoads(const int iteration)
11431146
}
11441147

11451148
deepVectorClear(trackSeeds);
1149+
// sort tracks in quality (accounting for 1. length; 2. chi2)
1150+
// needed since then tracks with shared clusters can be marked/discarded
11461151
tbb::parallel_sort(tracks.begin(), tracks.end(), [](const auto& a, const auto& b) {
1147-
return a.getChi2() < b.getChi2();
1152+
return a.isBetter(b);
11481153
});
11491154
});
11501155

11511156
for (auto& track : tracks) {
11521157
int nShared = 0;
11531158
bool isFirstShared{false};
1154-
int firstLayer{-1}, firstCluster{-1};
1159+
int firstLayer{constants::UnusedIndex}, firstCluster{constants::UnusedIndex};
11551160
for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) {
11561161
if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
11571162
continue;
@@ -1172,20 +1177,32 @@ void TrackerTraits<NLayers>::findRoads(const int iteration)
11721177

11731178
// here we can do the calculation of the time bracket simply
11741179
// by checkig in which rofs the clusters are
1175-
int bcStart{0}, bcEnd{std::numeric_limits<int>::max()};
1180+
std::array<utils::Bracket, NLayers> brackets;
1181+
brackets.fill(utils::InvalidBracket);
11761182
for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) {
11771183
if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
11781184
continue;
11791185
}
1180-
mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
11811186
int currentROF = mTimeFrame->getClusterROF(iLayer, track.getClusterIndex(iLayer));
1182-
int bcClsSta = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFStartInBC(currentROF);
1183-
int bcClsEnd = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFEndInBC(currentROF);
1184-
bcStart = std::max(bcStart, bcClsSta);
1185-
bcEnd = std::min(bcEnd, bcClsEnd);
1187+
// need to account for the imposed delay
1188+
int bcClsSta = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFStartInBC(currentROF, true);
1189+
int bcClsEnd = mTimeFrame->getROFOverlapTableView().getLayer(iLayer).getROFEndInBC(currentROF, true);
1190+
brackets[iLayer] = utils::Bracket{bcClsSta, bcClsEnd};
1191+
LOGP(debug, "\tlay:{} bcClsSta={} bcClsEnd={}", iLayer, bcClsSta, bcClsEnd);
1192+
}
1193+
const auto best = utils::computeSmallestBracket(brackets);
1194+
if (best == utils::InvalidBracket) {
1195+
continue; // track has an impossible span, discard
1196+
}
1197+
// mark used clusters for the next iteration
1198+
for (int iLayer{0}; iLayer < mRecoParams[iteration].params.NLayers; ++iLayer) {
1199+
if (track.getClusterIndex(iLayer) == constants::UnusedIndex) {
1200+
continue;
1201+
}
1202+
mTimeFrame->markUsedCluster(iLayer, track.getClusterIndex(iLayer));
11861203
}
1187-
track.getTimeStamp().setTimeStamp(bcStart);
1188-
track.getTimeStamp().setTimeStampError(bcEnd - bcStart + 1);
1204+
track.getTimeStamp().setTimeStamp(best.first);
1205+
track.getTimeStamp().setTimeStampError(best.second - best.first + 1);
11891206
track.setUserField(0);
11901207
track.getParamOut().setUserField(0);
11911208
mTimeFrame->getTracks().emplace_back(track);

Detectors/ITSMFT/ITS/tracking/test/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,9 @@ o2_add_test(roflookuptables
2020
COMPONENT_NAME its-tracking
2121
LABELS "its;tracking"
2222
PUBLIC_LINK_LIBRARIES O2::ITStracking)
23+
24+
o2_add_test(utils
25+
SOURCES testUtils.cxx
26+
COMPONENT_NAME its-tracking
27+
LABELS "its;tracking"
28+
PUBLIC_LINK_LIBRARIES O2::ITStracking)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
12+
#include <boost/test/tools/old/interface.hpp>
13+
#define BOOST_TEST_MODULE ITS Utils
14+
#define BOOST_TEST_MAIN
15+
#define BOOST_TEST_DYN_LINK
16+
17+
#include <boost/test/unit_test.hpp>
18+
19+
#include "ITStracking/Utils.h"
20+
using namespace o2::its::utils;
21+
22+
BOOST_AUTO_TEST_CASE(test_1)
23+
{
24+
const std::array<Bracket, 2> brackets{{{594, 1188},
25+
{297, 891}}};
26+
const auto result = computeSmallestBracket(brackets);
27+
BOOST_CHECK_EQUAL(result.first, 594);
28+
BOOST_CHECK_EQUAL(result.second, 891);
29+
}
30+
31+
BOOST_AUTO_TEST_CASE(test_2)
32+
{
33+
const std::array<Bracket, 7> brackets{{{594, 1188},
34+
{594, 1188},
35+
{594, 1188},
36+
{297, 891},
37+
{297, 891},
38+
{297, 891},
39+
{891, 1485}}};
40+
const auto result = computeSmallestBracket(brackets);
41+
BOOST_CHECK_EQUAL(result.first, 594);
42+
BOOST_CHECK_EQUAL(result.second, 1188);
43+
}
44+
45+
BOOST_AUTO_TEST_CASE(test_3)
46+
{
47+
std::array<Bracket, 7> brackets;
48+
brackets.fill(InvalidBracket);
49+
brackets[0] = {500, 600};
50+
brackets[3] = {500, 600};
51+
brackets[6] = {500, 600};
52+
const auto result = computeSmallestBracket(brackets);
53+
BOOST_CHECK_EQUAL(result.first, 500);
54+
BOOST_CHECK_EQUAL(result.second, 600);
55+
}
56+
57+
BOOST_AUTO_TEST_CASE(test_4)
58+
{
59+
std::array<Bracket, 3> brackets;
60+
brackets.fill(InvalidBracket);
61+
brackets[0] = {100, 200};
62+
brackets[2] = {500, 600};
63+
const auto result = computeSmallestBracket(brackets);
64+
BOOST_CHECK(result == InvalidBracket);
65+
}
66+
67+
BOOST_AUTO_TEST_CASE(test_5)
68+
{
69+
std::array<Bracket, 7> brackets{{{5346, 5940},
70+
{5346, 5940},
71+
{5346, 5940},
72+
{5049, 5643},
73+
{4455, 5049},
74+
{5049, 5643},
75+
{5049, 5643}}};
76+
const auto result = computeSmallestBracket(brackets);
77+
BOOST_CHECK(result != InvalidBracket);
78+
}
79+
80+
BOOST_AUTO_TEST_CASE(test_6)
81+
{
82+
std::array<Bracket, 7> brackets{{{46926, 47520},
83+
{46926, 47520},
84+
{46926, 47520},
85+
{47817, 48411},
86+
{47817, 48411},
87+
{47817, 48411},
88+
{47817, 48411}}};
89+
const auto result = computeSmallestBracket(brackets);
90+
BOOST_CHECK(result == InvalidBracket);
91+
}

0 commit comments

Comments
 (0)