@@ -257,6 +257,12 @@ struct HfTaskCd {
257257 using CollisionsWithEvSelFT0M = soa::Join<aod::Collisions, aod::EvSels, aod::PVMults, aod::CentFT0Ms>;
258258 using CollisionsMcWithEvSelFT0M = soa::Join<aod::Collisions, aod::McCollisionLabels, aod::EvSels, aod::PVMults, aod::CentFT0Ms>;
259259
260+ struct : ConfigurableGroup {
261+ std::string prefix = " mixing" ;
262+ Configurable<bool > enabled{" enabled" , false , " Analyze mixed-event input in a separate run" };
263+ Configurable<int > type{" type" , 0 , " QA label matching builder mixing.type: 0 d, 1 K, 2 pion" };
264+ } mixing;
265+
260266 using CdCandidates = soa::Filtered<soa::Join<aod::HfCand3Prong, aod::HfSelCd, aod::HfCand3ProngWPidPiKaDe>>;
261267 using CdCandidatesMc = soa::Filtered<soa::Join<aod::HfCand3Prong, aod::HfSelCd, aod::HfCand3ProngWPidPiKaDe, aod::HfCand3ProngMcRec>>;
262268 using McParticles3ProngMatched = soa::Join<aod::McParticles, aod::HfCand3ProngMcGen>;
@@ -327,6 +333,30 @@ struct HfTaskCd {
327333 }
328334 const bool isData = doprocessDataStd || doprocessDataStdWithFT0C || doprocessDataStdWithFT0M;
329335
336+ if (mixing.enabled ) {
337+ constexpr int LastMixingType{2 };
338+ if (!isData || mixing.type < 0 || mixing.type > LastMixingType) {
339+ LOGP (fatal, " Mixed-event taskCd requires a data process and a valid mixing.type." );
340+ }
341+ registry.add (" Mixed/hMassVsPtVsType" , " Mixed candidates after selector;M(dK#pi);p_{T};mixing type" , HistType::kTH3F ,
342+ {{400 , 2.4 , 4.4 }, {binsPt, " p_{T}" }, {3 , -0.5 , 2.5 }});
343+ }
344+ if (isData && (fillCandLiteTree || fillCandFullTree)) {
345+ registry.add (" Data/hTreeCutFlow" , " Cumulative write preselection per mass hypothesis;Stage;Hypothesis" , HistType::kTH2D , {{4 , -0.5 , 3.5 }, {2 , -0.5 , 1.5 }});
346+ registry.add (" Data/hDeuteronTofStatus" , " TOF status before write preselection;Status;Hypothesis" , HistType::kTH2D , {{5 , -0.5 , 4.5 }, {2 , -0.5 , 1.5 }});
347+ const std::array<std::string, 4 > cutLabels{" Before tree cuts" , " After TOF (or disabled)" , " After minimum d DCA" , " After DCA ordering (or disabled)" };
348+ const std::array<std::string, 5 > tofLabels{" No TOF match" , " Nonfinite nSigma" , " Missing nSigma sentinel" , " Finite nSigma within cut" , " Finite nSigma outside cut" };
349+ for (size_t i = 0 ; i < cutLabels.size (); ++i) {
350+ registry.get <TH2 >(HIST (" Data/hTreeCutFlow" ))->GetXaxis ()->SetBinLabel (i + 1 , cutLabels[i].c_str ());
351+ }
352+ for (size_t i = 0 ; i < tofLabels.size (); ++i) {
353+ registry.get <TH2 >(HIST (" Data/hDeuteronTofStatus" ))->GetXaxis ()->SetBinLabel (i + 1 , tofLabels[i].c_str ());
354+ }
355+ for (const auto & histogram : {registry.get <TH2 >(HIST (" Data/hTreeCutFlow" )), registry.get <TH2 >(HIST (" Data/hDeuteronTofStatus" ))}) {
356+ histogram->GetYaxis ()->SetBinLabel (1 , " DeKPi" );
357+ histogram->GetYaxis ()->SetBinLabel (2 , " PiKDe" );
358+ }
359+ }
330360 auto addHistogramsRec = [&](const std::string& histoName, const std::string& xAxisTitle, const std::string& yAxisTitle, const HistogramConfigSpec& configSpec) {
331361 if (!isData) {
332362 registry.add ((" MC/reconstructed/signal/" + histoName + " RecSig" ).c_str (), (" 3-prong candidates (matched);" + xAxisTitle + " ;" + yAxisTitle).c_str (), configSpec);
@@ -768,6 +798,14 @@ struct HfTaskCd {
768798 const auto chi2PCA = candidate.chi2PCA ();
769799 const auto cpa = candidate.cpa ();
770800 const auto cpaXY = candidate.cpaXY ();
801+ if (mixing.enabled ) {
802+ if (candidate.isSelCdToDeKPi () >= selectionFlagCd) {
803+ registry.fill (HIST (" Mixed/hMassVsPtVsType" ), HfHelper::invMassCdToDeKPi (candidate), candidate.pt (), mixing.type .value );
804+ }
805+ if (candidate.isSelCdToPiKDe () >= selectionFlagCd) {
806+ registry.fill (HIST (" Mixed/hMassVsPtVsType" ), HfHelper::invMassCdToPiKDe (candidate), candidate.pt (), mixing.type .value );
807+ }
808+ }
771809 if (candidate.isSelCdToDeKPi () >= selectionFlagCd) {
772810 registry.fill (HIST (" Data/hMass" ), HfHelper::invMassCdToDeKPi (candidate));
773811 registry.fill (HIST (" Data/hMassVsPtVsNPvContributors" ), HfHelper::invMassCdToDeKPi (candidate), pt, numPvContributors);
@@ -874,16 +912,27 @@ struct HfTaskCd {
874912 registry.fill (HIST (" Data/hNsigmaTPCKaVsP" ), prong1.tpcInnerParam () * prong1.sign (), nSigmaTpcKa);
875913 registry.fill (HIST (" Data/hNsigmaTOFKaVsP" ), prong1.tpcInnerParam () * prong1.sign (), nSigmaTofKa);
876914
915+ // Diagnostic categories only: preserve the existing selection predicates below.
916+ enum TofStatus { NoMatch, Nonfinite, Missing, WithinCut, OutsideCut };
917+ constexpr float MissingTofNSigma{-999 .f };
918+ const int hypothesis = isDeKPi ? 0 : 1 ;
919+ const int tofStatus = !deuteronProng.hasTOF () ? NoMatch : !std::isfinite (nSigmaTofDe) ? Nonfinite : nSigmaTofDe <= MissingTofNSigma ? Missing : std::abs (nSigmaTofDe) <= cfgMaxDeuteronTofPidPreselection ? WithinCut : OutsideCut;
920+ registry.fill (HIST (" Data/hDeuteronTofStatus" ), tofStatus, hypothesis);
921+ registry.fill (HIST (" Data/hTreeCutFlow" ), 0 , hypothesis);
877922 if (cfgUseTofPidForDeuteron && std::abs (nSigmaTofDe) > cfgMaxDeuteronTofPidPreselection) {
878923 return ;
879924 }
925+ registry.fill (HIST (" Data/hTreeCutFlow" ), 1 , hypothesis);
880926 if (std::abs (dcaDeuteron) < cfgMinDeuteronDcaPreselection) {
881927 return ;
882928 }
929+ registry.fill (HIST (" Data/hTreeCutFlow" ), 2 , hypothesis);
883930 if (cfgCutOnDeuteronDcaOrdering && (std::abs (dcaDeuteron) > std::abs (dcaKaon) || std::abs (dcaDeuteron) > std::abs (dcaPion))) {
884931 return ;
885932 }
886933
934+ registry.fill (HIST (" Data/hTreeCutFlow" ), 3 , hypothesis);
935+
887936 if (fillCandLiteTree) {
888937 rowCandCdLite (
889938 invMassCd, invMassLc, pt, eta, phi, ptProng0, ptProng1, ptProng2,
0 commit comments