Project
Loading...
Searching...
No Matches
TrackingTopology.h
Go to the documentation of this file.
1// Copyright 2019-2026 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#ifndef TRACKINGITSU_INCLUDE_TRACKINGTOPOLOGY_H_
13#define TRACKINGITSU_INCLUDE_TRACKINGTOPOLOGY_H_
14
15#include <array>
16#include <cstdint>
17#include <limits>
18#include <type_traits>
19
20#ifndef GPUCA_GPUCODE
21#include <fmt/format.h>
22#include <string>
23#include "Framework/Logger.h"
24#endif
25
27#include "GPUCommonDef.h"
28#include "GPUCommonMath.h"
30
31namespace o2::its
32{
33
34template <int NLayers>
36{
37 public:
38 static constexpr int MaxLinks = (NLayers * (NLayers - 1)) / 2;
39 static constexpr int MaxCells = (NLayers * (NLayers - 1) * (NLayers - 2)) / 6;
40 using Id = std::conditional_t<MaxCells <= std::numeric_limits<uint8_t>::max(), uint8_t, uint16_t>;
41 using Mask = LayerMask;
43 static_assert(NLayers < std::numeric_limits<Id>::max());
44 static_assert(MaxLinks <= std::numeric_limits<Id>::max());
45 static_assert(MaxCells <= std::numeric_limits<Id>::max());
46
47 // Describes from which layer to which layer the look-up happens
48 struct LayerLink {
51 };
52 static_assert(std::is_standard_layout_v<LayerLink>);
53 static_assert(std::is_trivially_copyable_v<LayerLink>);
54 static_assert(sizeof(LayerLink) == (2 * sizeof(Id)));
55
56 // Describes from which LayerLink a tracklet is allowed to originate
57 // and with which LayerLink this can be combined additionally the hitMasked is cached
63 static_assert(std::is_standard_layout_v<CellTopology>);
64 static_assert(std::is_trivially_copyable_v<CellTopology>);
65 static_assert(sizeof(CellTopology) == (2 * sizeof(Id)) + sizeof(Mask));
66
67 // GPU ready view of the underlying LUTs
68 struct View {
69 const LayerLink* links{nullptr};
70 const CellTopology* cells{nullptr};
72 const Id* cellsByFirstLink{nullptr};
73 const Id* maxCellLevel{nullptr};
78
79 GPUhdi() const LayerLink& getLink(Id id) const { return links[id]; }
80 GPUhdi() const CellTopology& getCell(Id id) const { return cells[id]; }
81 GPUhdi() Range getCellsStartingWithLink(Id linkId) const { return cellsByFirstLinkIndex[linkId]; }
82 GPUhdi() Id getMaxCellLevel(Id id) const { return maxCellLevel[id]; }
83
84#ifndef GPUCA_GPUCODE
85 std::string asString() const
86 {
87 std::string out = fmt::format("TrackingTopology: links={} cells={} seedingLayers={}", nLinks, nCells, seedingLayerMask.asString());
88 out += "\n links:";
89 for (Id linkId = 0; linkId < nLinks; ++linkId) {
90 const auto& t = links[linkId];
91 out += fmt::format("\n {}: {} -> {}", linkId, t.fromLayer, t.toLayer);
92 }
93 out += "\n cells:";
94 for (Id cellId = 0; cellId < nCells; ++cellId) {
95 const auto& c = cells[cellId];
96 const auto& first = links[c.firstLink];
97 const auto& second = links[c.secondLink];
98 out += fmt::format("\n {}: {} -> {} -> {} hitMask={} links=({}, {}) maxLevel={}", cellId, first.fromLayer, first.toLayer, second.toLayer, c.hitLayerMask.asString(), c.firstLink, c.secondLink, maxCellLevel != nullptr ? int(maxCellLevel[cellId]) : -1);
99 }
100 return out;
101 }
102
103 void print() const
104 {
105 LOGP(info, "{}", asString());
106 }
107#endif
108 };
109
110 void init(int maxLayers, int maxHoles, Mask holeLayerMask, Mask seedingLayerMask = 0)
111 {
112 clear();
113 mMaxLayers = o2::gpu::CAMath::Max(0, o2::gpu::CAMath::Min(maxLayers, NLayers));
114 mMaxHoles = o2::gpu::CAMath::Max(maxHoles, 0);
115 mHoleLayerMask = holeLayerMask;
116 mSeedingLayerMask = seedingLayerMask.empty() ? Mask::span(0, mMaxLayers - 1) : (seedingLayerMask & Mask::span(0, mMaxLayers - 1));
117#ifndef GPUCA_GPUCODE
118 if (mSeedingLayerMask.count() < constants::ClustersPerCell) {
119 LOGP(fatal, "Tracking topology has {} seeding layers, but at least {} are required to build CA cells", mSeedingLayerMask.count(), constants::ClustersPerCell);
120 }
121#endif
122 for (int fromLayer = 0; fromLayer < mMaxLayers; ++fromLayer) {
123 if (!mSeedingLayerMask.has(fromLayer)) {
124 continue;
125 }
126 for (int toLayer = fromLayer + 1; toLayer < mMaxLayers; ++toLayer) {
127 if (mSeedingLayerMask.has(toLayer) && isAllowedSeedingLink(fromLayer, toLayer)) {
128 mLinks[mNLinks++] = LayerLink{static_cast<Id>(fromLayer), static_cast<Id>(toLayer)};
129 }
130 }
131 }
132
133 for (Id firstId = 0; firstId < mNLinks; ++firstId) {
134 const auto& first = mLinks[firstId];
135 for (Id secondId = 0; secondId < mNLinks; ++secondId) {
136 const auto& second = mLinks[secondId];
137 if (first.toLayer != second.fromLayer) {
138 continue;
139 }
140 const Mask hitMask{first.fromLayer, first.toLayer, second.toLayer};
141 if ((hitMask.holeMask() & mSeedingLayerMask).isAllowedHoleMask(mMaxHoles, mHoleLayerMask)) {
142 mCells[mNCells++] = CellTopology{firstId, secondId, hitMask};
143 }
144 }
145 }
146
147 fillCellsByLink();
148 fillMaxCellLevels();
149 }
150
151 View getView() const
152 {
153 return View{mLinks.data(),
154 mCells.data(),
155 mCellsByFirstLinkIndex.data(),
156 mCellsByFirstLink.data(),
157 mMaxCellLevel.data(),
158 mSeedingLayerMask,
159 mNLinks,
160 mNCells,
161 mNCellsByFirstLink};
162 }
163
164 View getDeviceView(const LayerLink* deviceLinks,
165 const CellTopology* deviceCells,
166 const Range* deviceCellsByFirstLinkIndex,
167 const Id* deviceCellsByFirstLink) const
168 {
169 return View{deviceLinks,
170 deviceCells,
171 deviceCellsByFirstLinkIndex,
172 deviceCellsByFirstLink,
173 nullptr,
174 mSeedingLayerMask,
175 mNLinks,
176 mNCells,
177 mNCellsByFirstLink};
178 }
179
180 const auto& getLinks() const noexcept { return mLinks; }
181 const auto& getCells() const noexcept { return mCells; }
182 const auto& getCellsByFirstLinkIndex() const noexcept { return mCellsByFirstLinkIndex; }
183 const auto& getCellsByFirstLink() const noexcept { return mCellsByFirstLink; }
184 const auto& getMaxCellLevels() const noexcept { return mMaxCellLevel; }
185 Id getNLinks() const noexcept { return mNLinks; }
186 Id getNCells() const noexcept { return mNCells; }
187 Id getNCellsByFirstLink() const noexcept { return mNCellsByFirstLink; }
188
189 private:
190 void clear()
191 {
192 mNLinks = 0;
193 mNCells = 0;
194 mNCellsByFirstLink = 0;
195 mLinks.fill({});
196 mCells.fill({});
197 mCellsByFirstLinkIndex.fill(Range{0, 0});
198 mCellsByFirstLink.fill(0);
199 mMaxCellLevel.fill(0);
200 }
201
202 void fillMaxCellLevels()
203 {
204 for (Id cellId = 0; cellId < mNCells; ++cellId) {
205 mMaxCellLevel[cellId] = 1;
206 }
207 for (int outerLayer = 0; outerLayer < mMaxLayers; ++outerLayer) {
208 for (Id cellId = 0; cellId < mNCells; ++cellId) {
209 if (mCells[cellId].hitLayerMask.last() != outerLayer) {
210 continue;
211 }
212 const auto& successors = mCellsByFirstLinkIndex[mCells[cellId].secondLink];
213 for (Id i = 0; i < successors.getEntries(); ++i) {
214 const Id next = mCellsByFirstLink[successors.getFirstEntry() + i];
215 mMaxCellLevel[next] = o2::gpu::CAMath::Max(mMaxCellLevel[next], static_cast<Id>(mMaxCellLevel[cellId] + 1));
216 }
217 }
218 }
219 }
220
221 void fillCellsByLink()
222 {
223 std::array<Id, MaxLinks> counts{};
224 for (Id cellId = 0; cellId < mNCells; ++cellId) {
225 ++counts[mCells[cellId].firstLink];
226 }
227
228 Id offset = 0;
229 for (Id linkId = 0; linkId < mNLinks; ++linkId) {
230 mCellsByFirstLinkIndex[linkId].setFirstEntry(offset);
231 mCellsByFirstLinkIndex[linkId].setEntries(counts[linkId]);
232 offset += counts[linkId];
233 }
234
235 std::array<Id, MaxLinks> cursor{};
236 for (Id cellId = 0; cellId < mNCells; ++cellId) {
237 const Id linkId = mCells[cellId].firstLink;
238 mCellsByFirstLink[mCellsByFirstLinkIndex[linkId].getFirstEntry() + cursor[linkId]++] = cellId;
239 }
240 mNCellsByFirstLink = offset;
241 }
242
243 bool isAllowedSeedingLink(int fromLayer, int toLayer) const noexcept
244 {
245 return (Mask::skipped(fromLayer, toLayer) & mSeedingLayerMask).isAllowedHoleMask(mMaxHoles, mHoleLayerMask);
246 }
247
248 int mMaxLayers{0};
249 int mMaxHoles{0};
250 Mask mHoleLayerMask{0};
251 Mask mSeedingLayerMask{0};
252 Id mNLinks{0};
253 Id mNCells{0};
254 Id mNCellsByFirstLink{0};
255 std::array<LayerLink, MaxLinks> mLinks{};
256 std::array<CellTopology, MaxCells> mCells{};
257 std::array<Range, MaxLinks> mCellsByFirstLinkIndex{};
258 std::array<Id, MaxCells> mCellsByFirstLink{};
259 std::array<Id, MaxCells> mMaxCellLevel{};
260};
261
262} // namespace o2::its
263
264#endif
int32_t i
Class to refer to the 1st entry and N elements of some group in the continuous container.
uint32_t c
Definition RawData.h:2
const auto & getCellsByFirstLinkIndex() const noexcept
View getDeviceView(const LayerLink *deviceLinks, const CellTopology *deviceCells, const Range *deviceCellsByFirstLinkIndex, const Id *deviceCellsByFirstLink) const
const auto & getCells() const noexcept
Id getNCellsByFirstLink() const noexcept
o2::dataformats::RangeReference< Id, Id > Range
static constexpr int MaxCells
const auto & getCellsByFirstLink() const noexcept
Id getNLinks() const noexcept
const auto & getLinks() const noexcept
static constexpr int MaxLinks
void init(int maxLayers, int maxHoles, Mask holeLayerMask, Mask seedingLayerMask=0)
std::conditional_t< MaxCells<=std::numeric_limits< uint8_t >::max(), uint8_t, uint16_t > Id
const auto & getMaxCellLevels() const noexcept
Id getNCells() const noexcept
GLintptr offset
Definition glcorearb.h:660
GLuint id
Definition glcorearb.h:650
constexpr int ClustersPerCell
Definition Constants.h:31
const Id * maxCellLevel
host only, see getDeviceView
GPUhdi() Range getCellsStartingWithLink(Id linkId) const
GPUhdi() const LayerLink &getLink(Id id) const
GPUhdi() Id getMaxCellLevel(Id id) const
GPUhdi() const CellTopology &getCell(Id id) const