@@ -100,6 +100,8 @@ struct DiHadronCor {
100100 O2_DEFINE_CONFIGURABLE (cfgUseEventWeights, bool , false , " Use event weights for mixed event" )
101101 O2_DEFINE_CONFIGURABLE (cfgUsePtOrder, bool , true , " enable trigger pT < associated pT cut" )
102102 O2_DEFINE_CONFIGURABLE (cfgUsePtOrderInMixEvent, bool , true , " enable trigger pT < associated pT cut in mixed event" )
103+ O2_DEFINE_CONFIGURABLE (cfgSoloPtTrack, bool , false , " Skip trigger tracks that are alone in their pT bin for same process" )
104+ O2_DEFINE_CONFIGURABLE (cfgSingleSoloPtTrack, bool , false , " Skip associated tracks that are alone in their pT bin for same process, works only if cfgSoloPtTrack is enabled" )
103105 struct : ConfigurableGroup {
104106 O2_DEFINE_CONFIGURABLE (cfgMultCentHighCutFunction, std::string, " [0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x + 10.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)" , " Functional for multiplicity correlation cut" );
105107 O2_DEFINE_CONFIGURABLE (cfgMultCentLowCutFunction, std::string, " [0] + [1]*x + [2]*x*x + [3]*x*x*x + [4]*x*x*x*x - 3.*([5] + [6]*x + [7]*x*x + [8]*x*x*x + [9]*x*x*x*x)" , " Functional for multiplicity correlation cut" );
@@ -279,6 +281,13 @@ struct DiHadronCor {
279281 registry.add (" zVtx_used" , " zVtx_used" , {HistType::kTH1D , {axisVertex}});
280282 registry.add (" Trig_hist" , " " , {HistType::kTHnSparseF , {{axisSample, axisVertex, axisPtTrigger}}});
281283 }
284+ if (cfgSoloPtTrack && doprocessSame) {
285+ registry.add (" Nch_final_pt" , " pT" , {HistType::kTH1D , {axisPtTrigger}});
286+ registry.add (" Solo_tracks_trigger" , " pT" , {HistType::kTH1D , {axisPtTrigger}});
287+ if (!cfgSingleSoloPtTrack) {
288+ registry.add (" Solo_tracks_assoc" , " pT" , {HistType::kTH1D , {axisPtAssoc}});
289+ }
290+ }
282291
283292 registry.add (" eventcount" , " bin" , {HistType::kTH1F , {{4 , 0 , 4 , " bin" }}}); // histogram to see how many events are in the same and mixed event
284293 if (doprocessMCSame && doprocessOntheflySame) {
@@ -582,6 +591,103 @@ struct DiHadronCor {
582591 }
583592 }
584593 }
594+
595+ template <CorrelationContainer::CFStep step, typename TTracks, typename TTracksAssoc>
596+ void fillCorrelationsExcludeSoloTracks (TTracks tracks1, TTracksAssoc tracks2, float posZ, int magneticField, float cent, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms
597+ {
598+ std::vector<int64_t > tracksSkipIndices;
599+ std::vector<int64_t > tracks2SkipIndices;
600+
601+ findBiasedTracks (tracks1, tracksSkipIndices, posZ);
602+ if (!cfgSingleSoloPtTrack) { // only look for the solo pt tracks if we want to skip both
603+ findBiasedTracks (tracks2, tracks2SkipIndices, posZ);
604+ }
605+
606+ // Cache efficiency for particles (too many FindBin lookups)
607+ if (mEfficiency ) {
608+ efficiencyAssociatedCache.clear ();
609+ efficiencyAssociatedCache.reserve (tracks2.size ());
610+ for (const auto & track2 : tracks2) {
611+ float weff = 1 .;
612+ getEfficiencyCorrection (weff, track2.eta (), track2.pt (), posZ);
613+ efficiencyAssociatedCache.push_back (weff);
614+ }
615+ }
616+
617+ if (!cfgCentTableUnavailable)
618+ registry.fill (HIST (" Centrality_used" ), cent);
619+ registry.fill (HIST (" Nch_used" ), tracks1.size ());
620+
621+ int fSampleIndex = gRandom ->Uniform (0 , cfgSampleSize);
622+
623+ float triggerWeight = 1 .0f ;
624+ float associatedWeight = 1 .0f ;
625+ // loop over all tracks
626+ for (auto const & track1 : tracks1) {
627+
628+ if (!trackSelected (track1))
629+ continue ;
630+ if (!getEfficiencyCorrection (triggerWeight, track1.eta (), track1.pt (), posZ))
631+ continue ;
632+
633+ registry.fill (HIST (" Nch_final_pt" ), track1.pt ());
634+
635+ if (std::find (tracksSkipIndices.begin (), tracksSkipIndices.end (), track1.globalIndex ()) != tracksSkipIndices.end ()) {
636+ registry.fill (HIST (" Solo_tracks_trigger" ), track1.pt ());
637+ continue ; // Skip the track1 if it is alone in pt bin
638+ }
639+ registry.fill (HIST (" Trig_hist" ), fSampleIndex , posZ, track1.pt (), eventWeight * triggerWeight);
640+
641+ for (auto const & track2 : tracks2) {
642+
643+ if (!trackSelected (track2))
644+ continue ;
645+ if (mEfficiency ) {
646+ associatedWeight = efficiencyAssociatedCache[track2.filteredIndex ()];
647+ }
648+ if (!cfgUsePtOrder && track1.globalIndex () == track2.globalIndex ())
649+ continue ; // For pt-differential correlations, skip if the trigger and associate are the same track
650+ if (cfgUsePtOrder && track1.pt () <= track2.pt ())
651+ continue ; // Without pt-differential correlations, skip if the trigger pt is less than the associate pt
652+ if (!cfgSingleSoloPtTrack) { // avoid skipping the second track if we only want one
653+ if (std::find (tracks2SkipIndices.begin (), tracks2SkipIndices.end (), track2.globalIndex ()) != tracks2SkipIndices.end ()) {
654+ registry.fill (HIST (" Solo_tracks_assoc" ), track2.pt ());
655+ continue ; // Skip the track2 if it is alone in pt bin
656+ }
657+ }
658+
659+ float deltaPhi = RecoDecay::constrainAngle (track1.phi () - track2.phi (), -PIHalf);
660+ float deltaEta = track1.eta () - track2.eta ();
661+
662+ if (std::abs (deltaEta) < cfgCutMerging) {
663+
664+ double dPhiStarHigh = getDPhiStar (track1, track2, cfgRadiusHigh, magneticField);
665+ double dPhiStarLow = getDPhiStar (track1, track2, cfgRadiusLow, magneticField);
666+
667+ const double kLimit = 3.0 * cfgCutMerging;
668+
669+ bool bIsBelow = false ;
670+
671+ if (std::abs (dPhiStarLow) < kLimit || std::abs (dPhiStarHigh) < kLimit || dPhiStarLow * dPhiStarHigh < 0 ) {
672+ for (double rad (cfgRadiusLow); rad < cfgRadiusHigh; rad += 0.01 ) {
673+ double dPhiStar = getDPhiStar (track1, track2, rad, magneticField);
674+ if (std::abs (dPhiStar) < kLimit ) {
675+ bIsBelow = true ;
676+ break ;
677+ }
678+ }
679+ if (bIsBelow)
680+ continue ;
681+ }
682+ }
683+
684+ // fill the right sparse and histograms
685+ same->getPairHist ()->Fill (step, fSampleIndex , posZ, track1.pt (), track2.pt (), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight);
686+ registry.fill (HIST (" deltaEta_deltaPhi_same" ), deltaPhi, deltaEta, eventWeight * triggerWeight * associatedWeight);
687+ }
688+ }
689+ }
690+
585691 template <CorrelationContainer::CFStep step, typename TTracks, typename TTracksAssoc>
586692 void fillMCCorrelations (TTracks tracks1, TTracksAssoc tracks2, float posZ, int system, float eventWeight) // function to fill the Output functions (sparse) and the delta eta and delta phi histograms
587693 {
@@ -729,6 +835,45 @@ struct DiHadronCor {
729835 return 1 ;
730836 }
731837
838+ void findBiasedTracks (FilteredTracks const & tracks, std::vector<int64_t >& tracksSkipIndices, float posZ)
839+ {
840+ // Find the tracks that are alone in their pT bin
841+ tracksSkipIndices.clear ();
842+ static const std::vector<double >& ptBins = axisPtTrigger.value ;
843+ static const size_t nPtBins = ptBins.size () - 1 ;
844+
845+ std::vector<int > numberOfTracksInBin (nPtBins, 0 );
846+ std::vector<int64_t > firstTrackIndex (nPtBins, -1 );
847+
848+ float triggerWeight = 1 .0f ;
849+
850+ // Count tracks per bin and remember the first track id in each bin
851+ for (const auto & track : tracks) {
852+ if (!trackSelected (track))
853+ continue ;
854+ if (!getEfficiencyCorrection (triggerWeight, track.eta (), track.pt (), posZ))
855+ continue ;
856+ double pt = track.pt ();
857+ auto binEdgeIt = std::upper_bound (ptBins.begin (), ptBins.end (), pt);
858+ if (binEdgeIt == ptBins.begin () || binEdgeIt == ptBins.end ())
859+ continue ; // skip pt bins out of range
860+
861+ size_t binIndex = static_cast <size_t >(std::distance (ptBins.begin (), binEdgeIt) - 1 );
862+
863+ if (numberOfTracksInBin[binIndex] == 0 ) {
864+ firstTrackIndex[binIndex] = track.globalIndex ();
865+ }
866+ ++numberOfTracksInBin[binIndex];
867+ }
868+
869+ // Collect track ids for bins that have exactly one track
870+ for (size_t i = 0 ; i < nPtBins; ++i) {
871+ if (numberOfTracksInBin[i] == 1 ) {
872+ tracksSkipIndices.push_back (firstTrackIndex[i]);
873+ }
874+ }
875+ }
876+
732877 void processSame (FilteredCollisions::iterator const & collision, FilteredTracks const & tracks, aod::BCsWithTimestamps const &)
733878 {
734879 if (!collision.sel8 ())
@@ -761,7 +906,11 @@ struct DiHadronCor {
761906 fillYield (collision, tracks);
762907
763908 same->fillEvent (tracks.size (), CorrelationContainer::kCFStepReconstructed );
764- fillCorrelations<CorrelationContainer::kCFStepReconstructed >(tracks, tracks, collision.posZ (), SameEvent, getMagneticField (bc.timestamp ()), cent, weightCent);
909+ if (!cfgSoloPtTrack) {
910+ fillCorrelations<CorrelationContainer::kCFStepReconstructed >(tracks, tracks, collision.posZ (), SameEvent, getMagneticField (bc.timestamp ()), cent, weightCent);
911+ } else {
912+ fillCorrelationsExcludeSoloTracks<CorrelationContainer::kCFStepReconstructed >(tracks, tracks, collision.posZ (), getMagneticField (bc.timestamp ()), cent, weightCent);
913+ }
765914 }
766915 PROCESS_SWITCH (DiHadronCor, processSame, " Process same event" , true );
767916
0 commit comments