@@ -514,12 +514,22 @@ void TrackerTraits<NLayers>::findCellsNeighbours(const int iteration)
514514}
515515
516516template <int NLayers>
517- void TrackerTraits<NLayers>::processNeighbours(int iLayer, int iLevel, const bounded_vector<CellSeedN>& currentCellSeed, const bounded_vector<int >& currentCellId, bounded_vector<CellSeedN>& updatedCellSeeds, bounded_vector<int >& updatedCellsIds)
517+ void TrackerTraits<NLayers>::processNeighbours(int iLayer, int iLevel, const bounded_vector<CellSeedN>& currentCellSeed, const bounded_vector<int >& currentCellId, bounded_vector<CellSeedN>& updatedCellSeeds, bounded_vector<int >& updatedCellsIds, int beginCell, int endCell )
518518{
519- auto propagator = o2::base::Propagator::Instance ();
519+ updatedCellSeeds.clear ();
520+ updatedCellsIds.clear ();
521+
522+ const int totalCells = static_cast <int >(currentCellSeed.size ());
523+ beginCell = std::clamp (beginCell, 0 , totalCells);
524+ endCell = endCell < 0 ? totalCells : std::clamp (endCell, beginCell, totalCells);
525+ if (beginCell >= endCell) {
526+ return ;
527+ }
520528
529+ auto propagator = o2::base::Propagator::Instance ();
521530 mTaskArena ->execute ([&] {
522- auto forCellNeighbours = [&](auto Tag, int iCell, int offset = 0 ) -> int {
531+ auto forCellNeighbours = [&](auto Tag, int localCell, int offset = 0 ) -> int {
532+ const int iCell = beginCell + localCell;
523533 const auto & currentCell{currentCellSeed[iCell]};
524534
525535 if constexpr (decltype (Tag)::value != PassMode::TwoPassInsert::value) {
@@ -604,15 +614,15 @@ void TrackerTraits<NLayers>::processNeighbours(int iLayer, int iLevel, const bou
604614 return foundSeeds;
605615 };
606616
607- const int nCells = static_cast < int >(currentCellSeed. size ()) ;
617+ const int nCells = endCell - beginCell ;
608618 if (mTaskArena ->max_concurrency () <= 1 ) {
609- for (int iCell {0 }; iCell < nCells; ++iCell ) {
610- forCellNeighbours (PassMode::OnePass{}, iCell );
619+ for (int localCell {0 }; localCell < nCells; ++localCell ) {
620+ forCellNeighbours (PassMode::OnePass{}, localCell );
611621 }
612622 } else {
613623 bounded_vector<int > perCellCount (nCells + 1 , 0 , mMemoryPool .get ());
614- tbb::parallel_for (0 , nCells, [&](const int iCell ) {
615- perCellCount[iCell ] = forCellNeighbours (PassMode::TwoPassCount{}, iCell );
624+ tbb::parallel_for (0 , nCells, [&](const int localCell ) {
625+ perCellCount[localCell ] = forCellNeighbours (PassMode::TwoPassCount{}, localCell );
616626 });
617627
618628 std::exclusive_scan (perCellCount.begin (), perCellCount.end (), perCellCount.begin (), 0 );
@@ -623,12 +633,12 @@ void TrackerTraits<NLayers>::processNeighbours(int iLayer, int iLevel, const bou
623633 updatedCellSeeds.resize (totalNeighbours);
624634 updatedCellsIds.resize (totalNeighbours);
625635
626- tbb::parallel_for (0 , nCells, [&](const int iCell ) {
627- int offset = perCellCount[iCell ];
628- if (offset == perCellCount[iCell + 1 ]) {
636+ tbb::parallel_for (0 , nCells, [&](const int localCell ) {
637+ int offset = perCellCount[localCell ];
638+ if (offset == perCellCount[localCell + 1 ]) {
629639 return ;
630640 }
631- forCellNeighbours (PassMode::TwoPassInsert{}, iCell , offset);
641+ forCellNeighbours (PassMode::TwoPassInsert{}, localCell , offset);
632642 });
633643 }
634644 });
@@ -644,119 +654,157 @@ void TrackerTraits<NLayers>::findRoads(const int iteration)
644654 for (int startLevel{mTrkParams [iteration].CellsPerRoad ()}; startLevel >= mTrkParams [iteration].CellMinimumLevel (); --startLevel) {
645655
646656 auto seedFilter = [&](const auto & seed) {
647- return seed.getQ2Pt () <= 1 .e3 && seed.getChi2 () <= mTrkParams [0 ].MaxChi2NDF * ((startLevel + 2 ) * 2 - 5 );
657+ return seed.getQ2Pt () <= 1 .e3 && seed.getChi2 () <= mTrkParams [iteration ].MaxChi2NDF * ((startLevel + 2 ) * 2 - 5 );
648658 };
649659
650- bounded_vector<CellSeedN> trackSeeds (mMemoryPool .get ());
651- for (int startLayer{mTrkParams [iteration].NeighboursPerRoad ()}; startLayer >= startLevel - 1 ; --startLayer) {
652- if ((mTrkParams [iteration].StartLayerMask & (1 << (startLayer + 2 ))) == 0 ) {
653- continue ;
654- }
655-
656- bounded_vector<int > lastCellId (mMemoryPool .get ()), updatedCellId (mMemoryPool .get ());
657- bounded_vector<CellSeedN> lastCellSeed (mMemoryPool .get ()), updatedCellSeed (mMemoryPool .get ());
658-
659- processNeighbours (startLayer, startLevel, mTimeFrame ->getCells ()[startLayer], lastCellId, updatedCellSeed, updatedCellId);
660-
661- int level = startLevel;
662- for (int iLayer{startLayer - 1 }; iLayer > 0 && level > 2 ; --iLayer) {
663- lastCellSeed.swap (updatedCellSeed);
664- lastCellId.swap (updatedCellId);
665- deepVectorClear (updatedCellSeed); // / tame the memory peaks
666- deepVectorClear (updatedCellId); // / tame the memory peaks
667- processNeighbours (iLayer, --level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId);
668- }
669- deepVectorClear (lastCellId); // / tame the memory peaks
670- deepVectorClear (lastCellSeed); // / tame the memory peaks
671-
672- if (!updatedCellSeed.empty ()) {
673- trackSeeds.reserve (trackSeeds.size () + std::count_if (updatedCellSeed.begin (), updatedCellSeed.end (), seedFilter));
674- std::copy_if (updatedCellSeed.begin (), updatedCellSeed.end (), std::back_inserter (trackSeeds), seedFilter);
675- }
676- }
677-
678- if (trackSeeds.empty ()) {
679- continue ;
680- }
681-
682660 bounded_vector<TrackITSExt> tracks (mMemoryPool .get ());
683- mTaskArena ->execute ([&] {
684- auto forSeed = [&](auto Tag, int iSeed, int offset = 0 ) {
685- TrackITSExt temporaryTrack = seedTrackForRefit (trackSeeds[iSeed]);
686- o2::track::TrackPar linRef{temporaryTrack};
687- bool fitSuccess = fitTrack (temporaryTrack, 0 , mTrkParams [0 ].NLayers , 1 , mTrkParams [0 ].MaxChi2ClusterAttachment , mTrkParams [0 ].MaxChi2NDF , o2::constants::math::VeryBig, 0 , &linRef);
688- if (!fitSuccess) {
689- return 0 ;
690- }
691- temporaryTrack.getParamOut () = temporaryTrack.getParamIn ();
692- linRef = temporaryTrack.getParamOut (); // use refitted track as lin.reference
693- temporaryTrack.resetCovariance ();
694- temporaryTrack.setCov (temporaryTrack.getQ2Pt () * temporaryTrack.getQ2Pt () * temporaryTrack.getCov ()[o2::track::CovLabels::kSigQ2Pt2 ], o2::track::CovLabels::kSigQ2Pt2 );
695- temporaryTrack.setChi2 (0 );
696- fitSuccess = fitTrack (temporaryTrack, mTrkParams [0 ].NLayers - 1 , -1 , -1 , mTrkParams [0 ].MaxChi2ClusterAttachment , mTrkParams [0 ].MaxChi2NDF , 50 .f , 0 , &linRef);
697- if (!fitSuccess || temporaryTrack.getPt () < mTrkParams [iteration].MinPt [mTrkParams [iteration].NLayers - temporaryTrack.getNClusters ()]) {
698- return 0 ;
699- }
700- if (mTrkParams [0 ].RepeatRefitOut ) { // repeat outward refit seeding and linearizing with the stable inward fit result
701- o2::track::TrackParCov saveInw{temporaryTrack};
702- linRef = saveInw; // use refitted track as lin.reference
703- float saveChi2 = temporaryTrack.getChi2 ();
661+ auto fitSeeds = [&](const bounded_vector<CellSeedN>& finalSeeds) {
662+ bounded_vector<TrackITSExt> trackChunk (mMemoryPool .get ());
663+ mTaskArena ->execute ([&] {
664+ auto forSeed = [&](auto Tag, int iSeed, int offset = 0 ) {
665+ if (!seedFilter (finalSeeds[iSeed])) {
666+ return 0 ;
667+ }
668+
669+ TrackITSExt temporaryTrack = seedTrackForRefit (finalSeeds[iSeed]);
670+ o2::track::TrackPar linRef{temporaryTrack};
671+ bool fitSuccess = fitTrack (temporaryTrack, 0 , mTrkParams [0 ].NLayers , 1 , mTrkParams [0 ].MaxChi2ClusterAttachment , mTrkParams [0 ].MaxChi2NDF , o2::constants::math::VeryBig, 0 , &linRef);
672+ if (!fitSuccess) {
673+ return 0 ;
674+ }
675+ temporaryTrack.getParamOut () = temporaryTrack.getParamIn ();
676+ linRef = temporaryTrack.getParamOut (); // use refitted track as lin.reference
704677 temporaryTrack.resetCovariance ();
705678 temporaryTrack.setCov (temporaryTrack.getQ2Pt () * temporaryTrack.getQ2Pt () * temporaryTrack.getCov ()[o2::track::CovLabels::kSigQ2Pt2 ], o2::track::CovLabels::kSigQ2Pt2 );
706679 temporaryTrack.setChi2 (0 );
707- fitSuccess = fitTrack (temporaryTrack, 0 , mTrkParams [0 ].NLayers , 1 , mTrkParams [0 ].MaxChi2ClusterAttachment , mTrkParams [0 ].MaxChi2NDF , o2::constants::math::VeryBig , 0 , &linRef);
708- if (!fitSuccess) {
680+ fitSuccess = fitTrack (temporaryTrack, mTrkParams [0 ].NLayers - 1 , - 1 , - 1 , mTrkParams [0 ].MaxChi2ClusterAttachment , mTrkParams [0 ].MaxChi2NDF , 50 . f , 0 , &linRef);
681+ if (!fitSuccess || temporaryTrack. getPt () < mTrkParams [iteration]. MinPt [ mTrkParams [iteration]. NLayers - temporaryTrack. getNClusters ()] ) {
709682 return 0 ;
710683 }
711- temporaryTrack.getParamOut () = temporaryTrack.getParamIn ();
712- temporaryTrack.getParamIn () = saveInw;
713- temporaryTrack.setChi2 (saveChi2);
714- }
684+ if (mTrkParams [0 ].RepeatRefitOut ) { // repeat outward refit seeding and linearizing with the stable inward fit result
685+ o2::track::TrackParCov saveInw{temporaryTrack};
686+ linRef = saveInw; // use refitted track as lin.reference
687+ float saveChi2 = temporaryTrack.getChi2 ();
688+ temporaryTrack.resetCovariance ();
689+ temporaryTrack.setCov (temporaryTrack.getQ2Pt () * temporaryTrack.getQ2Pt () * temporaryTrack.getCov ()[o2::track::CovLabels::kSigQ2Pt2 ], o2::track::CovLabels::kSigQ2Pt2 );
690+ temporaryTrack.setChi2 (0 );
691+ fitSuccess = fitTrack (temporaryTrack, 0 , mTrkParams [0 ].NLayers , 1 , mTrkParams [0 ].MaxChi2ClusterAttachment , mTrkParams [0 ].MaxChi2NDF , o2::constants::math::VeryBig, 0 , &linRef);
692+ if (!fitSuccess) {
693+ return 0 ;
694+ }
695+ temporaryTrack.getParamOut () = temporaryTrack.getParamIn ();
696+ temporaryTrack.getParamIn () = saveInw;
697+ temporaryTrack.setChi2 (saveChi2);
698+ }
715699
716- if constexpr (decltype (Tag)::value == PassMode::OnePass::value) {
717- tracks.push_back (temporaryTrack);
718- } else if constexpr (decltype (Tag)::value == PassMode::TwoPassCount::value) {
719- // nothing to do
720- } else if constexpr (decltype (Tag)::value == PassMode::TwoPassInsert::value) {
721- tracks[offset] = temporaryTrack;
700+ if constexpr (decltype (Tag)::value == PassMode::OnePass::value) {
701+ trackChunk.push_back (temporaryTrack);
702+ } else if constexpr (decltype (Tag)::value == PassMode::TwoPassCount::value) {
703+ // nothing to do
704+ } else if constexpr (decltype (Tag)::value == PassMode::TwoPassInsert::value) {
705+ trackChunk[offset] = temporaryTrack;
706+ } else {
707+ static_assert (false , " Unknown mode!" );
708+ }
709+ return 1 ;
710+ };
711+
712+ const int nSeeds = static_cast <int >(finalSeeds.size ());
713+ if (mTaskArena ->max_concurrency () <= 1 ) {
714+ for (int iSeed{0 }; iSeed < nSeeds; ++iSeed) {
715+ forSeed (PassMode::OnePass{}, iSeed);
716+ }
722717 } else {
723- static_assert (false , " Unknown mode!" );
724- }
725- return 1 ;
726- };
718+ bounded_vector<int > perSeedCount (nSeeds + 1 , 0 , mMemoryPool .get ());
719+ tbb::parallel_for (0 , nSeeds, [&](const int iSeed) {
720+ perSeedCount[iSeed] = forSeed (PassMode::TwoPassCount{}, iSeed);
721+ });
722+
723+ std::exclusive_scan (perSeedCount.begin (), perSeedCount.end (), perSeedCount.begin (), 0 );
724+ auto totalTracks{perSeedCount.back ()};
725+ if (totalTracks == 0 ) {
726+ return ;
727+ }
728+ trackChunk.resize (totalTracks);
727729
728- const int nSeeds = static_cast <int >(trackSeeds.size ());
729- if (mTaskArena ->max_concurrency () <= 1 ) {
730- for (int iSeed{0 }; iSeed < nSeeds; ++iSeed) {
731- forSeed (PassMode::OnePass{}, iSeed);
730+ tbb::parallel_for (0 , nSeeds, [&](const int iSeed) {
731+ if (perSeedCount[iSeed] == perSeedCount[iSeed + 1 ]) {
732+ return ;
733+ }
734+ forSeed (PassMode::TwoPassInsert{}, iSeed, perSeedCount[iSeed]);
735+ });
732736 }
733- } else {
734- bounded_vector<int > perSeedCount (nSeeds + 1 , 0 , mMemoryPool .get ());
735- tbb::parallel_for (0 , nSeeds, [&](const int iSeed) {
736- perSeedCount[iSeed] = forSeed (PassMode::TwoPassCount{}, iSeed);
737- });
737+ });
738+ if (!trackChunk.empty ()) {
739+ tracks.reserve (tracks.size () + trackChunk.size ());
740+ tracks.insert (tracks.end (), std::make_move_iterator (trackChunk.begin ()), std::make_move_iterator (trackChunk.end ()));
741+ }
742+ };
738743
739- std::exclusive_scan (perSeedCount.begin (), perSeedCount.end (), perSeedCount.begin (), 0 );
740- auto totalTracks{perSeedCount.back ()};
741- if (totalTracks == 0 ) {
742- return ;
743- }
744- tracks.resize (totalTracks);
744+ for (int startLayer{mTrkParams [iteration].NeighboursPerRoad ()}; startLayer >= startLevel - 1 ; --startLayer) {
745+ if ((mTrkParams [iteration].StartLayerMask & (1 << (startLayer + 2 ))) == 0 ) {
746+ continue ;
747+ }
745748
746- tbb::parallel_for (0 , nSeeds, [&](const int iSeed) {
747- if (perSeedCount[iSeed] == perSeedCount[iSeed + 1 ]) {
748- return ;
749+ bounded_vector<int > inputCellIds (mMemoryPool .get ()), outputCellIds (mMemoryPool .get ());
750+ bounded_vector<CellSeedN> inputCellSeeds (mMemoryPool .get ()), outputCellSeeds (mMemoryPool .get ());
751+ const bounded_vector<CellSeedN>* currentSeeds = &mTimeFrame ->getCells ()[startLayer];
752+ const bounded_vector<int >* currentIds = &inputCellIds;
753+ int layer = startLayer;
754+ int level = startLevel;
755+
756+ while (!currentSeeds->empty () && level > 1 ) {
757+ if (!mTrkParams [iteration].PNChunkSize ) {
758+ processNeighbours (layer, level, *currentSeeds, *currentIds, outputCellSeeds, outputCellIds);
759+ if (level == 2 ) {
760+ fitSeeds (outputCellSeeds);
749761 }
750- forSeed (PassMode::TwoPassInsert{}, iSeed, perSeedCount[iSeed]);
751- });
762+ } else {
763+ for (int beginCell{0 }; beginCell < static_cast <int >(currentSeeds->size ()); beginCell += mTrkParams [iteration].PNChunkSize ) {
764+ const int endCell = std::min (beginCell + mTrkParams [iteration].PNChunkSize , static_cast <int >(currentSeeds->size ()));
765+ bounded_vector<CellSeedN> chunkSeeds (mMemoryPool .get ());
766+ bounded_vector<int > chunkIds (mMemoryPool .get ());
767+ processNeighbours (layer, level, *currentSeeds, *currentIds, chunkSeeds, chunkIds, beginCell, endCell);
768+ if (chunkSeeds.empty ()) {
769+ continue ;
770+ }
771+ if (level == 2 ) {
772+ fitSeeds (chunkSeeds);
773+ continue ;
774+ }
775+ outputCellSeeds.reserve (outputCellSeeds.size () + chunkSeeds.size ());
776+ outputCellIds.reserve (outputCellIds.size () + chunkIds.size ());
777+ outputCellSeeds.insert (outputCellSeeds.end (), std::make_move_iterator (chunkSeeds.begin ()), std::make_move_iterator (chunkSeeds.end ()));
778+ outputCellIds.insert (outputCellIds.end (), std::make_move_iterator (chunkIds.begin ()), std::make_move_iterator (chunkIds.end ()));
779+ }
780+ }
781+ if (outputCellSeeds.empty () || level == 2 ) {
782+ break ;
783+ }
784+
785+ --layer;
786+ --level;
787+ inputCellSeeds.swap (outputCellSeeds);
788+ inputCellIds.swap (outputCellIds);
789+ deepVectorClear (outputCellSeeds);
790+ deepVectorClear (outputCellIds);
791+ currentSeeds = &inputCellSeeds;
792+ currentIds = &inputCellIds;
752793 }
794+ }
753795
754- deepVectorClear (trackSeeds);
796+ if (tracks.empty ()) {
797+ continue ;
798+ }
799+
800+ // sort by quality do to disambiguation
801+ mTaskArena ->execute ([&] {
755802 tbb::parallel_sort (tracks.begin (), tracks.end (), [](const auto & a, const auto & b) {
756803 return a.getChi2 () < b.getChi2 ();
757804 });
758805 });
759806
807+ // create final tracks
760808 const float smallestROFHalf = mTimeFrame ->getROFOverlapTableView ().getClockLayer ().mROFLength * 0 .5f ;
761809 for (auto & track : tracks) {
762810 int nShared = 0 ;
0 commit comments