@@ -642,6 +642,34 @@ struct HStrangeCorrelation {
642642 " Not in table, no cut explains it" ,
643643 " In table, but replica would reject" };
644644
645+ // Breakdown of the Rec variant 0 -> 1 step of PairLossK0/Comparison ("+ truth-trigger
646+ // match/acceptance"). Every Rec trigger is counted in the All bin and in exactly one
647+ // other bin: Matched if it passes variant 1, otherwise the first condition it fails.
648+ // The order follows the variant 1 lookup -- MC label, MC collision of the label, then
649+ // the truth-trigger acceptance in the order pairLossTruthTriggerRejection checks it --
650+ // so All = Matched + the sum of the rejection bins.
651+ enum PairLossTriggerMatchQABin : int {
652+ PairLossTriggerMatchAll = 0 ,
653+ PairLossTriggerMatchMatched,
654+ PairLossTriggerMatchNoMcLabel,
655+ PairLossTriggerMatchOtherMcCollision,
656+ PairLossTriggerMatchFailPdg,
657+ PairLossTriggerMatchFailEta,
658+ PairLossTriggerMatchFailPt,
659+ PairLossTriggerMatchFailCharge,
660+ PairLossTriggerMatchNBins
661+ };
662+
663+ static constexpr std::array<std::string_view, PairLossTriggerMatchNBins> PairLossTriggerMatchQANames = {
664+ " All Rec (variant 0)" ,
665+ " Matched (variant 1)" ,
666+ " No MC label" ,
667+ " Label in another MC collision" ,
668+ " Truth PDG not pi/K/p/e/mu" ,
669+ " |eta truth| > etaSel" ,
670+ " pT truth outside trigger axis" ,
671+ " Truth charge" };
672+
645673 struct PairLossV0Info {
646674 int64_t globalIndex = -1 ;
647675 int64_t positiveTrackId = -1 ;
@@ -738,6 +766,9 @@ struct HStrangeCorrelation {
738766 std::unordered_set<PairLossPairKey, PairLossPairKeyHash> finalTruthPairs;
739767 std::unordered_set<PairLossPairKey, PairLossPairKeyHash> countedPairs;
740768 std::unordered_set<int64_t > countedTriggers;
769+ // PairLossTriggerMatchQABin of the MC particle behind every labelled trigger
770+ // track, keyed by MC particle. Only particles of this MC collision are present.
771+ std::unordered_map<int64_t , int > triggerTruthRejection;
741772
742773 void clear ()
743774 {
@@ -757,6 +788,7 @@ struct HStrangeCorrelation {
757788 finalTruthPairs.clear ();
758789 countedPairs.clear ();
759790 countedTriggers.clear ();
791+ triggerTruthRejection.clear ();
760792 }
761793 };
762794 static thread_local PairLossComparisonContext pairLossComparison;
@@ -836,6 +868,48 @@ struct HStrangeCorrelation {
836868 return absPdg == PDG_t::kPiPlus || absPdg == PDG_t::kKPlus || absPdg == PDG_t::kProton || absPdg == PDG_t::kElectron || absPdg == PDG_t::kMuonMinus ;
837869 }
838870
871+ // Truth-trigger acceptance of the PairLoss Rec comparison (comparisonTruthTriggers):
872+ // species, |eta|, pT and charge, checked in this order. Returns
873+ // PairLossTriggerMatchMatched if the generated particle passes all of them, otherwise
874+ // the PairLossTriggerMatchQABin of the first one it fails. sign is set to the charge
875+ // sign once species, |eta| and pT have passed, and to 0 before.
876+ template <typename TMcParticle>
877+ int pairLossTruthTriggerRejection (TMcParticle const & mcParticle, int & sign)
878+ {
879+ sign = 0 ;
880+ if (!isPairLossTriggerPdg (mcParticle.pdgCode ())) {
881+ return PairLossTriggerMatchFailPdg;
882+ }
883+ if (std::abs (mcParticle.eta ()) > etaSel) {
884+ return PairLossTriggerMatchFailEta;
885+ }
886+ if (mcParticle.pt () < axisRanges[3 ][0 ] || mcParticle.pt () > axisRanges[3 ][1 ]) {
887+ return PairLossTriggerMatchFailPt;
888+ }
889+ auto const * pdgParticle = pdgDB->GetParticle (mcParticle.pdgCode ());
890+ const double charge = pdgParticle != nullptr ? pdgParticle->Charge () : 0.0 ;
891+ sign = charge > 0.0 ? 1 : (charge < 0.0 ? -1 : 0 );
892+ if (sign == 0 || (triggerParticleCharge > 0 && sign < 0 ) || (triggerParticleCharge < 0 && sign > 0 )) {
893+ return PairLossTriggerMatchFailCharge;
894+ }
895+ return PairLossTriggerMatchMatched;
896+ }
897+
898+ // PairLossTriggerMatchQABin of a Rec trigger track while the PairLoss Rec comparison
899+ // runs: the two lookups of Rec variant 1, resolved into the first one that fails
900+ static int pairLossTriggerMatchBin (int64_t trackGlobalIndex)
901+ {
902+ const auto mcIt = pairLossComparison.trackToMc .find (trackGlobalIndex);
903+ if (mcIt == pairLossComparison.trackToMc .end ()) {
904+ return PairLossTriggerMatchNoMcLabel;
905+ }
906+ const auto rejectionIt = pairLossComparison.triggerTruthRejection .find (mcIt->second );
907+ if (rejectionIt == pairLossComparison.triggerTruthRejection .end ()) {
908+ return PairLossTriggerMatchOtherMcCollision;
909+ }
910+ return rejectionIt->second ;
911+ }
912+
839913 template <typename TTrack>
840914 PairLossTrackInfo makePairLossTrackInfo (TTrack const & track) const
841915 {
@@ -1376,6 +1450,9 @@ struct HStrangeCorrelation {
13761450 efficiencyTriggError = 0 ;
13771451 }
13781452 }
1453+ // PairLossTriggerMatchQABin of this trigger, set only while the PairLoss Rec
1454+ // comparison fills its variants, and reused for every pair of the trigger
1455+ int pairLossTriggerMatch = PairLossTriggerMatchAll;
13791456 if (!mixing) {
13801457
13811458 fillTriggerHistogram (histos.get <TH2 >(HIST (" sameEvent/TriggerParticlesV0" )), trigg.pt (), mult, efficiencyTrigg, efficiencyTriggError, purityTrigg, purityTriggErr);
@@ -1394,6 +1471,9 @@ struct HStrangeCorrelation {
13941471 histos.fill (HIST (" PairLossK0/Comparison/TriggerVariants" ), variant, fillPtTrigger, fillVtxZ, fillMult, weight);
13951472 };
13961473 fillTriggerVariant (0 , trigg.pt (), pvz, mult, triggerWeight);
1474+ pairLossTriggerMatch = pairLossTriggerMatchBin (trigg.globalIndex ());
1475+ histos.fill (HIST (" PairLossK0/Comparison/TriggerMatchQA/hTrigger" ), PairLossTriggerMatchAll, trigg.pt (), triggerWeight);
1476+ histos.fill (HIST (" PairLossK0/Comparison/TriggerMatchQA/hTrigger" ), pairLossTriggerMatch, trigg.pt (), triggerWeight);
13971477 const auto triggerLadderMcIt = pairLossComparison.trackToMc .find (trigg.globalIndex ());
13981478 if (triggerLadderMcIt != pairLossComparison.trackToMc .end ()) {
13991479 const auto triggerLadderTruthIt = pairLossComparison.truthTriggers .find (triggerLadderMcIt->second );
@@ -1654,6 +1734,8 @@ struct HStrangeCorrelation {
16541734 // 0: the exact Rec entry, including reconstructed coordinates
16551735 // and the ordinary Rec weight.
16561736 fillWeightedRecVariant (0 , deltaphi, deltaeta, ptassoc, pttrigger, pvz, mult);
1737+ histos.fill (HIST (" PairLossK0/Comparison/TriggerMatchQA/hPair" ), PairLossTriggerMatchAll, deltaphi, deltaeta, ptassoc, pttrigger, pairWeight);
1738+ histos.fill (HIST (" PairLossK0/Comparison/TriggerMatchQA/hPair" ), pairLossTriggerMatch, deltaphi, deltaeta, ptassoc, pttrigger, pairWeight);
16571739
16581740 const auto triggerMcIdIt = pairLossComparison.trackToMc .find (trigg.globalIndex ());
16591741 if (triggerMcIdIt != pairLossComparison.trackToMc .end ()) {
@@ -2972,6 +3054,21 @@ struct HStrangeCorrelation {
29723054 for (size_t i = 0 ; i < triggerVariantLabels.size (); ++i) {
29733055 triggerVariants->GetAxis (0 )->SetBinLabel (i + 1 , triggerVariantLabels[i].data ());
29743056 }
3057+
3058+ // Where the Rec triggers lost at the variant 0 -> 1 step fail, per trigger and per
3059+ // pair, with the weights and reconstructed coordinates of the variants: the All and
3060+ // Matched bins of hTrigger integrate to TriggerVariants 0 and 1, those of hPair to
3061+ // RecVariants 0 and 1. hPair keeps the angular axes so that the shape of the lost
3062+ // pairs (correlated or flat) is visible.
3063+ const AxisSpec axisPairLossTriggerMatchQA{PairLossTriggerMatchNBins, -0.5 , static_cast <double >(PairLossTriggerMatchNBins) - 0.5 , " Rec variant 0 #rightarrow 1 trigger match" };
3064+ histos.add (" PairLossK0/Comparison/TriggerMatchQA/hTrigger" , " Rec triggers by first failing truth-trigger condition;Rec variant 0 #rightarrow 1 trigger match;#it{p}_{T}^{trigger, reco} (GeV/#it{c})" , kTH2D , {axisPairLossTriggerMatchQA, axesConfigurations.axisPtQA });
3065+ histos.add (" PairLossK0/Comparison/TriggerMatchQA/hPair" , " Rec peak-window h-K0 pairs by first failing truth-trigger condition of their trigger" , kTHnF , {axisPairLossTriggerMatchQA, axisDeltaPhiNDim, axisDeltaEtaNDim, axisPtAssocNDim, axisPtTriggerNDim});
3066+ auto triggerMatchQATrigger = histos.get <TH2 >(HIST (" PairLossK0/Comparison/TriggerMatchQA/hTrigger" ));
3067+ auto triggerMatchQAPair = histos.get <THn>(HIST (" PairLossK0/Comparison/TriggerMatchQA/hPair" ));
3068+ for (int i = 0 ; i < PairLossTriggerMatchNBins; ++i) {
3069+ triggerMatchQATrigger->GetXaxis ()->SetBinLabel (i + 1 , PairLossTriggerMatchQANames[i].data ());
3070+ triggerMatchQAPair->GetAxis (0 )->SetBinLabel (i + 1 , PairLossTriggerMatchQANames[i].data ());
3071+ }
29753072 }
29763073 }
29773074
@@ -4965,20 +5062,16 @@ struct HStrangeCorrelation {
49655062 std::vector<PairLossTruthTrackInfo> comparisonTruthTriggers;
49665063 std::vector<PairLossTruthK0Info> comparisonTruthK0s;
49675064 for (auto const & mcParticle : mcParticles) {
4968- if (isPairLossTriggerPdg (mcParticle.pdgCode ()) && std::abs (mcParticle.eta ()) <= etaSel &&
4969- mcParticle.pt () >= axisRanges[3 ][0 ] && mcParticle.pt () <= axisRanges[3 ][1 ]) {
4970- auto const * pdgParticle = pdgDB->GetParticle (mcParticle.pdgCode ());
4971- const double charge = pdgParticle != nullptr ? pdgParticle->Charge () : 0.0 ;
4972- const int sign = charge > 0.0 ? 1 : (charge < 0.0 ? -1 : 0 );
4973- if ((triggerParticleCharge <= 0 || sign >= 0 ) && (triggerParticleCharge >= 0 || sign <= 0 ) && sign != 0 ) {
4974- comparisonTruthTriggers.push_back (PairLossTruthTrackInfo{
4975- .globalIndex = mcParticle.globalIndex (),
4976- .pt = mcParticle.pt (),
4977- .eta = mcParticle.eta (),
4978- .phi = mcParticle.phi (),
4979- .sign = sign,
4980- .physicalPrimary = mcParticle.isPhysicalPrimary ()});
4981- }
5065+ // same acceptance as the TriggerMatchQA rejection bins
5066+ int sign = 0 ;
5067+ if (pairLossTruthTriggerRejection (mcParticle, sign) == PairLossTriggerMatchMatched) {
5068+ comparisonTruthTriggers.push_back (PairLossTruthTrackInfo{
5069+ .globalIndex = mcParticle.globalIndex (),
5070+ .pt = mcParticle.pt (),
5071+ .eta = mcParticle.eta (),
5072+ .phi = mcParticle.phi (),
5073+ .sign = sign,
5074+ .physicalPrimary = mcParticle.isPhysicalPrimary ()});
49825075 }
49835076
49845077 if (mcParticle.pdgCode () != PDG_t::kK0Short || std::abs (mcParticle.eta ()) > etaSel ||
@@ -5323,6 +5416,25 @@ struct HStrangeCorrelation {
53235416 }
53245417 }
53255418 }
5419+ // Truth-trigger rejection bin of the MC particle behind every labelled trigger
5420+ // track, for PairLossK0/Comparison/TriggerMatchQA. mcParticles holds only the
5421+ // particles of this MC collision, so a label missing from the map points to
5422+ // another MC collision.
5423+ std::unordered_set<int64_t > triggerLabelIds;
5424+ for (auto const & collision : recCollisions) {
5425+ for (auto const & triggerEntry : triggerTracks.sliceBy (collisionSliceTracks, collision.globalIndex ())) {
5426+ const auto triggerMcIt = pairLossComparison.trackToMc .find (triggerEntry.trackId ());
5427+ if (triggerMcIt != pairLossComparison.trackToMc .end ()) {
5428+ triggerLabelIds.insert (triggerMcIt->second );
5429+ }
5430+ }
5431+ }
5432+ for (auto const & mcParticle : mcParticles) {
5433+ if (triggerLabelIds.contains (mcParticle.globalIndex ())) {
5434+ int sign = 0 ;
5435+ pairLossComparison.triggerTruthRejection [mcParticle.globalIndex ()] = pairLossTruthTriggerRejection (mcParticle, sign);
5436+ }
5437+ }
53265438 for (auto const & truthTrigger : comparisonTruthTriggers) {
53275439 pairLossComparison.truthTriggers [truthTrigger.globalIndex ] = truthTrigger;
53285440 }
0 commit comments