@@ -69,7 +69,7 @@ namespace full
6969{
7070// Candidate kinematics
7171DECLARE_SOA_COLUMN (MassCd, massCd, float ); // ! Invariant mass of cd candidate (GeV/c^2)
72- DECLARE_SOA_COLUMN (MassLc, massLc, float ); // ! Invariant mass of lc candidate (GeV/c^2)
72+ DECLARE_SOA_COLUMN (MassLc, massLc, float ); // ! Invariant mass under the p K pi hypothesis (GeV/c^2)
7373DECLARE_SOA_COLUMN (Pt, pt, float ); // ! Transverse momentum of candidate (GeV/c)
7474DECLARE_SOA_COLUMN (Eta, eta, float ); // ! eta of candidate (GeV/c)
7575DECLARE_SOA_COLUMN (Phi, phi, float ); // ! phi of candidate (GeV/c)
@@ -114,13 +114,15 @@ DECLARE_SOA_COLUMN(NTpcSignalsKa, nTpcSignalsKa, float); //! Number o
114114DECLARE_SOA_COLUMN (NItsSignalsDe, nItsSignalsDe, float ); // ! Number of ITS signas
115115DECLARE_SOA_COLUMN (CandidateSelFlag, candidateSelFlag, int8_t ); // ! Candidates falg
116116DECLARE_SOA_COLUMN (CandidateSign, candidateSign, int8_t ); // ! Candidates sign
117- DECLARE_SOA_COLUMN (FlagMc, flagMc, int8_t ); // ! MC matching flag
117+ DECLARE_SOA_COLUMN (FlagMc, flagMc, int8_t ); // ! Main MC decay-channel flag; 0 for unmatched candidates
118+ DECLARE_SOA_COLUMN (IsCandidateSwapped, isCandidateSwapped, int8_t ); // ! MC-matched prong permutation; -1 for data
118119DECLARE_SOA_COLUMN (OriginMcRec, originMcRec, int8_t ); // ! MC origin for reconstructed candidates
119120DECLARE_SOA_COLUMN (FlagMcDecayChanRec, flagMcDecayChanRec, int8_t ); // ! Resonant MC decay channel for reconstructed candidates
120121DECLARE_SOA_COLUMN (OriginMcGen, originMcGen, int8_t ); // ! MC origin for generated particles
121122DECLARE_SOA_COLUMN (FlagMcDecayChanGen, flagMcDecayChanGen, int8_t ); // ! Resonant MC decay channel for generated candidates
122123DECLARE_SOA_COLUMN (CtGen, ctGen, float ); // ! Generated ct computed wrt to c-deuteron production vertex, which can be either PV (prompt) or B-hadron decay vertex (non-prompt)
123124DECLARE_SOA_COLUMN (CtRec, ctRec, float ); // ! Reconstructed ct computed wrt to PV
125+ DECLARE_SOA_COLUMN (NumPvContributors, numPvContributors, uint16_t ); // ! Number of contributors to the primary vertex
124126DECLARE_SOA_COLUMN (Cent, cent, float ); // ! Centrality
125127DECLARE_SOA_COLUMN (VtxZ, vtxZ, float ); // ! Vertex Z
126128DECLARE_SOA_COLUMN (GIndexCol, gIndexCol , int ); // ! Global index for the collision
@@ -192,9 +194,11 @@ DECLARE_SOA_TABLE(HfCandCdFull, "AOD", "HFCANDCDFULL",
192194 full::CandidateSelFlag,
193195 full::CandidateSign,
194196 full::FlagMc,
197+ full::IsCandidateSwapped,
195198 full::OriginMcRec,
196199 full::FlagMcDecayChanRec,
197200 full::CtGen,
201+ full::NumPvContributors,
198202 full::Cent,
199203 full::VtxZ,
200204 full::GIndexCol,
@@ -209,6 +213,7 @@ DECLARE_SOA_TABLE(HfCandCdGen, "AOD", "HFCANDCDGEN",
209213 full::OriginMcGen,
210214 full::FlagMcDecayChanGen,
211215 full::CtGen,
216+ full::NumPvContributors,
212217 full::Cent,
213218 full::VtxZ,
214219 full::McCollisionId);
@@ -231,6 +236,9 @@ struct HfTaskCd {
231236 Configurable<bool > cfgCutOnDeuteronDcaOrdering{" cfgCutOnDeuteronDcaOrdering" , false , " Require deuteron DCA to be smaller than kaon and pion DCAs" };
232237 Configurable<float > cfgMinDeuteronDcaPreselection{" cfgMinDeuteronDcaPreselection" , 0.004 , " Minimum deuteron DCA for preselection (cm)" };
233238 Configurable<float > cfgMaxDeuteronTofPidPreselection{" cfgMaxDeuteronTofPidPreselection" , 5 , " Maximum |nSigma TOF| for deuteron preselection" };
239+ Configurable<bool > fillMcCorrelatedBackgrounds{" fillMcCorrelatedBackgrounds" , false , " Store selected MC candidates matched to a supported decay channel other than c-deuteron" };
240+ Configurable<bool > fillMcCombinatorialBackground{" fillMcCombinatorialBackground" , false , " Store selected MC candidates with flagMcMatchRec equal to zero" };
241+ Configurable<bool > acceptCandidatesWithoutCdFlag{" acceptCandidatesWithoutCdFlag" , false , " Accept selected candidates without the Cd skim bit; intended for MC reflection studies" };
234242
235243 SliceCache cache;
236244
@@ -263,9 +271,9 @@ struct HfTaskCd {
263271 ConfigurableAxis thnConfigAxisNumPvContr{" thnConfigAxisNumPvContr" , {200 , -0.5 , 199.5 }, " Number of PV contributors" };
264272 ConfigurableAxis thnConfigAxisCt{" thnConfigAxisCt" , {500 , 0 ., 5000 .}, " " };
265273
266- constexpr static std::string_view SignalFolders[] = {" signal" , " prompt" , " nonprompt" };
267- constexpr static std::string_view SignalSuffixes[] = {" " , " Prompt" , " NonPrompt" };
268- const float cmToMum = 1 .e4 ;
274+ static constexpr std::array<std:: string_view, 3 > SignalFolders = {" signal" , " prompt" , " nonprompt" };
275+ static constexpr std::array<std:: string_view, 3 > SignalSuffixes = {" " , " Prompt" , " NonPrompt" };
276+ static constexpr float CmToMum = 1 .e4f ;
269277
270278 enum SignalClasses : int {
271279 Signal = 0 ,
@@ -332,6 +340,9 @@ struct HfTaskCd {
332340 addHistogramsGen (" hPt" , " #it{p}_{T}^{gen.} (GeV/#it{c})" , " entries" , {HistType::kTH1D , {{360 , 0 ., 36 .}}});
333341 if (!isData) {
334342 registry.add (" MC/generated/signal/hPtGenSig" , " 3-prong candidates (matched);#it{p}_{T}^{gen.} (GeV/#it{c});entries" , {HistType::kTH1D , {{360 , 0 ., 36 .}}});
343+ registry.add (" MC/reconstructed/allCandidates/hFlagMcMatchRec" , " Selected 3-prong candidates;MC decay-channel flag;entries" , {HistType::kTH1D , {{49 , -24.5 , 24.5 }}});
344+ registry.add (" MC/reconstructed/allCandidates/hMassCdVsFlagMcMatchRec" , " Selected 3-prong candidates;inv. mass (d K #pi) (GeV/#it{c}^{2});MC decay-channel flag" , {HistType::kTH2F , {{400 , 2.4 , 4.4 }, {49 , -24.5 , 24.5 }}});
345+ registry.add (" MC/reconstructed/allCandidates/hMassPKPiVsFlagMcMatchRec" , " Selected 3-prong candidates;inv. mass (p K #pi) (GeV/#it{c}^{2});MC decay-channel flag" , {HistType::kTH2F , {{400 , 1.6 , 3.2 }, {49 , -24.5 , 24.5 }}});
335346 }
336347 addHistogramsRec (" hPtProng0" , " prong 0 #it{p}_{T} (GeV/#it{c})" , " entries" , {HistType::kTH1D , {{360 , 0 ., 36 .}}});
337348 addHistogramsRec (" hPtProng1" , " prong 1 #it{p}_{T} (GeV/#it{c})" , " entries" , {HistType::kTH1D , {{360 , 0 ., 36 .}}});
@@ -496,25 +507,39 @@ struct HfTaskCd {
496507 const int64_t timeStamp = bc.timestamp ();
497508
498509 for (const auto & candidate : groupedCdCandidates) {
499- if (candidate.flagMcMatchRec () == 0 ) { // we skip combinatorial background
510+ const int absFlagMc = std::abs (candidate.flagMcMatchRec ());
511+ const bool isTrueCd = absFlagMc == hf_decay::hf_cand_3prong::DecayChannelMain::CDeuteronToDeKPi;
512+ const bool keepCorrelatedBackground = fillMcCorrelatedBackgrounds && absFlagMc != 0 && !isTrueCd;
513+ const bool keepCombinatorialBackground = fillMcCombinatorialBackground && absFlagMc == 0 ;
514+ if (!isTrueCd && !keepCorrelatedBackground && !keepCombinatorialBackground) {
500515 continue ;
501516 }
502- if (!TESTBIT (candidate.hfflag (), aod::hf_cand_3prong::DecayType::CdToDeKPi)) {
517+ if (!acceptCandidatesWithoutCdFlag && ! TESTBIT (candidate.hfflag (), aod::hf_cand_3prong::DecayType::CdToDeKPi)) {
503518 continue ;
504519 }
505520 const auto yCd = RecoDecay::y (candidate.pVector (), o2::constants::physics::MassCDeuteron);
506521 if (yCandRecoMax >= 0 . && std::abs (yCd) > yCandRecoMax) {
507522 continue ;
508523 }
509524
525+ registry.fill (HIST (" MC/reconstructed/allCandidates/hFlagMcMatchRec" ), candidate.flagMcMatchRec ());
526+ if (candidate.isSelCdToDeKPi () >= selectionFlagCd) {
527+ registry.fill (HIST (" MC/reconstructed/allCandidates/hMassCdVsFlagMcMatchRec" ), HfHelper::invMassCdToDeKPi (candidate), candidate.flagMcMatchRec ());
528+ registry.fill (HIST (" MC/reconstructed/allCandidates/hMassPKPiVsFlagMcMatchRec" ), HfHelper::invMassLcToPKPi (candidate), candidate.flagMcMatchRec ());
529+ }
530+ if (candidate.isSelCdToPiKDe () >= selectionFlagCd) {
531+ registry.fill (HIST (" MC/reconstructed/allCandidates/hMassCdVsFlagMcMatchRec" ), HfHelper::invMassCdToPiKDe (candidate), candidate.flagMcMatchRec ());
532+ registry.fill (HIST (" MC/reconstructed/allCandidates/hMassPKPiVsFlagMcMatchRec" ), HfHelper::invMassLcToPiKP (candidate), candidate.flagMcMatchRec ());
533+ }
534+
510535 float ctGen{-1 .f }, ptGen{-1 .f };
511536 int pdgCodeProng0{0 };
512- if (std::abs (candidate. flagMcMatchRec ()) == hf_decay::hf_cand_3prong::DecayChannelMain::CDeuteronToDeKPi ) {
537+ if (isTrueCd ) {
513538 const auto & mcParticleProng0 = candidate.template prong0_as <HFTracksMc>().template mcParticle_as <CandCdMcGen>();
514539 pdgCodeProng0 = std::abs (mcParticleProng0.pdgCode ());
515540 const auto indexMother = RecoDecay::getMother (mcParticles, mcParticleProng0, o2::constants::physics::Pdg::kCDeuteron , true );
516541 const auto particleMother = mcParticles.rawIteratorAt (indexMother);
517- ctGen = RecoDecay::ct (std::array{particleMother.px (), particleMother.py (), particleMother.pz ()}, RecoDecay::distance (std::array{particleMother.vx (), particleMother.vy (), particleMother.vz ()}, std::array{mcParticleProng0.vx (), mcParticleProng0.vy (), mcParticleProng0.vz ()}), o2::constants::physics::MassCDeuteron) * cmToMum ;
542+ ctGen = RecoDecay::ct (std::array{particleMother.px (), particleMother.py (), particleMother.pz ()}, RecoDecay::distance (std::array{particleMother.vx (), particleMother.vy (), particleMother.vz ()}, std::array{mcParticleProng0.vx (), mcParticleProng0.vy (), mcParticleProng0.vz ()}), o2::constants::physics::MassCDeuteron) * CmToMum ;
518543 ptGen = particleMother.pt ();
519544 }
520545
@@ -566,7 +591,7 @@ struct HfTaskCd {
566591 candidate.decayLength (), candidate.cpa (), candidate.chi2PCA (),
567592 nSigmaTpcDe, nSigmaTpcPr, nSigmaItsDe, nSigmaTofDe,
568593 tofBetaDe, tpcInnerParamDe, tofExpMomDe,
569- candidate.ct (o2::constants::physics::MassCDeuteron) * cmToMum ,
594+ candidate.ct (o2::constants::physics::MassCDeuteron) * CmToMum ,
570595 candFlag, candSign, candidate.flagMcMatchRec (), candidate.originMcRec (),
571596 candidate.flagMcDecayChanRec (), ctGen, o2::hf_centrality::getCentralityColl (collision));
572597 }
@@ -581,23 +606,34 @@ struct HfTaskCd {
581606 nSigmaTpcDe, nSigmaTpcPr, nSigmaItsDe, nSigmaTofDe,
582607 tofBetaDe, tpcInnerParamDe, tofExpMomDe,
583608 nSigmaTpcPi, nSigmaTofPi, nSigmaTpcKa, nSigmaTofKa,
584- candidate.ct (o2::constants::physics::MassCDeuteron) * cmToMum ,
585- candFlag, candSign, candidate.flagMcMatchRec (), candidate.originMcRec (),
586- candidate.flagMcDecayChanRec (), ctGen, o2::hf_centrality::getCentralityColl (collision),
609+ candidate.ct (o2::constants::physics::MassCDeuteron) * CmToMum ,
610+ candFlag, candSign, candidate.flagMcMatchRec (), candidate.isCandidateSwapped (), candidate. originMcRec (),
611+ candidate.flagMcDecayChanRec (), ctGen, collision. numContrib (), o2::hf_centrality::getCentralityColl (collision),
587612 collision.posZ (), collision.globalIndex (), timeStamp);
588613 }
589614 };
590615
591- // For MC, retain only the hypothesis that matches the true deuteron prong.
592- if (selDeKPi && pdgCodeProng0 == o2::constants::physics::Pdg::kDeuteron ) {
593- writeMcHypothesis (true );
594- }
595- if (selPiKDe && pdgCodeProng0 == kPiPlus ) {
596- writeMcHypothesis (false );
616+ if (isTrueCd) {
617+ // For signal MC, retain only the hypothesis that matches the true deuteron prong.
618+ if (selDeKPi && pdgCodeProng0 == o2::constants::physics::Pdg::kDeuteron ) {
619+ writeMcHypothesis (true );
620+ }
621+ if (selPiKDe && pdgCodeProng0 == kPiPlus ) {
622+ writeMcHypothesis (false );
623+ }
624+ } else {
625+ // Reflection and combinatorial candidates have no true deuteron prong.
626+ // Retain every Cd hypothesis accepted by the selector and distinguish them with CandidateSelFlag.
627+ if (selDeKPi) {
628+ writeMcHypothesis (true );
629+ }
630+ if (selPiKDe) {
631+ writeMcHypothesis (false );
632+ }
597633 }
598634 }
599635
600- if (std::abs (candidate. flagMcMatchRec ()) != hf_decay::hf_cand_3prong::DecayChannelMain::CDeuteronToDeKPi ) {
636+ if (!isTrueCd ) {
601637 continue ;
602638 }
603639
@@ -661,7 +697,7 @@ struct HfTaskCd {
661697 const bool isPrompt = particle.originMcGen () == 0 ;
662698 const float ptGenB = isPrompt ? -1 .f : mcParticles.rawIteratorAt (particle.idxBhadMotherPart ()).pt ();
663699 const auto firstDau = particle.template daughters_as <CandCdMcGen>().begin ();
664- const float ctGen = RecoDecay::ct (std::array{particle.px (), particle.py (), particle.pz ()}, RecoDecay::distance (std::array{particle.vx (), particle.vy (), particle.vz ()}, std::array{firstDau.vx (), firstDau.vy (), firstDau.vz ()}), o2::constants::physics::MassCDeuteron) * cmToMum ;
700+ const float ctGen = RecoDecay::ct (std::array{particle.px (), particle.py (), particle.pz ()}, RecoDecay::distance (std::array{particle.vx (), particle.vy (), particle.vz ()}, std::array{firstDau.vx (), firstDau.vy (), firstDau.vz ()}), o2::constants::physics::MassCDeuteron) * CmToMum ;
665701
666702 fillHistogramsGen<Signal>(particle, yGen);
667703 if (isPrompt) {
@@ -684,6 +720,7 @@ struct HfTaskCd {
684720 particle.originMcGen (),
685721 particle.flagMcDecayChanGen (),
686722 ctGen,
723+ numPvContributors,
687724 cent,
688725 vtxZ,
689726 particle.mcCollision ().globalIndex ());
@@ -849,7 +886,7 @@ struct HfTaskCd {
849886 tofBetaDe, tpcInnerParamDe, tofExpMomDe,
850887 nSigmaTpcPi, nSigmaTofPi, nSigmaTpcKa, nSigmaTofKa,
851888 candidate.ct (o2::constants::physics::MassCDeuteron),
852- candFlag, candSign, 0 , 0 , - 1 , -1 .f , cent,
889+ candFlag, candSign, 0 , - 1 , 0 , 0 , -1 .f , collision. numContrib () , cent,
853890 collision.posZ (), collision.globalIndex (), timeStamp);
854891 }
855892 };
0 commit comments