@@ -1724,6 +1724,38 @@ struct HfTrackIndexSkimCreator {
17241724 }
17251725 }
17261726
1727+ // / One track of the collision under study, propagated to that collision's primary vertex.
1728+ // / \tparam TTrackIndex is the iterator type of the track-collision associations
1729+ // / \tparam TTrack is the iterator type of the track table
1730+ template <typename TTrackIndex, typename TTrack>
1731+ struct HfPropagatedProng {
1732+ TTrackIndex trackIndex; // /< track-collision association, carries isSelProng and isIdentifiedPid
1733+ TTrack track; // /< track row
1734+ o2::track::TrackParCov trackParVar; // /< track parameters at the PCA to the primary vertex
1735+ std::array<float , 3 > pVec{}; // /< momentum at the PCA to the primary vertex
1736+ std::array<float , 2 > dcaInfo{}; // /< DCA (xy, z) to the primary vertex
1737+ };
1738+
1739+ // / Fill the per-collision cache of tracks propagated to the collision's primary vertex, so that
1740+ // / each track is propagated once per collision instead of once per pair or triplet.
1741+ // / \param collision is the collision under study
1742+ // / \param trackIndices are the track associations of this collision
1743+ // / \param prongs is the cache to be filled, in the order of trackIndices
1744+ template <typename TTracks, typename TCollision, typename TTrackIndices, typename TProng>
1745+ void fillPropagatedProngCache (TCollision const & collision, TTrackIndices const & trackIndices, std::vector<TProng>& prongs)
1746+ {
1747+ prongs.clear ();
1748+ const auto thisCollId = collision.globalIndex ();
1749+ for (auto trackIndex = trackIndices.begin (); trackIndex != trackIndices.end (); ++trackIndex) {
1750+ const auto track = trackIndex.template track_as <TTracks>();
1751+ auto & prong = prongs.emplace_back (TProng{trackIndex, track, getTrackParCov (track), track.pVector (), {track.dcaXY (), track.dcaZ ()}});
1752+ if (thisCollId != track.collisionId ()) { // this is not the "default" collision for this track, we have to re-propagate it
1753+ o2::base::Propagator::Instance ()->propagateToDCABxByBz ({collision.posX (), collision.posY (), collision.posZ ()}, prong.trackParVar , 2 .f , noMatCorr, &prong.dcaInfo );
1754+ getPxPyPz (prong.trackParVar , prong.pVec );
1755+ }
1756+ }
1757+ }
1758+
17271759 // / Method to perform selections for 2-prong candidates before vertex reconstruction
17281760 // / \param pVecTrack0 is the momentum array of the first daughter track
17291761 // / \param pVecTrack1 is the momentum array of the second daughter track
@@ -2319,6 +2351,12 @@ struct HfTrackIndexSkimCreator {
23192351 }
23202352 */
23212353
2354+ // per-collision caches of the tracks propagated to the primary vertex, declared here so that their capacity is reused
2355+ using TrackIndexIterator = decltype (positiveFor2And3Prongs->sliceByCached (aod::track::collisionId, 0 , cache).begin ());
2356+ using PropagatedProng = HfPropagatedProng<TrackIndexIterator, decltype (tracks.rawIteratorAt (0 ))>;
2357+ std::vector<PropagatedProng> prongsPos{};
2358+ std::vector<PropagatedProng> prongsNeg{};
2359+
23222360 for (const auto & collision : collisions) {
23232361
23242362 // / retrieve PV contributors for the current collision
@@ -2398,39 +2436,36 @@ struct HfTrackIndexSkimCreator {
23982436 std::optional<decltype (positiveSoftPions->sliceByCached (aod::track::collisionId, 0 , cache))> groupedTrackIndicesSoftPionsPos;
23992437 std::optional<decltype (negativeSoftPions->sliceByCached (aod::track::collisionId, 0 , cache))> groupedTrackIndicesSoftPionsNeg;
24002438 int lastFilledD0 = -1 ; // index to be filled in table for D* mesons
2401- for (auto trackIndexPos1 = groupedTrackIndicesPos1.begin (); trackIndexPos1 != groupedTrackIndicesPos1.end (); ++trackIndexPos1) {
2402- const auto trackPos1 = trackIndexPos1.template track_as <TTracks>();
2439+
2440+ // propagate each track to this collision's PV once, instead of once per pair or triplet
2441+ fillPropagatedProngCache<TTracks>(collision, groupedTrackIndicesPos1, prongsPos);
2442+ fillPropagatedProngCache<TTracks>(collision, groupedTrackIndicesNeg1, prongsNeg);
2443+
2444+ for (std::size_t iPos1 = 0 ; iPos1 < prongsPos.size (); ++iPos1) {
2445+ const auto & trackIndexPos1 = prongsPos[iPos1].trackIndex ;
2446+ const auto & trackPos1 = prongsPos[iPos1].track ;
2447+ const auto & trackParVarPos1 = prongsPos[iPos1].trackParVar ;
2448+ const auto & pVecTrackPos1 = prongsPos[iPos1].pVec ;
2449+ const auto & dcaInfoPos1 = prongsPos[iPos1].dcaInfo ;
24032450
24042451 // retrieve the selection flag that corresponds to this collision
24052452 const auto isSelProngPos1 = trackIndexPos1.isSelProng ();
24062453 const bool sel2ProngStatusPos = TESTBIT (isSelProngPos1, CandidateType::Cand2Prong);
24072454 const bool sel3ProngStatusPos1 = TESTBIT (isSelProngPos1, CandidateType::Cand3Prong);
24082455
2409- auto trackParVarPos1 = getTrackParCov (trackPos1);
2410- std::array pVecTrackPos1{trackPos1.pVector ()};
2411- std::array dcaInfoPos1{trackPos1.dcaXY (), trackPos1.dcaZ ()};
2412- if (thisCollId != trackPos1.collisionId ()) { // this is not the "default" collision for this track, we have to re-propagate it
2413- o2::base::Propagator::Instance ()->propagateToDCABxByBz ({collision.posX (), collision.posY (), collision.posZ ()}, trackParVarPos1, 2 .f , noMatCorr, &dcaInfoPos1);
2414- getPxPyPz (trackParVarPos1, pVecTrackPos1);
2415- }
2416-
24172456 // first loop over negative tracks
2418- for (auto trackIndexNeg1 = groupedTrackIndicesNeg1.begin (); trackIndexNeg1 != groupedTrackIndicesNeg1.end (); ++trackIndexNeg1) {
2419- const auto trackNeg1 = trackIndexNeg1.template track_as <TTracks>();
2457+ for (std::size_t iNeg1 = 0 ; iNeg1 < prongsNeg.size (); ++iNeg1) {
2458+ const auto & trackIndexNeg1 = prongsNeg[iNeg1].trackIndex ;
2459+ const auto & trackNeg1 = prongsNeg[iNeg1].track ;
2460+ const auto & trackParVarNeg1 = prongsNeg[iNeg1].trackParVar ;
2461+ const auto & pVecTrackNeg1 = prongsNeg[iNeg1].pVec ;
2462+ const auto & dcaInfoNeg1 = prongsNeg[iNeg1].dcaInfo ;
24202463
24212464 // retrieve the selection flag that corresponds to this collision
24222465 const auto isSelProngNeg1 = trackIndexNeg1.isSelProng ();
24232466 const bool sel2ProngStatusNeg = TESTBIT (isSelProngNeg1, CandidateType::Cand2Prong);
24242467 const bool sel3ProngStatusNeg1 = TESTBIT (isSelProngNeg1, CandidateType::Cand3Prong);
24252468
2426- auto trackParVarNeg1 = getTrackParCov (trackNeg1);
2427- std::array pVecTrackNeg1{trackNeg1.pVector ()};
2428- std::array dcaInfoNeg1{trackNeg1.dcaXY (), trackNeg1.dcaZ ()};
2429- if (thisCollId != trackNeg1.collisionId ()) { // this is not the "default" collision for this track, we have to re-propagate it
2430- o2::base::Propagator::Instance ()->propagateToDCABxByBz ({collision.posX (), collision.posY (), collision.posZ ()}, trackParVarNeg1, 2 .f , noMatCorr, &dcaInfoNeg1);
2431- getPxPyPz (trackParVarNeg1, pVecTrackNeg1);
2432- }
2433-
24342469 uint isSelected2ProngCand = n2ProngBit; // bitmap for checking status of two-prong candidates (1 is true, 0 is rejected)
24352470
24362471 if (config.debug ) {
@@ -2638,7 +2673,8 @@ struct HfTrackIndexSkimCreator {
26382673
26392674 if (config.do3Prong && is2ProngCandidateGoodFor3Prong) { // if 3 prongs are enabled and the first 2 tracks are selected for the 3-prong channels
26402675 // second loop over positive tracks
2641- for (auto trackIndexPos2 = trackIndexPos1 + 1 ; trackIndexPos2 != groupedTrackIndicesPos1.end (); ++trackIndexPos2) {
2676+ for (std::size_t iPos2 = iPos1 + 1 ; iPos2 < prongsPos.size (); ++iPos2) {
2677+ const auto & trackIndexPos2 = prongsPos[iPos2].trackIndex ;
26422678
26432679 uint isSelected3ProngCand = n3ProngBit;
26442680 if (!TESTBIT (trackIndexPos2.isSelProng (), CandidateType::Cand3Prong)) { // continue immediately
@@ -2655,18 +2691,13 @@ struct HfTrackIndexSkimCreator {
26552691 isSelected3ProngCand = 0 ;
26562692 }
26572693
2658- const auto trackPos2 = trackIndexPos2.template track_as <TTracks>();
2659-
2660- auto trackParVarPos2 = getTrackParCov (trackPos2);
2661- std::array dcaInfoPos2{trackPos2.dcaXY (), trackPos2.dcaZ ()};
2694+ const auto & trackPos2 = prongsPos[iPos2].track ;
2695+ const auto & trackParVarPos2 = prongsPos[iPos2].trackParVar ;
2696+ const auto & dcaInfoPos2 = prongsPos[iPos2].dcaInfo ;
26622697
26632698 // preselection of 3-prong candidates
26642699 if (isSelected3ProngCand) {
2665- std::array pVecTrackPos2{trackPos2.pVector ()};
2666- if (thisCollId != trackPos2.collisionId ()) { // this is not the "default" collision for this track and we still did not re-propagate it, we have to re-propagate it
2667- o2::base::Propagator::Instance ()->propagateToDCABxByBz ({collision.posX (), collision.posY (), collision.posZ ()}, trackParVarPos2, 2 .f , noMatCorr, &dcaInfoPos2);
2668- getPxPyPz (trackParVarPos2, pVecTrackPos2);
2669- }
2700+ const auto & pVecTrackPos2 = prongsPos[iPos2].pVec ;
26702701
26712702 if (config.debug ) {
26722703 for (int iDecay3P = 0 ; iDecay3P < kN3ProngDecays ; iDecay3P++) {
@@ -2913,7 +2944,8 @@ struct HfTrackIndexSkimCreator {
29132944 }
29142945
29152946 // second loop over negative tracks
2916- for (auto trackIndexNeg2 = trackIndexNeg1 + 1 ; trackIndexNeg2 != groupedTrackIndicesNeg1.end (); ++trackIndexNeg2) {
2947+ for (std::size_t iNeg2 = iNeg1 + 1 ; iNeg2 < prongsNeg.size (); ++iNeg2) {
2948+ const auto & trackIndexNeg2 = prongsNeg[iNeg2].trackIndex ;
29172949
29182950 int isSelected3ProngCand = n3ProngBit;
29192951 if (!TESTBIT (trackIndexNeg2.isSelProng (), CandidateType::Cand3Prong)) { // continue immediately
@@ -2930,17 +2962,13 @@ struct HfTrackIndexSkimCreator {
29302962 isSelected3ProngCand = 0 ;
29312963 }
29322964
2933- auto trackNeg2 = trackIndexNeg2. template track_as <TTracks>() ;
2934- auto trackParVarNeg2 = getTrackParCov (trackNeg2) ;
2935- std::array dcaInfoNeg2{trackNeg2. dcaXY (), trackNeg2. dcaZ ()} ;
2965+ const auto & trackNeg2 = prongsNeg[iNeg2]. track ;
2966+ const auto & trackParVarNeg2 = prongsNeg[iNeg2]. trackParVar ;
2967+ const auto & dcaInfoNeg2 = prongsNeg[iNeg2]. dcaInfo ;
29362968
29372969 // preselection of 3-prong candidates
29382970 if (isSelected3ProngCand) {
2939- std::array pVecTrackNeg2{trackNeg2.pVector ()};
2940- if (thisCollId != trackNeg2.collisionId ()) { // this is not the "default" collision for this track and we still did not re-propagate it, we have to re-propagate it
2941- o2::base::Propagator::Instance ()->propagateToDCABxByBz ({collision.posX (), collision.posY (), collision.posZ ()}, trackParVarNeg2, 2 .f , noMatCorr, &dcaInfoNeg2);
2942- getPxPyPz (trackParVarNeg2, pVecTrackNeg2);
2943- }
2971+ const auto & pVecTrackNeg2 = prongsNeg[iNeg2].pVec ;
29442972
29452973 if (config.debug ) {
29462974 for (int iDecay3P = 0 ; iDecay3P < kN3ProngDecays ; iDecay3P++) {
0 commit comments