Skip to content

Commit 7b036be

Browse files
authored
ITS: optionally restrict CA to a subset of layers + support inactive layers (#15515)
* ITS: allow CA seeding on configurable layer subsets Add a SeedingLayers mask to TrackingParameters and use it when building the CA tracking topology. Transitions and cells are built only from layers that participate in seeding, while skipped non-seeding layers do not contribute to the effective seed length or hole budget. Move the track-seed selection predicate to TrackHelpers so CPU and GPU road finding use the same host/device logic. * ITS: distinguish inactive layers from track holes Add an InactiveLayerMask to TrackingParameters to represent detector layers that are absent for a given input or configuration. Inactive layers remain skippable, but they do not inflate the effective seed length or consume the ordinary hole budget. Guard the multiple-scattering helper against zero material so inactive layers can be configured with no material budget. * ITS: make sure that seeds are not cut by min track lenght * ITS: implement Felix' comments * ITS: second round of comments
1 parent 507a6f0 commit 7b036be

11 files changed

Lines changed: 139 additions & 49 deletions

File tree

Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,9 @@ void processNeighboursHandler(const int startLevel,
193193
const float MaxChi2ClusterAttachment,
194194
const float maxChi2NDF,
195195
const int maxHoles,
196-
const int minTrackLength,
196+
const int minSeedingClusters,
197197
const LayerMask holeLayerMask,
198+
const LayerMask nonSeedingLayerMask,
198199
const std::vector<float>& layerxX0Host,
199200
const o2::base::Propagator* propagator,
200201
const o2::base::PropagatorF::MatCorrType matCorrType,

Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,9 @@ void TrackerTraitsGPU<NLayers>::findRoads(const int iteration)
331331
this->mTrkParams[iteration].MaxChi2ClusterAttachment,
332332
this->mTrkParams[iteration].MaxChi2NDF,
333333
this->mTrkParams[iteration].MaxHoles,
334-
this->mTrkParams[iteration].MinTrackLength,
334+
this->mTrkParams[iteration].getMinSeedingClusters(),
335335
this->mTrkParams[iteration].HoleLayerMask,
336+
this->mTrkParams[iteration].getNonSeedingLayerMask(),
336337
this->mTrkParams[iteration].LayerxX0,
337338
mTimeFrameGPU->getDevicePropagator(),
338339
this->mTrkParams[iteration].CorrType,

Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
#include "ITStracking/Tracklet.h"
3333
#include "ITStracking/Cluster.h"
3434
#include "ITStracking/Cell.h"
35-
#include "ITStracking/TrackFollower.h"
3635
#include "ITStracking/TrackHelpers.h"
36+
#include "ITStracking/TrackFollower.h"
3737
#include "DataFormatsITS/TrackITS.h"
3838
#include "ITStrackingGPU/TrackingKernels.h"
3939
#include "ITStrackingGPU/Utils.h"
@@ -86,23 +86,6 @@ struct is_valid_pair {
8686
}
8787
};
8888

89-
template <int NLayers>
90-
struct seed_selector {
91-
float mMaxQ2Pt;
92-
float mMaxChi2;
93-
int mMaxHoles;
94-
int mMinTrackLength;
95-
LayerMask mHoleLayerMask;
96-
97-
GPUhd() seed_selector(float maxQ2Pt, float maxChi2, int maxHoles, int minTrackLength, LayerMask holeLayerMask) : mMaxQ2Pt(maxQ2Pt), mMaxChi2(maxChi2), mMaxHoles(maxHoles), mMinTrackLength(minTrackLength), mHoleLayerMask(holeLayerMask) {}
98-
GPUhd() bool operator()(const TrackSeed<NLayers>& seed) const
99-
{
100-
return !(seed.getQ2Pt() > mMaxQ2Pt || seed.getChi2() > mMaxChi2) &&
101-
seed.getHitLayerMask().length() >= mMinTrackLength &&
102-
seed.getHitLayerMask().isAllowed(mMaxHoles, mHoleLayerMask);
103-
}
104-
};
105-
10689
struct compare_track_chi2 {
10790
GPUhd() bool operator()(const TrackITSExt& a, const TrackITSExt& b) const
10891
{
@@ -975,8 +958,9 @@ void processNeighboursHandler(const int startLevel,
975958
const float maxChi2ClusterAttachment,
976959
const float maxChi2NDF,
977960
const int maxHoles,
978-
const int minTrackLength,
961+
const int minSeedingClusters,
979962
const LayerMask holeLayerMask,
963+
const LayerMask nonSeedingLayerMask,
980964
const std::vector<float>& layerxX0Host,
981965
const o2::base::Propagator* propagator,
982966
const o2::base::PropagatorF::MatCorrType matCorrType,
@@ -1110,7 +1094,7 @@ void processNeighboursHandler(const int startLevel,
11101094
}
11111095
GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream));
11121096
thrust::device_vector<TrackSeed<NLayers>, gpu::TypedAllocator<TrackSeed<NLayers>>> outSeeds(updatedCellSeed.size(), allocTrackSeed);
1113-
auto end = thrust::copy_if(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), gpu::seed_selector<NLayers>(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5), maxHoles, minTrackLength, holeLayerMask));
1097+
auto end = thrust::copy_if(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), track::TrackSeedSelector<NLayers>{constants::MaxTrackSeedQ2Pt, maxChi2NDF, startLevel, maxHoles, minSeedingClusters, holeLayerMask, nonSeedingLayerMask});
11141098
auto s{end - outSeeds.begin()};
11151099
seedsHost.reserve(seedsHost.size() + s);
11161100
thrust::copy(outSeeds.begin(), outSeeds.begin() + s, std::back_inserter(seedsHost));
@@ -1380,8 +1364,9 @@ template void processNeighboursHandler<7>(const int startLevel,
13801364
const float maxChi2ClusterAttachment,
13811365
const float maxChi2NDF,
13821366
const int maxHoles,
1383-
const int minTrackLength,
1367+
const int minSeedingClusters,
13841368
const LayerMask holeLayerMask,
1369+
const LayerMask nonSeedingLayerMask,
13851370
const std::vector<float>& layerxX0Host,
13861371
const o2::base::Propagator* propagator,
13871372
const o2::base::PropagatorF::MatCorrType matCorrType,
@@ -1580,8 +1565,9 @@ template void processNeighboursHandler<11>(const int startLevel,
15801565
const float maxChi2ClusterAttachment,
15811566
const float maxChi2NDF,
15821567
const int maxHoles,
1583-
const int minTrackLength,
1568+
const int minSeedingClusters,
15841569
const LayerMask holeLayerMask,
1570+
const LayerMask nonSeedingLayerMask,
15851571
const std::vector<float>& layerxX0Host,
15861572
const o2::base::Propagator* propagator,
15871573
const o2::base::PropagatorF::MatCorrType matCorrType,

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

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,42 @@ enum class IterationStep : uint16_t {
4646
using IterationSteps = o2::utils::EnumFlags<IterationStep>;
4747

4848
struct TrackingParameters {
49-
int CellMinimumLevel() const noexcept
49+
LayerMask getActiveLayerMask() const noexcept
50+
{
51+
return LayerMask::span(0, NLayers - 1) & ~InactiveLayerMask;
52+
}
53+
54+
LayerMask getSeedingLayerMask() const noexcept
55+
{
56+
const auto activeLayers = getActiveLayerMask();
57+
return SeedingLayers.empty() ? activeLayers : (SeedingLayers & activeLayers);
58+
}
59+
60+
LayerMask getNonSeedingLayerMask() const noexcept
61+
{
62+
return ~(getSeedingLayerMask());
63+
}
64+
65+
int getNSeedingLayers() const noexcept
66+
{
67+
return getSeedingLayerMask().count();
68+
}
69+
70+
int getMinSeedingClusters() const noexcept
5071
{
5172
const int minClusters = MinTrackLength - (MaxHoles > 0 ? MaxHoles : 0);
52-
const int effectiveMinClusters = minClusters > constants::ClustersPerCell ? minClusters : constants::ClustersPerCell;
53-
return effectiveMinClusters - constants::ClustersPerCell + 1;
73+
const int minClustersWithCells = minClusters > constants::ClustersPerCell ? minClusters : constants::ClustersPerCell;
74+
const int nSeedingLayers = getNSeedingLayers();
75+
return minClustersWithCells < nSeedingLayers ? minClustersWithCells : nSeedingLayers;
76+
}
77+
78+
int CellMinimumLevel() const noexcept
79+
{
80+
return getMinSeedingClusters() - constants::ClustersPerCell + 1;
5481
}
55-
int NeighboursPerRoad() const noexcept { return NLayers - 3; }
56-
int CellsPerRoad() const noexcept { return NLayers - 2; }
57-
int TrackletsPerRoad() const noexcept { return NLayers - 1; }
82+
int NeighboursPerRoad() const noexcept { return getNSeedingLayers() - 3; }
83+
int CellsPerRoad() const noexcept { return getNSeedingLayers() - 2; }
84+
int TrackletsPerRoad() const noexcept { return getNSeedingLayers() - 1; }
5885
std::string asString() const;
5986

6087
IterationSteps PassFlags{IterationStep::FirstPass, IterationStep::RebuildClusterLUT};
@@ -76,6 +103,8 @@ struct TrackingParameters {
76103
int MinTrackLength = 7;
77104
int MaxHoles = 0;
78105
LayerMask HoleLayerMask = 0;
106+
LayerMask InactiveLayerMask = 0;
107+
LayerMask SeedingLayers = 0;
79108
float NSigmaCut = 5;
80109
float PVres = 1.e-2f;
81110
/// Trackleting cuts

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ constexpr bool DoTimeBenchmarks = true;
2929
constexpr bool SaveTimeBenchmarks = false;
3030
constexpr float Tolerance = 1e-12; // numerical tolerance
3131
constexpr int ClustersPerCell = 3; // number of clusters for a cell
32+
constexpr float MaxTrackSeedQ2Pt = 1.e3f; // maximum q/pt for track seeds
3233
constexpr int UnusedIndex = -1; // global unused flag
3334
constexpr float UnsetValue = -999.f; // global unset value
3435
constexpr float Radl = 9.36f; // Radiation length of Si [cm]

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ GPUhdi() constexpr float SqDiff(float x, float y)
122122

123123
GPUhdi() float MSangle(float mass, float p, float xX0)
124124
{
125+
if (xX0 <= 0.f) {
126+
return 0.f;
127+
}
125128
float beta = p / o2::gpu::CAMath::Hypot(mass, p);
126129
return 0.0136f * o2::gpu::CAMath::Sqrt(xX0) * (1.f + 0.038f * o2::gpu::CAMath::Log(xX0)) / (beta * p);
127130
}

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

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "ITStracking/Cell.h"
2222
#include "ITStracking/Cluster.h"
2323
#include "ITStracking/Constants.h"
24+
#include "ITStracking/LayerMask.h"
2425
#include "ITStracking/MathUtils.h"
2526
#include "ITStracking/TrackITSInternal.h"
2627
#include "DetectorsBase/Propagator.h"
@@ -34,16 +35,46 @@ GPUhdi() bool isBetter(const int nClustersA, const float chi2A, const int nClust
3435
return (nClustersA > nClustersB) || (nClustersA == nClustersB && chi2A < chi2B);
3536
}
3637

37-
GPUhdi() bool isBetter(const o2::its::TrackITS& a, const o2::its::TrackITS& b)
38+
GPUhdi() bool isBetter(const auto& a, const auto& b)
3839
{
3940
return isBetter(a.getNumberOfClusters(), a.getChi2(), b.getNumberOfClusters(), b.getChi2());
4041
}
4142

4243
template <int NLayers>
43-
GPUhdi() bool isBetter(const o2::its::TrackITSInternal<NLayers>& a, const o2::its::TrackITSInternal<NLayers>& b)
44-
{
45-
return isBetter(a.getNumberOfClusters(), a.getChi2(), b.getNumberOfClusters(), b.getChi2());
46-
}
44+
struct TrackSeedSelector {
45+
float maxQ2Pt;
46+
float maxChi2;
47+
int maxHoles;
48+
int minTrackLength;
49+
LayerMask holeLayerMask;
50+
LayerMask nonSeedingLayerMask;
51+
52+
GPUhd() TrackSeedSelector(float maxQ2Pt, float maxChi2NDF, int startLevel, int maxHoles, int minTrackLength, LayerMask holeLayerMask, LayerMask nonSeedingLayerMask)
53+
: maxQ2Pt{maxQ2Pt}, maxChi2{maxChi2NDF * ((startLevel + 2) * 2 - 5)}, maxHoles{maxHoles}, minTrackLength{minTrackLength}, holeLayerMask{holeLayerMask}, nonSeedingLayerMask{nonSeedingLayerMask}
54+
{
55+
}
56+
57+
static GPUhdi() int getEffectiveTrackLength(LayerMask hitLayerMask, LayerMask excludedLayerMask)
58+
{
59+
if (hitLayerMask.empty()) {
60+
return 0;
61+
}
62+
return hitLayerMask.length() - (LayerMask::span(hitLayerMask.first(), hitLayerMask.last()) & excludedLayerMask).count();
63+
}
64+
65+
static GPUhdi() LayerMask getEffectiveHoleMask(LayerMask hitLayerMask, LayerMask excludedLayerMask)
66+
{
67+
return hitLayerMask.holeMask() & ~excludedLayerMask;
68+
}
69+
70+
GPUhd() bool operator()(const TrackSeed<NLayers>& seed) const
71+
{
72+
const auto hitLayerMask = seed.getHitLayerMask();
73+
return !(seed.getQ2Pt() > maxQ2Pt || seed.getChi2() > maxChi2) &&
74+
getEffectiveTrackLength(hitLayerMask, nonSeedingLayerMask) >= minTrackLength &&
75+
getEffectiveHoleMask(hitLayerMask, nonSeedingLayerMask).isAllowedHoleMask(maxHoles, holeLayerMask);
76+
}
77+
};
4778

4879
// Find the populated interior layer closest to the radial midpoint.
4980
// If no layer can be found, return constants::UnusedIndex.

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class TrackingTopology
7070
const CellTopology* cells{nullptr};
7171
const Range* cellsByFirstLinkIndex{nullptr};
7272
const Id* cellsByFirstLink{nullptr};
73+
Mask seedingLayerMask{0};
7374
Id nLinks{0};
7475
Id nCells{0};
7576
Id nCellsByFirstLink{0};
@@ -81,7 +82,7 @@ class TrackingTopology
8182
#ifndef GPUCA_GPUCODE
8283
std::string asString() const
8384
{
84-
std::string out = fmt::format("TrackingTopology: links={} cells={}", nLinks, nCells);
85+
std::string out = fmt::format("TrackingTopology: links={} cells={} seedingLayers={}", nLinks, nCells, seedingLayerMask.asString());
8586
out += "\n links:";
8687
for (Id linkId = 0; linkId < nLinks; ++linkId) {
8788
const auto& t = links[linkId];
@@ -104,15 +105,24 @@ class TrackingTopology
104105
#endif
105106
};
106107

107-
void init(int maxLayers, int maxHoles, Mask holeLayerMask)
108+
void init(int maxLayers, int maxHoles, Mask holeLayerMask, Mask seedingLayerMask = 0)
108109
{
109110
clear();
110111
mMaxLayers = o2::gpu::CAMath::Max(0, o2::gpu::CAMath::Min(maxLayers, NLayers));
111112
mMaxHoles = o2::gpu::CAMath::Max(maxHoles, 0);
112113
mHoleLayerMask = holeLayerMask;
114+
mSeedingLayerMask = seedingLayerMask.empty() ? Mask::span(0, mMaxLayers - 1) : (seedingLayerMask & Mask::span(0, mMaxLayers - 1));
115+
#ifndef GPUCA_GPUCODE
116+
if (mSeedingLayerMask.count() < constants::ClustersPerCell) {
117+
LOGP(fatal, "Tracking topology has {} seeding layers, but at least {} are required to build CA cells", mSeedingLayerMask.count(), constants::ClustersPerCell);
118+
}
119+
#endif
113120
for (int fromLayer = 0; fromLayer < mMaxLayers; ++fromLayer) {
121+
if (!mSeedingLayerMask.has(fromLayer)) {
122+
continue;
123+
}
114124
for (int toLayer = fromLayer + 1; toLayer < mMaxLayers; ++toLayer) {
115-
if (Mask::skipped(fromLayer, toLayer).isAllowedHoleMask(mMaxHoles, mHoleLayerMask)) {
125+
if (mSeedingLayerMask.has(toLayer) && isAllowedSeedingLink(fromLayer, toLayer)) {
116126
mLinks[mNLinks++] = LayerLink{static_cast<Id>(fromLayer), static_cast<Id>(toLayer)};
117127
}
118128
}
@@ -126,7 +136,7 @@ class TrackingTopology
126136
continue;
127137
}
128138
const Mask hitMask{first.fromLayer, first.toLayer, second.toLayer};
129-
if (hitMask.isAllowed(mMaxHoles, mHoleLayerMask)) {
139+
if ((hitMask.holeMask() & mSeedingLayerMask).isAllowedHoleMask(mMaxHoles, mHoleLayerMask)) {
130140
mCells[mNCells++] = CellTopology{firstId, secondId, hitMask};
131141
}
132142
}
@@ -141,6 +151,7 @@ class TrackingTopology
141151
mCells.data(),
142152
mCellsByFirstLinkIndex.data(),
143153
mCellsByFirstLink.data(),
154+
mSeedingLayerMask,
144155
mNLinks,
145156
mNCells,
146157
mNCellsByFirstLink};
@@ -155,6 +166,7 @@ class TrackingTopology
155166
deviceCells,
156167
deviceCellsByFirstLinkIndex,
157168
deviceCellsByFirstLink,
169+
mSeedingLayerMask,
158170
mNLinks,
159171
mNCells,
160172
mNCellsByFirstLink};
@@ -202,9 +214,15 @@ class TrackingTopology
202214
mNCellsByFirstLink = offset;
203215
}
204216

217+
bool isAllowedSeedingLink(int fromLayer, int toLayer) const noexcept
218+
{
219+
return (Mask::skipped(fromLayer, toLayer) & mSeedingLayerMask).isAllowedHoleMask(mMaxHoles, mHoleLayerMask);
220+
}
221+
205222
int mMaxLayers{0};
206223
int mMaxHoles{0};
207224
Mask mHoleLayerMask{0};
225+
Mask mSeedingLayerMask{0};
208226
Id mNLinks{0};
209227
Id mNCells{0};
210228
Id mNCellsByFirstLink{0};

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ std::string TrackingParameters::asString() const
5959
if (MaxHoles) {
6060
str += std::format(" MaxHoles:{} HoleMask:{}", MaxHoles, HoleLayerMask.asString());
6161
}
62+
if (!InactiveLayerMask.empty()) {
63+
str += std::format(" InactiveMask:{}", InactiveLayerMask.asString());
64+
}
65+
if (!SeedingLayers.empty()) {
66+
str += std::format(" SeedingLayers:{}", SeedingLayers.asString());
67+
}
6268
if (PassFlags[IterationStep::TrackFollowerTop] || PassFlags[IterationStep::TrackFollowerBot]) {
6369
const bool top = PassFlags[IterationStep::TrackFollowerTop], bot = PassFlags[IterationStep::TrackFollowerBot];
6470
str += std::format(" TrackFollower:{} NSigmaZ/Phi:{:.2f}/{:.2f}",

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,16 +249,25 @@ void TimeFrame<NLayers>::initVertexingTopology(const TrackingParameters& trkPara
249249
template <int NLayers>
250250
void TimeFrame<NLayers>::initDefaultTrackingTopology(const TrackingParameters& trkParam, const int maxLayers)
251251
{
252-
mDefaultTrackingTopology.init(maxLayers, trkParam.MaxHoles, trkParam.HoleLayerMask);
252+
if (maxLayers < trkParam.NLayers) {
253+
LOGP(fatal, "Default tracking topology limited to {} layers, but the tracking parameters expect {}", maxLayers, trkParam.NLayers);
254+
}
255+
mDefaultTrackingTopology.init(trkParam.NLayers, trkParam.MaxHoles, trkParam.HoleLayerMask, trkParam.getSeedingLayerMask());
253256
}
254257

255258
template <int NLayers>
256259
void TimeFrame<NLayers>::initTrackerTopologies(gsl::span<const TrackingParameters> trkParams, const int maxLayers)
257260
{
258261
mTrackerTopologies.resize(trkParams.size());
259262
for (size_t iteration = 0; iteration < trkParams.size(); ++iteration) {
260-
const int iterationMaxLayers = std::min(maxLayers, trkParams[iteration].NLayers);
261-
mTrackerTopologies[iteration].init(iterationMaxLayers, trkParams[iteration].MaxHoles, trkParams[iteration].HoleLayerMask);
263+
if (maxLayers < trkParams[iteration].NLayers) {
264+
LOGP(fatal, "Iteration {}: tracking topology limited to {} layers, but the tracking parameters expect {}", iteration, maxLayers, trkParams[iteration].NLayers);
265+
}
266+
const int nActiveLayers = trkParams[iteration].getActiveLayerMask().count();
267+
if (trkParams[iteration].MinTrackLength > nActiveLayers) {
268+
LOGP(fatal, "Iteration {}: MinTrackLength {} cannot be satisfied with {} active layers", iteration, trkParams[iteration].MinTrackLength, nActiveLayers);
269+
}
270+
mTrackerTopologies[iteration].init(trkParams[iteration].NLayers, trkParams[iteration].MaxHoles, trkParams[iteration].HoleLayerMask, trkParams[iteration].getSeedingLayerMask());
262271
}
263272
}
264273

0 commit comments

Comments
 (0)