3232#include " PWGHF/Utils/utilsEvSelHf.h"
3333#include " PWGLF/DataModel/LFStrangenessTables.h"
3434
35+ #include " Common/Core/RecoDecay.h"
3536#include " Common/DataModel/Centrality.h"
3637#include " Common/DataModel/EventSelection.h"
3738#include " Common/DataModel/Multiplicity.h"
@@ -494,8 +495,46 @@ struct HfProducerCharmHadronsV0FemtoDream {
494495 }
495496 }
496497
498+ // / Classify the MC origin of a V0 candidate into the four physics classes.
499+ // / The heavy-flavour feed-down is identified with RecoDecay::getParticleOrigin, which also
500+ // / covers charm- and beauty-hadron decays flagged as physical primaries, while the
501+ // / light-flavour feed-down from a phi decay is handled explicitly.
502+ // / \param mcParticles table of the MC particles
503+ // / \param particleMc MC particle matched to the V0 candidate
504+ // / \param isFromPhi true if the K0S comes from a phi decay chain
505+ // / \return the origin according to ParticleOriginMCTruth (kPrimary, kMaterial,
506+ // / kSecondaryFromHF, kSecondaryFromLF or kSecondaryFromPhi)
507+ template <typename T>
508+ static int getK0sOrigin (T const & mcParticles, typename T::iterator const & particleMc, const bool isFromPhi)
509+ {
510+ using namespace o2 ::aod::femtodreamMCparticle;
511+ constexpr int GenFromTransport = -1 ;
512+ const auto process = particleMc.getProcess ();
513+ // hadronic interaction in the detector material
514+ if (process == TMCProcess::kPHInhelastic && particleMc.getGenStatusCode () == GenFromTransport) {
515+ return kMaterial ;
516+ }
517+ // charm- or beauty-hadron anywhere in the mother chain (feed-down can be a physical primary)
518+ if (RecoDecay::getParticleOrigin (mcParticles, particleMc, false ) != RecoDecay::OriginType::None) {
519+ return kSecondaryFromHF ;
520+ }
521+ // phi -> K0/K0bar -> K0S is light-flavour feed-down, but kept as a separate class because
522+ // the relatively long phi lifetime makes it a distinct source (also flagged as a physical primary)
523+ if (isFromPhi) {
524+ return kSecondaryFromPhi ;
525+ }
526+ if (particleMc.isPhysicalPrimary ()) {
527+ return kPrimary ;
528+ }
529+ // weak decay of a light-flavour hadron during the transport
530+ if (process == TMCProcess::kPDecay && particleMc.getGenStatusCode () == GenFromTransport && particleMc.has_mothers ()) {
531+ return kSecondaryFromLF ;
532+ }
533+ return kElse ;
534+ }
535+
497536 template <typename CollisionType, typename ParticleType>
498- void fillMcParticle (CollisionType const & col, ParticleType const & particle, o2::aod::femtodreamparticle::ParticleType fdparttype)
537+ void fillMcParticle (CollisionType const & col, ParticleType const & particle, o2::aod::femtodreamparticle::ParticleType fdparttype, aod::McParticles const & mcParticles )
499538 {
500539 if (particle.has_mcParticle ()) {
501540 // get corresponding MC particle and its info
@@ -510,6 +549,19 @@ struct HfProducerCharmHadronsV0FemtoDream {
510549 float etaPos{-1 .f }, etaNeg{-1 .f };
511550 float phiPos{-1 .f }, phiNeg{-1 .f };
512551 int pdgCodePos{0 }, pdgCodeNeg{0 };
552+ // phi -> K0/K0bar -> K0s (or phi -> K0s directly); the heavy-flavour feed-down is
553+ // handled in getK0sOrigin through RecoDecay::getParticleOrigin
554+ bool isFromPhi = false ;
555+ if (fdparttype == o2::aod::femtodreamparticle::ParticleType::kV0 && !motherparticlesMc.empty ()) {
556+ const auto absPdgMother = std::abs (motherparticlesMc.front ().pdgCode ());
557+ if (absPdgMother == o2::constants::physics::Pdg::kPhi ) {
558+ isFromPhi = true ;
559+ } else if (absPdgMother == kK0 ) {
560+ const auto & grandMothersMc = motherparticlesMc.front ().template mothers_as <aod::McParticles>();
561+ isFromPhi = !grandMothersMc.empty () && std::abs (grandMothersMc.front ().pdgCode ()) == o2::constants::physics::Pdg::kPhi ;
562+ }
563+ }
564+
513565 // check pdg code
514566 // if this fails, the particle is a fake
515567 if (std::abs (pdgCode) == std::abs (v0PDGCode.value )) {
@@ -518,6 +570,11 @@ struct HfProducerCharmHadronsV0FemtoDream {
518570 if ((col.has_mcCollision () && (particleMc.mcCollisionId () != col.mcCollisionId ())) || !col.has_mcCollision ()) {
519571 particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kWrongCollision ;
520572 // check if particle is primary
573+ } else if (fdparttype == o2::aod::femtodreamparticle::ParticleType::kV0 ) {
574+ particleOrigin = getK0sOrigin (mcParticles, particleMc, isFromPhi);
575+ if (!motherparticlesMc.empty ()) {
576+ pdgCodeMother = motherparticlesMc.front ().pdgCode ();
577+ }
521578 } else if (particleMc.isPhysicalPrimary ()) {
522579 particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kPrimary ;
523580 // check if particle is secondary
@@ -612,7 +669,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
612669 }
613670
614671 template <bool IsMc = false , typename V0Type, typename CollisionType, typename TrackType>
615- bool fillV0sForCharmHadron (CollisionType const & col, V0Type const & fullV0s, TrackType const & /* tracks*/ )
672+ bool fillV0sForCharmHadron (CollisionType const & col, V0Type const & fullV0s, TrackType const & /* tracks*/ , aod::McParticles const * mcParticles = nullptr )
616673 {
617674 const bool isK0S = (selectionFlagV0 == V0Channel::K0S );
618675 const bool isLambda = (selectionFlagV0 == V0Channel::Lambda);
@@ -724,15 +781,15 @@ struct HfProducerCharmHadronsV0FemtoDream {
724781 }
725782
726783 if constexpr (IsMc) {
727- fillMcParticle (col, v0, o2::aod::femtodreamparticle::ParticleType::kV0 );
784+ fillMcParticle (col, v0, o2::aod::femtodreamparticle::ParticleType::kV0 , *mcParticles );
728785 }
729786 fIsV0Filled = true ;
730787 }
731788 return fIsV0Filled ;
732789 }
733790
734791 template <DecayChannel Channel, bool IsMc, bool UseCharmMl, typename V0Type, typename CollisionType, typename TrackType, typename CandType>
735- void fillCharmHadronTable (CollisionType const & col, TrackType const & tracks, V0Type const & fullV0s, CandType const & candidates)
792+ void fillCharmHadronTable (CollisionType const & col, TrackType const & tracks, V0Type const & fullV0s, CandType const & candidates, aod::McParticles const * mcParticles = nullptr )
736793 {
737794 const auto vtxZ = col.posZ ();
738795 const auto sizeCand = candidates.size ();
@@ -1019,7 +1076,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
10191076 fillTable (2 , candidate.isSelDstarToD0Pi (), outputMlDstar.at (0 ), outputMlDstar.at (1 ), outputMlDstar.at (2 ));
10201077 }
10211078 }
1022- isV0Filled = fillV0sForCharmHadron<IsMc>(col, fullV0s, tracks);
1079+ isV0Filled = fillV0sForCharmHadron<IsMc>(col, fullV0s, tracks, mcParticles );
10231080 aod::femtodreamcollision::BitMaskType bitV0 = 0 ;
10241081 if (isV0Filled) {
10251082 bitV0 |= 1 << 0 ;
@@ -1248,26 +1305,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
12481305 aod::BCsWithTimestamps const &,
12491306 FemtoHFMcTracks const & tracks,
12501307 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1251- aod::McParticles const &,
1308+ aod::McParticles const & mcParticles ,
12521309 CandidateD0Mc const & candidates)
12531310 {
12541311 // get magnetic field for run
12551312 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1256- fillCharmHadronTable<DecayChannel::D0ToPiK, true , false >(col, tracks, fullV0s, candidates);
1313+ fillCharmHadronTable<DecayChannel::D0ToPiK, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
12571314 }
12581315 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcD0ToPiK, " Provide Mc for D0ToPiK" , false );
12591316
12601317 void processMcD0ToPiKWithML (FemtoFullCollisionMc const & col,
12611318 aod::BCsWithTimestamps const &,
12621319 FemtoHFMcTracks const & tracks,
12631320 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1264- aod::McParticles const &,
1321+ aod::McParticles const & mcParticles ,
12651322 soa::Join<CandidateD0Mc,
12661323 aod::HfMlD0> const & candidates)
12671324 {
12681325 // get magnetic field for run
12691326 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1270- fillCharmHadronTable<DecayChannel::D0ToPiK, true , true >(col, tracks, fullV0s, candidates);
1327+ fillCharmHadronTable<DecayChannel::D0ToPiK, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
12711328 }
12721329 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcD0ToPiKWithML, " Provide Mc for D0ToPiK with ml" , false );
12731330
@@ -1307,26 +1364,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
13071364 aod::BCsWithTimestamps const &,
13081365 FemtoHFMcTracks const & tracks,
13091366 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1310- aod::McParticles const &,
1367+ aod::McParticles const & mcParticles ,
13111368 CandidateDstarMc const & candidates)
13121369 {
13131370 // get magnetic field for run
13141371 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1315- fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , false >(col, tracks, fullV0s, candidates);
1372+ fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
13161373 }
13171374 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDstarToD0Pi, " Provide Mc for DstarToD0Pi" , false );
13181375
13191376 void processMcDstarToD0PiWithML (FemtoFullCollisionMc const & col,
13201377 aod::BCsWithTimestamps const &,
13211378 FemtoHFMcTracks const & tracks,
13221379 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1323- aod::McParticles const &,
1380+ aod::McParticles const & mcParticles ,
13241381 soa::Join<CandidateDstarMc,
13251382 aod::HfMlDstarToD0Pi> const & candidates)
13261383 {
13271384 // get magnetic field for run
13281385 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1329- fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , true >(col, tracks, fullV0s, candidates);
1386+ fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
13301387 }
13311388 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDstarToD0PiWithML, " Provide Mc for DstarToD0Pi with ml" , false );
13321389
@@ -1368,26 +1425,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
13681425 aod::BCsWithTimestamps const &,
13691426 FemtoHFMcTracks const & tracks,
13701427 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1371- aod::McParticles const &,
1428+ aod::McParticles const & mcParticles ,
13721429 CandidateDplusMc const & candidates)
13731430 {
13741431 // get magnetic field for run
13751432 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1376- fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , false >(col, tracks, fullV0s, candidates);
1433+ fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
13771434 }
13781435 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDplusToPiKPi, " Provide Mc for DplusToPiKPi" , false );
13791436
13801437 void processMcDplusToPiKPiWithML (FemtoFullCollisionMc const & col,
13811438 aod::BCsWithTimestamps const &,
13821439 FemtoHFMcTracks const & tracks,
13831440 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1384- aod::McParticles const &,
1441+ aod::McParticles const & mcParticles ,
13851442 soa::Join<CandidateDplusMc,
13861443 aod::HfMlDplusToPiKPi> const & candidates)
13871444 {
13881445 // get magnetic field for run
13891446 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1390- fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , true >(col, tracks, fullV0s, candidates);
1447+ fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
13911448 }
13921449 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDplusToPiKPiWithML, " Provide Mc for DplusToPiKPi with ml" , false );
13931450
@@ -1429,26 +1486,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
14291486 aod::BCsWithTimestamps const &,
14301487 FemtoHFMcTracks const & tracks,
14311488 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1432- aod::McParticles const &,
1489+ aod::McParticles const & mcParticles ,
14331490 CandidateLcMc const & candidates)
14341491 {
14351492 // get magnetic field for run
14361493 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1437- fillCharmHadronTable<DecayChannel::LcToPKPi, true , false >(col, tracks, fullV0s, candidates);
1494+ fillCharmHadronTable<DecayChannel::LcToPKPi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
14381495 }
14391496 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcLcToPKPi, " Provide Mc for lctopkpi" , false );
14401497
14411498 void processMcLcToPKPiWithML (FemtoFullCollisionMc const & col,
14421499 aod::BCsWithTimestamps const &,
14431500 FemtoHFMcTracks const & tracks,
14441501 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1445- aod::McParticles const &,
1502+ aod::McParticles const & mcParticles ,
14461503 soa::Join<CandidateLcMc,
14471504 aod::HfMlLcToPKPi> const & candidates)
14481505 {
14491506 // get magnetic field for run
14501507 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1451- fillCharmHadronTable<DecayChannel::LcToPKPi, true , true >(col, tracks, fullV0s, candidates);
1508+ fillCharmHadronTable<DecayChannel::LcToPKPi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
14521509 }
14531510 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcLcToPKPiWithML, " Provide Mc for lctopkpi with ml" , false );
14541511
0 commit comments