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,47 @@ struct HfProducerCharmHadronsV0FemtoDream {
494495 }
495496 }
496497
498+ // / Classify the MC origin of a V0 candidate.
499+ // / The heavy-flavour feed-down is identified with RecoDecay::getParticleOrigin, which also
500+ // / covers charm- and beauty-hadron decays flagged as physical primaries. The feed-down from
501+ // / a phi decay is light-flavour and kept as a separate class, since the relatively long phi
502+ // / lifetime makes it a distinct source.
503+ // / \param mcParticles table of the MC particles
504+ // / \param particleMc MC particle matched to the V0 candidate
505+ // / \param isFromPhi true if the K0S comes from a phi decay chain
506+ // / \return the origin according to ParticleOriginMCTruth (kPrimary, kMaterial,
507+ // / kSecondaryFromHF, kSecondaryFromLF or kSecondaryFromPhi)
508+ template <typename T>
509+ static int getK0sOrigin (T const & mcParticles, typename T::iterator const & particleMc, const bool isFromPhi)
510+ {
511+ using namespace o2 ::aod::femtodreamMCparticle;
512+ constexpr int GenFromTransport = -1 ;
513+ const auto process = particleMc.getProcess ();
514+ // hadronic interaction in the detector material
515+ if (process == TMCProcess::kPHInhelastic && particleMc.getGenStatusCode () == GenFromTransport) {
516+ return kMaterial ;
517+ }
518+ // charm- or beauty-hadron anywhere in the mother chain (feed-down can be a physical primary)
519+ if (RecoDecay::getParticleOrigin (mcParticles, particleMc, false ) != RecoDecay::OriginType::None) {
520+ return kSecondaryFromHF ;
521+ }
522+ // phi -> K0/K0bar -> K0S is light-flavour feed-down, but kept as a separate class because
523+ // the relatively long phi lifetime makes it a distinct source (also flagged as a physical primary)
524+ if (isFromPhi) {
525+ return kSecondaryFromPhi ;
526+ }
527+ if (particleMc.isPhysicalPrimary ()) {
528+ return kPrimary ;
529+ }
530+ // weak decay of a light-flavour hadron during the transport
531+ if (process == TMCProcess::kPDecay && particleMc.getGenStatusCode () == GenFromTransport && particleMc.has_mothers ()) {
532+ return kSecondaryFromLF ;
533+ }
534+ return kElse ;
535+ }
536+
497537 template <typename CollisionType, typename ParticleType>
498- void fillMcParticle (CollisionType const & col, ParticleType const & particle, o2::aod::femtodreamparticle::ParticleType fdparttype)
538+ void fillMcParticle (CollisionType const & col, ParticleType const & particle, o2::aod::femtodreamparticle::ParticleType fdparttype, aod::McParticles const & mcParticles )
499539 {
500540 if (particle.has_mcParticle ()) {
501541 // get corresponding MC particle and its info
@@ -510,6 +550,19 @@ struct HfProducerCharmHadronsV0FemtoDream {
510550 float etaPos{-1 .f }, etaNeg{-1 .f };
511551 float phiPos{-1 .f }, phiNeg{-1 .f };
512552 int pdgCodePos{0 }, pdgCodeNeg{0 };
553+ // phi -> K0/K0bar -> K0s (or phi -> K0s directly); the heavy-flavour feed-down is
554+ // handled in getK0sOrigin through RecoDecay::getParticleOrigin
555+ bool isFromPhi = false ;
556+ if (fdparttype == o2::aod::femtodreamparticle::ParticleType::kV0 && !motherparticlesMc.empty ()) {
557+ const auto absPdgMother = std::abs (motherparticlesMc.front ().pdgCode ());
558+ if (absPdgMother == o2::constants::physics::Pdg::kPhi ) {
559+ isFromPhi = true ;
560+ } else if (absPdgMother == kK0 ) {
561+ const auto & grandMothersMc = motherparticlesMc.front ().template mothers_as <aod::McParticles>();
562+ isFromPhi = !grandMothersMc.empty () && std::abs (grandMothersMc.front ().pdgCode ()) == o2::constants::physics::Pdg::kPhi ;
563+ }
564+ }
565+
513566 // check pdg code
514567 // if this fails, the particle is a fake
515568 if (std::abs (pdgCode) == std::abs (v0PDGCode.value )) {
@@ -518,6 +571,11 @@ struct HfProducerCharmHadronsV0FemtoDream {
518571 if ((col.has_mcCollision () && (particleMc.mcCollisionId () != col.mcCollisionId ())) || !col.has_mcCollision ()) {
519572 particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kWrongCollision ;
520573 // check if particle is primary
574+ } else if (fdparttype == o2::aod::femtodreamparticle::ParticleType::kV0 ) {
575+ particleOrigin = getK0sOrigin (mcParticles, particleMc, isFromPhi);
576+ if (!motherparticlesMc.empty ()) {
577+ pdgCodeMother = motherparticlesMc.front ().pdgCode ();
578+ }
521579 } else if (particleMc.isPhysicalPrimary ()) {
522580 particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kPrimary ;
523581 // check if particle is secondary
@@ -612,7 +670,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
612670 }
613671
614672 template <bool IsMc = false , typename V0Type, typename CollisionType, typename TrackType>
615- bool fillV0sForCharmHadron (CollisionType const & col, V0Type const & fullV0s, TrackType const & /* tracks*/ )
673+ bool fillV0sForCharmHadron (CollisionType const & col, V0Type const & fullV0s, TrackType const & /* tracks*/ , aod::McParticles const * mcParticles = nullptr )
616674 {
617675 const bool isK0S = (selectionFlagV0 == V0Channel::K0S );
618676 const bool isLambda = (selectionFlagV0 == V0Channel::Lambda);
@@ -724,15 +782,15 @@ struct HfProducerCharmHadronsV0FemtoDream {
724782 }
725783
726784 if constexpr (IsMc) {
727- fillMcParticle (col, v0, o2::aod::femtodreamparticle::ParticleType::kV0 );
785+ fillMcParticle (col, v0, o2::aod::femtodreamparticle::ParticleType::kV0 , *mcParticles );
728786 }
729787 fIsV0Filled = true ;
730788 }
731789 return fIsV0Filled ;
732790 }
733791
734792 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)
793+ void fillCharmHadronTable (CollisionType const & col, TrackType const & tracks, V0Type const & fullV0s, CandType const & candidates, aod::McParticles const * mcParticles = nullptr )
736794 {
737795 const auto vtxZ = col.posZ ();
738796 const auto sizeCand = candidates.size ();
@@ -1019,7 +1077,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
10191077 fillTable (2 , candidate.isSelDstarToD0Pi (), outputMlDstar.at (0 ), outputMlDstar.at (1 ), outputMlDstar.at (2 ));
10201078 }
10211079 }
1022- isV0Filled = fillV0sForCharmHadron<IsMc>(col, fullV0s, tracks);
1080+ isV0Filled = fillV0sForCharmHadron<IsMc>(col, fullV0s, tracks, mcParticles );
10231081 aod::femtodreamcollision::BitMaskType bitV0 = 0 ;
10241082 if (isV0Filled) {
10251083 bitV0 |= 1 << 0 ;
@@ -1248,26 +1306,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
12481306 aod::BCsWithTimestamps const &,
12491307 FemtoHFMcTracks const & tracks,
12501308 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1251- aod::McParticles const &,
1309+ aod::McParticles const & mcParticles ,
12521310 CandidateD0Mc const & candidates)
12531311 {
12541312 // get magnetic field for run
12551313 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1256- fillCharmHadronTable<DecayChannel::D0ToPiK, true , false >(col, tracks, fullV0s, candidates);
1314+ fillCharmHadronTable<DecayChannel::D0ToPiK, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
12571315 }
12581316 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcD0ToPiK, " Provide Mc for D0ToPiK" , false );
12591317
12601318 void processMcD0ToPiKWithML (FemtoFullCollisionMc const & col,
12611319 aod::BCsWithTimestamps const &,
12621320 FemtoHFMcTracks const & tracks,
12631321 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1264- aod::McParticles const &,
1322+ aod::McParticles const & mcParticles ,
12651323 soa::Join<CandidateD0Mc,
12661324 aod::HfMlD0> const & candidates)
12671325 {
12681326 // get magnetic field for run
12691327 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1270- fillCharmHadronTable<DecayChannel::D0ToPiK, true , true >(col, tracks, fullV0s, candidates);
1328+ fillCharmHadronTable<DecayChannel::D0ToPiK, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
12711329 }
12721330 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcD0ToPiKWithML, " Provide Mc for D0ToPiK with ml" , false );
12731331
@@ -1307,26 +1365,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
13071365 aod::BCsWithTimestamps const &,
13081366 FemtoHFMcTracks const & tracks,
13091367 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1310- aod::McParticles const &,
1368+ aod::McParticles const & mcParticles ,
13111369 CandidateDstarMc const & candidates)
13121370 {
13131371 // get magnetic field for run
13141372 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1315- fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , false >(col, tracks, fullV0s, candidates);
1373+ fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
13161374 }
13171375 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDstarToD0Pi, " Provide Mc for DstarToD0Pi" , false );
13181376
13191377 void processMcDstarToD0PiWithML (FemtoFullCollisionMc const & col,
13201378 aod::BCsWithTimestamps const &,
13211379 FemtoHFMcTracks const & tracks,
13221380 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1323- aod::McParticles const &,
1381+ aod::McParticles const & mcParticles ,
13241382 soa::Join<CandidateDstarMc,
13251383 aod::HfMlDstarToD0Pi> const & candidates)
13261384 {
13271385 // get magnetic field for run
13281386 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1329- fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , true >(col, tracks, fullV0s, candidates);
1387+ fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
13301388 }
13311389 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDstarToD0PiWithML, " Provide Mc for DstarToD0Pi with ml" , false );
13321390
@@ -1368,26 +1426,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
13681426 aod::BCsWithTimestamps const &,
13691427 FemtoHFMcTracks const & tracks,
13701428 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1371- aod::McParticles const &,
1429+ aod::McParticles const & mcParticles ,
13721430 CandidateDplusMc const & candidates)
13731431 {
13741432 // get magnetic field for run
13751433 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1376- fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , false >(col, tracks, fullV0s, candidates);
1434+ fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
13771435 }
13781436 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDplusToPiKPi, " Provide Mc for DplusToPiKPi" , false );
13791437
13801438 void processMcDplusToPiKPiWithML (FemtoFullCollisionMc const & col,
13811439 aod::BCsWithTimestamps const &,
13821440 FemtoHFMcTracks const & tracks,
13831441 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1384- aod::McParticles const &,
1442+ aod::McParticles const & mcParticles ,
13851443 soa::Join<CandidateDplusMc,
13861444 aod::HfMlDplusToPiKPi> const & candidates)
13871445 {
13881446 // get magnetic field for run
13891447 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1390- fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , true >(col, tracks, fullV0s, candidates);
1448+ fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
13911449 }
13921450 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDplusToPiKPiWithML, " Provide Mc for DplusToPiKPi with ml" , false );
13931451
@@ -1429,26 +1487,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
14291487 aod::BCsWithTimestamps const &,
14301488 FemtoHFMcTracks const & tracks,
14311489 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1432- aod::McParticles const &,
1490+ aod::McParticles const & mcParticles ,
14331491 CandidateLcMc const & candidates)
14341492 {
14351493 // get magnetic field for run
14361494 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1437- fillCharmHadronTable<DecayChannel::LcToPKPi, true , false >(col, tracks, fullV0s, candidates);
1495+ fillCharmHadronTable<DecayChannel::LcToPKPi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
14381496 }
14391497 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcLcToPKPi, " Provide Mc for lctopkpi" , false );
14401498
14411499 void processMcLcToPKPiWithML (FemtoFullCollisionMc const & col,
14421500 aod::BCsWithTimestamps const &,
14431501 FemtoHFMcTracks const & tracks,
14441502 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1445- aod::McParticles const &,
1503+ aod::McParticles const & mcParticles ,
14461504 soa::Join<CandidateLcMc,
14471505 aod::HfMlLcToPKPi> const & candidates)
14481506 {
14491507 // get magnetic field for run
14501508 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1451- fillCharmHadronTable<DecayChannel::LcToPKPi, true , true >(col, tracks, fullV0s, candidates);
1509+ fillCharmHadronTable<DecayChannel::LcToPKPi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
14521510 }
14531511 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcLcToPKPiWithML, " Provide Mc for lctopkpi with ml" , false );
14541512
0 commit comments