12#define BOOST_TEST_MODULE ITSMFT ComputeLayerTracklets orchestration
13#define BOOST_TEST_MAIN
14#define BOOST_TEST_DYN_LINK
25#include <boost/test/unit_test.hpp>
27#include <oneapi/tbb/task_arena.h>
45#include "MFTTracking/Constants.h"
57constexpr float Bz = 0.5f;
58constexpr std::array<unsigned char, 3> OnePixelPattern{1, 1, 0x80};
66std::vector<LayerId> identitySurfaces(uint16_t nLayers)
68 std::vector<LayerId> mapping;
69 mapping.reserve(nLayers);
70 for (uint16_t
i = 0;
i < nLayers; ++
i) {
78 std::vector<SurfaceDescriptor> surfaces;
79 surfaces.reserve(nLayers);
80 for (uint16_t
i = 0;
i < nLayers; ++
i) {
83 surfaces.back().referenceCoordinate =
kind == SurfaceKind::Disk
85 : 3.f +
static_cast<float>(
i);
88 surfaces.back().material.xOverX0 = xOverX0;
94class PrescribedDecoder
98 : mDetector{detector}, mKind{
kind}, mClusters{std::move(
clusters)}
104 gsl::span<const unsigned char>::iterator& patterns,
106 uint32_t externalIndex)
const
110 if (externalIndex >= mClusters.size()) {
113 auto decoded = mClusters[externalIndex];
114 decoded.
nPixels = clusterData.nPixels;
122 std::vector<DecodedCluster> mClusters;
125struct TrackletSnapshot {
130 bool nonparticipatingEdgesEmpty{
false};
136 std::vector<int> allEdgeFromLayer;
137 std::vector<int> allEdgeToLayer;
138 std::vector<std::vector<Tracklet>> allTracklets;
139 std::vector<std::vector<int>> allLookups;
142template <
int NLayers>
146 std::vector<DecodedCluster> decoded,
151 auto pool = std::make_shared<BoundedMemoryResource>();
155 std::shared_ptr<tbb::task_arena> arena;
156 std::vector<ReferenceTrackingParameters>
params(1);
157 resetReferenceTrackingParameters(
params[0], detector);
158 params[0].UseDiamond =
true;
159 params[0].CreateArtefactLabels =
false;
160 params[0].PassFlags.reset();
161 params[0].PassFlags.set(IterationStep::FirstPass, IterationStep::RebuildClusterLUT);
162 if (customizeParams) {
163 customizeParams(
params[0]);
169 const auto orderedSurfaces = identitySurfaces(
static_cast<uint16_t
>(NLayers));
170 const auto catalog = makeCatalog(
static_cast<uint16_t
>(NLayers), detector,
kind);
171 const SurfaceCatalogView catalogView{catalog.data(),
static_cast<uint32_t
>(catalog.size())};
173 configuration.
catalog = catalogView;
177 BOOST_REQUIRE(tracker.
initialize(frame, configuration));
181 std::vector<CompClusterExt> compactClusters;
182 std::vector<unsigned char> patterns;
183 compactClusters.reserve(decoded.size());
184 patterns.reserve(decoded.size() * OnePixelPattern.size());
185 for (
const auto& cluster : decoded) {
187 patterns.insert(patterns.end(), OnePixelPattern.begin(), OnePixelPattern.end());
189 const std::vector<ROFRecord> rofs{
ROFRecord{{100, 5}, 0, 0,
static_cast<int>(compactClusters.size())}};
190 PrescribedDecoder decoder{detector,
kind, std::move(decoded)};
192 compactClusters, patterns, rofs, &dict(),
nullptr, detector,
193 gsl::span<const LayerId>{orderedSurfaces}, layout.getSurfaceCatalog()));
197 layerTiming.mROFLength = 40;
200 rofTable.defineLayer(
layer, layerTiming);
211 vtxTable.defineLayer(
layer, layerTiming);
221 std::array<gsl::span<const GlobalMeasurement>,
MaxLayoutSurfaces> measurementSpans;
223 BOOST_CHECK(view.layerGlobalMeasurements.data() == measurementSpans.data());
224 const auto layoutView = view.topology;
228 const auto preparedTopology = layoutView;
229 const auto& msAngles =
tf.getEdgeMSAngles();
230 const auto& phiCuts =
tf.getEdgePhiCuts();
231 BOOST_REQUIRE_EQUAL(msAngles.size(),
static_cast<size_t>(preparedTopology.nEdges));
232 BOOST_REQUIRE_EQUAL(phiCuts.size(),
static_cast<size_t>(preparedTopology.nEdges));
233 for (
int id = 0;
id < preparedTopology.nEdges; ++
id) {
239 const auto topology = layoutView;
241 for (
int id = 0;
id < topology.nEdges; ++
id) {
242 const auto& edge = topology.getEdge(
EdgeId{
static_cast<uint16_t
>(
id)});
243 if (edge.from.value() == 0 && edge.to.value() == 1) {
248 BOOST_REQUIRE_GE(edgeId, 0);
257 const auto&
lookup =
tf.getTrackletsLookupTable()[edgeId];
259 result.nonparticipatingEdgesEmpty =
true;
260 for (
int id = 0;
id < topology.nEdges; ++
id) {
261 if (
id != edgeId && !
tf.getTracklets()[
id].empty()) {
262 result.nonparticipatingEdgesEmpty =
false;
270 for (
int id = 0;
id < topology.nEdges; ++
id) {
271 const auto& edge = topology.getEdge(
EdgeId{
static_cast<uint16_t
>(
id)});
272 result.allEdgeFromLayer.push_back(edge.from.value());
273 result.allEdgeToLayer.push_back(edge.to.value());
274 const auto& idTracklets =
tf.getTracklets()[
id];
275 result.allTracklets.emplace_back(idTracklets.begin(), idTracklets.end());
276 const auto& idLookup =
tf.getTrackletsLookupTable()[
id];
277 result.allLookups.emplace_back(idLookup.begin(), idLookup.end());
282void checkSame(
const TrackletSnapshot& serial,
const TrackletSnapshot&
parallel)
285 BOOST_REQUIRE_EQUAL(serial.tracklets.size(),
parallel.tracklets.size());
286 BOOST_CHECK_EQUAL_COLLECTIONS(serial.lookup.begin(), serial.lookup.end(),
parallel.lookup.begin(),
parallel.lookup.end());
287 for (
size_t i = 0;
i < serial.tracklets.size(); ++
i) {
292 BOOST_CHECK_EQUAL(serial.tracklets[
i].getTimeStamp().getTimeStampError(),
parallel.tracklets[
i].getTimeStamp().getTimeStampError());
296void checkExactTracklet(
const TrackletSnapshot& snapshot,
float expectedTanLambda,
float expectedPhi)
298 BOOST_REQUIRE_EQUAL(snapshot.tracklets.size(), 1u);
299 const auto& tracklet = snapshot.tracklets.front();
304 BOOST_CHECK_EQUAL(tracklet.getTimeStamp().getTimeStamp(), snapshot.expectedTimestamp.getTimeStamp());
305 BOOST_CHECK_EQUAL(tracklet.getTimeStamp().getTimeStampError(), snapshot.expectedTimestamp.getTimeStampError());
306 const std::vector<int> expectedLookup{0, 1};
307 BOOST_CHECK_EQUAL_COLLECTIONS(snapshot.lookup.begin(), snapshot.lookup.end(), expectedLookup.begin(), expectedLookup.end());
314 cluster.
global = {radius, 0.f,
z};
315 cluster.cylinderFrame = {radius, 0.f,
z, 0.f};
316 cluster.rowColumnCovariance = {1.e-4f, 0.f, 1.e-4f};
317 cluster.layer =
layer;
325 cluster.rowColumnCovariance = {1.e-2f, 0.f, 1.e-2f};
326 cluster.layer =
layer;
334 const std::vector<DecodedCluster>
clusters{
335 cylinderCluster(3.f, 0.3f, 0),
336 cylinderCluster(4.f, 0.4f, 1)};
337 const auto serial = runFixture<ITSNLayers>(o2::detectors::DetID::ITS, SurfaceKind::Cylinder,
338 SurfaceKind::Cylinder,
clusters, 1);
339 const auto parallel = runFixture<ITSNLayers>(o2::detectors::DetID::ITS, SurfaceKind::Cylinder,
340 SurfaceKind::Cylinder,
clusters, 4);
341 checkExactTracklet(serial, (0.3f - 0.4f) / (3.f - 4.f), o2::gpu::CAMath::ATan2(0.f, -1.f));
342 checkExactTracklet(
parallel, (0.3f - 0.4f) / (3.f - 4.f), o2::gpu::CAMath::ATan2(0.f, -1.f));
350 for (
const float sign : {-1.f, 1.f}) {
351 std::vector<DecodedCluster>
clusters;
353 const float x = 3.f +
layer;
354 const float z = sign * 0.25f * (
layer + 1);
355 auto cluster = cylinderCluster(
x,
z,
layer);
356 cluster.global.y = 1.f;
357 cluster.cylinderFrame.u = 1.f;
364 const auto serial = runFixture<ITSNLayers>(o2::detectors::DetID::ITS, SurfaceKind::Cylinder,
365 SurfaceKind::Cylinder,
clusters, 1, widenSearch);
366 const auto parallel = runFixture<ITSNLayers>(o2::detectors::DetID::ITS, SurfaceKind::Cylinder,
367 SurfaceKind::Cylinder,
clusters, 4, widenSearch);
368 const float expectedPhi = o2::gpu::CAMath::ATan2(0.f, -1.f);
369 checkExactTracklet(serial, sign * 0.25f, expectedPhi);
370 checkExactTracklet(
parallel, sign * 0.25f, expectedPhi);
377 const float fromZ =
kMFTSurfaces[0].referenceCoordinate;
380 const std::vector<DecodedCluster>
clusters{
381 diskCluster(1.f, 0.5f, fromZ, 0),
382 diskCluster(1.f, -0.5f, toZ, 1)};
387 const auto serial = runFixture<MFTNLayers>(o2::detectors::DetID::MFT, SurfaceKind::Disk,
388 SurfaceKind::Disk,
clusters, 1, widenSearch);
389 const auto parallel = runFixture<MFTNLayers>(o2::detectors::DetID::MFT, SurfaceKind::Disk,
390 SurfaceKind::Disk,
clusters, 4, widenSearch);
391 const float expectedPhi = o2::gpu::CAMath::ATan2(1.f, 0.f);
392 checkExactTracklet(serial, toZ - fromZ, expectedPhi);
393 checkExactTracklet(
parallel, toZ - fromZ, expectedPhi);
399 const float fromZ =
kMFTSurfaces[0].referenceCoordinate;
401 const std::vector<DecodedCluster>
clusters{
402 diskCluster(1.f, 0.5f, fromZ, 0),
403 diskCluster(1.f, 0.5f, toZ, 1)};
405 const auto serial = runFixture<MFTNLayers>(o2::detectors::DetID::MFT, SurfaceKind::Disk,
406 SurfaceKind::Disk,
clusters, 1, widenSearch);
407 const auto parallel = runFixture<MFTNLayers>(o2::detectors::DetID::MFT, SurfaceKind::Disk,
408 SurfaceKind::Disk,
clusters, 4, widenSearch);
419 auto pool = std::make_shared<BoundedMemoryResource>();
423 std::shared_ptr<tbb::task_arena> arena;
424 std::vector<ReferenceTrackingParameters>
params(1);
425 resetReferenceTrackingParameters(
params[0], o2::detectors::DetID::ITS);
426 params[0].PassFlags.reset();
427 params[0].PassFlags.set(IterationStep::FirstPass, IterationStep::RebuildClusterLUT);
432 const auto orderedSurfaces = identitySurfaces(
static_cast<uint16_t
>(
ITSNLayers));
433 const auto catalog = makeCatalog(
static_cast<uint16_t
>(
ITSNLayers), o2::detectors::DetID::ITS, SurfaceKind::Cylinder);
434 const SurfaceCatalogView catalogView{catalog.data(),
static_cast<uint32_t
>(catalog.size())};
436 configuration.
catalog = catalogView;
439 BOOST_REQUIRE(tracker.
initialize(frame, configuration));
443 BOOST_REQUIRE(topologyBuild.ok());
444 const auto layoutView = topologyBuild.topology->getView(layout.getSurfaceCatalog());
450 const std::vector<DecodedCluster> decoded{cylinderCluster(3.f, 0.3f, 0), cylinderCluster(3.1f, 0.31f, 0),
451 cylinderCluster(4.f, 0.4f, 1)};
452 std::vector<CompClusterExt> compactClusters;
453 std::vector<unsigned char> patterns;
454 compactClusters.reserve(decoded.size());
455 patterns.reserve(decoded.size() * OnePixelPattern.size());
456 for (
const auto& cluster : decoded) {
458 patterns.insert(patterns.end(), OnePixelPattern.begin(), OnePixelPattern.end());
460 const std::vector<ROFRecord> rofs{
ROFRecord{{100, 5}, 0, 0,
static_cast<int>(compactClusters.size())}};
461 PrescribedDecoder decoder{o2::detectors::DetID::ITS, SurfaceKind::Cylinder, decoded};
463 compactClusters, patterns, rofs, &dict(),
nullptr, o2::detectors::DetID::ITS,
464 gsl::span<const LayerId>{orderedSurfaces}, layout.getSurfaceCatalog()));
466 BOOST_REQUIRE_EQUAL(layer0.size(), 2u);
467 layer0[1].clusterId = layer0[0].clusterId;
471 layerTiming.mROFLength = 40;
474 rofTable.defineLayer(
layer, layerTiming);
479 vtxTable.defineLayer(
layer, layerTiming);
489 std::array<gsl::span<const GlobalMeasurement>,
MaxLayoutSurfaces> measurementSpans;
492 const auto topology = layoutView;
493 const auto& msAngles =
tf.getEdgeMSAngles();
494 const auto& phiCuts =
tf.getEdgePhiCuts();
495 BOOST_REQUIRE_EQUAL(msAngles.size(),
static_cast<size_t>(topology.nEdges));
496 BOOST_REQUIRE_EQUAL(phiCuts.size(),
static_cast<size_t>(topology.nEdges));
497 for (
int id = 0;
id < topology.nEdges; ++
id) {
517 const std::vector<DecodedCluster>
clusters{
518 cylinderCluster(3.f, 0.3f, 0),
519 cylinderCluster(4.f, 0.4f, 1),
520 cylinderCluster(5.f, 0.5f, 2),
521 cylinderCluster(6.f, 0.6f, 3)};
522 const auto snapshot = runFixture<ITSNLayers>(o2::detectors::DetID::ITS, SurfaceKind::Cylinder,
523 SurfaceKind::Cylinder,
clusters, 1);
529 constexpr std::array<float, 4> radii{3.f, 4.f, 5.f, 6.f};
530 constexpr std::array<float, 4> zs{0.3f, 0.4f, 0.5f, 0.6f};
531 const float expectedPhi = o2::gpu::CAMath::ATan2(0.f, -1.f);
532 const std::vector<int> expectedLookup{0, 1};
534 BOOST_REQUIRE_EQUAL(snapshot.allEdgeFromLayer.size(), snapshot.allTracklets.size());
535 BOOST_REQUIRE_EQUAL(snapshot.allEdgeFromLayer.size(), snapshot.allLookups.size());
536 bool sawEdge01 =
false, sawEdge12 =
false, sawEdge23 =
false;
537 for (
size_t id = 0;
id < snapshot.allEdgeFromLayer.size(); ++
id) {
538 const int from = snapshot.allEdgeFromLayer[
id];
539 const int to = snapshot.allEdgeToLayer[
id];
540 const bool participates = (from == 0 && to == 1) || (from == 1 && to == 2) || (from == 2 && to == 3);
542 BOOST_REQUIRE_EQUAL(snapshot.allTracklets[
id].size(), 1u);
543 const auto& tracklet = snapshot.allTracklets[
id].front();
546 const float expectedTanLambda = (zs[from] - zs[to]) / (radii[from] - radii[to]);
549 BOOST_CHECK_EQUAL_COLLECTIONS(snapshot.allLookups[
id].begin(), snapshot.allLookups[
id].end(), expectedLookup.begin(), expectedLookup.end());
550 sawEdge01 |= (from == 0 && to == 1);
551 sawEdge12 |= (from == 1 && to == 2);
552 sawEdge23 |= (from == 2 && to == 3);
572 const std::vector<DecodedCluster>
clusters{
573 cylinderCluster(3.f, 0.3f, 0),
574 cylinderCluster(5.f, 0.5f, 2)};
575 const auto snapshot = runFixture<ITSNLayers>(
576 o2::detectors::DetID::ITS, SurfaceKind::Cylinder, SurfaceKind::Cylinder,
clusters, 1,
580 LayerMask{
static_cast<uint16_t
>(1u << 1)});
582 const float expectedTanLambda = (0.3f - 0.5f) / (3.f - 5.f);
583 const float expectedPhi = o2::gpu::CAMath::ATan2(0.f, -1.f);
584 bool sawHoleEdge =
false;
585 BOOST_REQUIRE_EQUAL(snapshot.allEdgeFromLayer.size(), snapshot.allTracklets.size());
586 for (
size_t id = 0;
id < snapshot.allEdgeFromLayer.size(); ++
id) {
587 const int from = snapshot.allEdgeFromLayer[
id];
588 const int to = snapshot.allEdgeToLayer[
id];
589 if (from == 0 && to == 2) {
591 BOOST_REQUIRE_EQUAL(snapshot.allTracklets[
id].size(), 1u);
592 const auto& tracklet = snapshot.allTracklets[
id].front();
595 const std::vector<int> expectedLookup{0, 1};
596 BOOST_CHECK_EQUAL_COLLECTIONS(snapshot.allLookups[
id].begin(), snapshot.allLookups[
id].end(), expectedLookup.begin(), expectedLookup.end());
606 const auto surfaces = makeCatalog(
static_cast<uint16_t
>(
ITSNLayers), o2::detectors::DetID::ITS, SurfaceKind::Cylinder);
608 BOOST_REQUIRE(layout.valid());
609 BOOST_REQUIRE_EQUAL(layout.size(),
static_cast<std::size_t
>(
ITSNLayers));
610 for (uint16_t position = 0; position <
ITSNLayers; ++position) {
617 const auto nCylinders =
static_cast<uint16_t
>(
ITSNLayers);
618 const auto nDisks =
static_cast<uint16_t
>(
MFTNLayers);
619 auto surfaces = makeCatalog(nCylinders, o2::detectors::DetID::ITS, SurfaceKind::Cylinder);
620 auto disks = makeCatalog(nDisks, o2::detectors::DetID::MFT, SurfaceKind::Disk);
621 surfaces.insert(surfaces.end(), disks.begin(), disks.end());
622 const std::vector<uint16_t> componentOffsets = {0, nCylinders};
625 parameters.
NLayers =
static_cast<int>(layout.size());
627 BOOST_REQUIRE(
result.ok());
Definition of the ITSMFT compact cluster.
uint8_t lookup(const char input) noexcept
Shared CA tracking configuration for ITS and MFT.
Passive common TimeFrame owner.
Runtime-plan-owned, detector-neutral CA workspace.
int ID
Detector identifiers: continuous, starting from 0.
static constexpr unsigned short InvalidPatternID
void setNThreads(int n, std::shared_ptr< tbb::task_arena > &arena)
bool initialize(TimeFrame &frame, const TrackerInitialization &configuration)
Shared CA tracker traits: same ITS-style tracklet/cell/road logic; MFT uses x-y LUT and forward refit...
GLenum const GLfloat * params
GLenum GLuint GLint GLint layer
GLdouble GLdouble GLdouble z
WorkflowSpec parallel(DataProcessorSpec original, size_t maxIndex, std::function< void(DataProcessorSpec &, size_t id)> amendCallback)
ClusterData< T > extractClusterData(const CompClusterExt &c, gsl::span< const unsigned char >::iterator &patterns, const TopologyDictionary *dict)
TrackingPlan makeTrackingPlan(const TrackingParameters ¶meters)
constexpr std::array< SurfaceDescriptor, MFTNLayers > kMFTSurfaces
constexpr int MFTNLayers
MFT CA half-disk layer count.
constexpr std::array< SurfaceDescriptor, ITSNLayers > kITSSurfaces
constexpr int ITSNLayers
ITS CA layer count.
constexpr uint32_t MaxLayoutSurfaces
TraversalTopologyBuildResult deriveTraversalTopology(const DetectorConfiguration &layout, const o2::itsmft::IterationParameters ¶meters)
BOOST_AUTO_TEST_CASE(Cluster_messageable)
constexpr std::array< Float_t, LayersNumber > LayerZCoordinate()
std::unique_ptr< GPUReconstructionTimeframe > tf
const DetectorConfiguration & getDetectorConfiguration() const noexcept
TimeFrameScratch & getScratch()
void setROFViews(RuntimeROFViews views) noexcept
gsl::span< const GlobalMeasurement > getGlobalMeasurements(LayerId surface) const
const RuntimeROFOverlapView & getROFOverlapView() const noexcept
SurfaceCatalogView catalog
std::shared_ptr< BoundedMemoryResource > memoryPool
static IterationContext prepare(Tracker &tracker, TimeFrame &frame, int iteration, std::array< gsl::span< const GlobalMeasurement >, MaxLayoutSurfaces > &measurementSpans)
static void computeTracklets(TrackerTraits &traits, IterationContext &view, int vertex)
coder decode(ctfImage, triggersD, clustersD)
std::vector< Cluster > clusters
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())
std::vector< Tracklet64 > tracklets