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"
5960
6061#include < TH1.h>
6162#include < TMCProcess.h>
63+ #include < TPDGCode.h>
6264
6365#include < array>
6466#include < chrono>
@@ -494,8 +496,47 @@ struct HfProducerCharmHadronsV0FemtoDream {
494496 }
495497 }
496498
499+ // / Classify the MC origin of a V0 candidate.
500+ // / The heavy-flavour feed-down is identified with RecoDecay::getParticleOrigin, which also
501+ // / covers charm- and beauty-hadron decays flagged as physical primaries. The feed-down from
502+ // / a phi decay is light-flavour and kept as a separate class, since the relatively long phi
503+ // / lifetime makes it a distinct source.
504+ // / \param mcParticles table of the MC particles
505+ // / \param particleMc MC particle matched to the V0 candidate
506+ // / \param isFromPhi true if the K0S comes from a phi decay chain
507+ // / \return the origin according to ParticleOriginMCTruth (kPrimary, kMaterial,
508+ // / kSecondaryFromHF, kSecondaryFromLF or kSecondaryFromPhi)
509+ template <typename T>
510+ static int getK0sOrigin (T const & mcParticles, typename T::iterator const & particleMc, const bool isFromPhi)
511+ {
512+ using namespace o2 ::aod::femtodreamMCparticle;
513+ constexpr int GenFromTransport = -1 ;
514+ const auto process = particleMc.getProcess ();
515+ // hadronic interaction in the detector material
516+ if (process == TMCProcess::kPHInhelastic && particleMc.getGenStatusCode () == GenFromTransport) {
517+ return kMaterial ;
518+ }
519+ // charm- or beauty-hadron anywhere in the mother chain (feed-down can be a physical primary)
520+ if (RecoDecay::getParticleOrigin (mcParticles, particleMc, false ) != RecoDecay::OriginType::None) {
521+ return kSecondaryFromHF ;
522+ }
523+ // phi -> K0/K0bar -> K0S is light-flavour feed-down, but kept as a separate class because
524+ // the relatively long phi lifetime makes it a distinct source (also flagged as a physical primary)
525+ if (isFromPhi) {
526+ return kSecondaryFromPhi ;
527+ }
528+ if (particleMc.isPhysicalPrimary ()) {
529+ return kPrimary ;
530+ }
531+ // weak decay of a light-flavour hadron during the transport
532+ if (process == TMCProcess::kPDecay && particleMc.getGenStatusCode () == GenFromTransport && particleMc.has_mothers ()) {
533+ return kSecondaryFromLF ;
534+ }
535+ return kElse ;
536+ }
537+
497538 template <typename CollisionType, typename ParticleType>
498- void fillMcParticle (CollisionType const & col, ParticleType const & particle, o2::aod::femtodreamparticle::ParticleType fdparttype)
539+ void fillMcParticle (CollisionType const & col, ParticleType const & particle, o2::aod::femtodreamparticle::ParticleType fdparttype, aod::McParticles const & mcParticles )
499540 {
500541 if (particle.has_mcParticle ()) {
501542 // get corresponding MC particle and its info
@@ -510,6 +551,19 @@ struct HfProducerCharmHadronsV0FemtoDream {
510551 float etaPos{-1 .f }, etaNeg{-1 .f };
511552 float phiPos{-1 .f }, phiNeg{-1 .f };
512553 int pdgCodePos{0 }, pdgCodeNeg{0 };
554+ // phi -> K0/K0bar -> K0s (or phi -> K0s directly); the heavy-flavour feed-down is
555+ // handled in getK0sOrigin through RecoDecay::getParticleOrigin
556+ bool isFromPhi = false ;
557+ if (fdparttype == o2::aod::femtodreamparticle::ParticleType::kV0 && !motherparticlesMc.empty ()) {
558+ const auto absPdgMother = std::abs (motherparticlesMc.front ().pdgCode ());
559+ if (absPdgMother == o2::constants::physics::Pdg::kPhi ) {
560+ isFromPhi = true ;
561+ } else if (absPdgMother == kK0 ) {
562+ const auto & grandMothersMc = motherparticlesMc.front ().template mothers_as <aod::McParticles>();
563+ isFromPhi = !grandMothersMc.empty () && std::abs (grandMothersMc.front ().pdgCode ()) == o2::constants::physics::Pdg::kPhi ;
564+ }
565+ }
566+
513567 // check pdg code
514568 // if this fails, the particle is a fake
515569 if (std::abs (pdgCode) == std::abs (v0PDGCode.value )) {
@@ -518,6 +572,11 @@ struct HfProducerCharmHadronsV0FemtoDream {
518572 if ((col.has_mcCollision () && (particleMc.mcCollisionId () != col.mcCollisionId ())) || !col.has_mcCollision ()) {
519573 particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kWrongCollision ;
520574 // check if particle is primary
575+ } else if (fdparttype == o2::aod::femtodreamparticle::ParticleType::kV0 ) {
576+ particleOrigin = getK0sOrigin (mcParticles, particleMc, isFromPhi);
577+ if (!motherparticlesMc.empty ()) {
578+ pdgCodeMother = motherparticlesMc.front ().pdgCode ();
579+ }
521580 } else if (particleMc.isPhysicalPrimary ()) {
522581 particleOrigin = aod::femtodreamMCparticle::ParticleOriginMCTruth::kPrimary ;
523582 // check if particle is secondary
@@ -612,7 +671,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
612671 }
613672
614673 template <bool IsMc = false , typename V0Type, typename CollisionType, typename TrackType>
615- bool fillV0sForCharmHadron (CollisionType const & col, V0Type const & fullV0s, TrackType const & /* tracks*/ )
674+ bool fillV0sForCharmHadron (CollisionType const & col, V0Type const & fullV0s, TrackType const & /* tracks*/ , aod::McParticles const * mcParticles = nullptr )
616675 {
617676 const bool isK0S = (selectionFlagV0 == V0Channel::K0S );
618677 const bool isLambda = (selectionFlagV0 == V0Channel::Lambda);
@@ -724,15 +783,15 @@ struct HfProducerCharmHadronsV0FemtoDream {
724783 }
725784
726785 if constexpr (IsMc) {
727- fillMcParticle (col, v0, o2::aod::femtodreamparticle::ParticleType::kV0 );
786+ fillMcParticle (col, v0, o2::aod::femtodreamparticle::ParticleType::kV0 , *mcParticles );
728787 }
729788 fIsV0Filled = true ;
730789 }
731790 return fIsV0Filled ;
732791 }
733792
734793 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)
794+ void fillCharmHadronTable (CollisionType const & col, TrackType const & tracks, V0Type const & fullV0s, CandType const & candidates, aod::McParticles const * mcParticles = nullptr )
736795 {
737796 const auto vtxZ = col.posZ ();
738797 const auto sizeCand = candidates.size ();
@@ -1019,7 +1078,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
10191078 fillTable (2 , candidate.isSelDstarToD0Pi (), outputMlDstar.at (0 ), outputMlDstar.at (1 ), outputMlDstar.at (2 ));
10201079 }
10211080 }
1022- isV0Filled = fillV0sForCharmHadron<IsMc>(col, fullV0s, tracks);
1081+ isV0Filled = fillV0sForCharmHadron<IsMc>(col, fullV0s, tracks, mcParticles );
10231082 aod::femtodreamcollision::BitMaskType bitV0 = 0 ;
10241083 if (isV0Filled) {
10251084 bitV0 |= 1 << 0 ;
@@ -1248,26 +1307,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
12481307 aod::BCsWithTimestamps const &,
12491308 FemtoHFMcTracks const & tracks,
12501309 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1251- aod::McParticles const &,
1310+ aod::McParticles const & mcParticles ,
12521311 CandidateD0Mc const & candidates)
12531312 {
12541313 // get magnetic field for run
12551314 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1256- fillCharmHadronTable<DecayChannel::D0ToPiK, true , false >(col, tracks, fullV0s, candidates);
1315+ fillCharmHadronTable<DecayChannel::D0ToPiK, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
12571316 }
12581317 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcD0ToPiK, " Provide Mc for D0ToPiK" , false );
12591318
12601319 void processMcD0ToPiKWithML (FemtoFullCollisionMc const & col,
12611320 aod::BCsWithTimestamps const &,
12621321 FemtoHFMcTracks const & tracks,
12631322 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1264- aod::McParticles const &,
1323+ aod::McParticles const & mcParticles ,
12651324 soa::Join<CandidateD0Mc,
12661325 aod::HfMlD0> const & candidates)
12671326 {
12681327 // get magnetic field for run
12691328 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1270- fillCharmHadronTable<DecayChannel::D0ToPiK, true , true >(col, tracks, fullV0s, candidates);
1329+ fillCharmHadronTable<DecayChannel::D0ToPiK, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
12711330 }
12721331 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcD0ToPiKWithML, " Provide Mc for D0ToPiK with ml" , false );
12731332
@@ -1307,26 +1366,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
13071366 aod::BCsWithTimestamps const &,
13081367 FemtoHFMcTracks const & tracks,
13091368 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1310- aod::McParticles const &,
1369+ aod::McParticles const & mcParticles ,
13111370 CandidateDstarMc const & candidates)
13121371 {
13131372 // get magnetic field for run
13141373 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1315- fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , false >(col, tracks, fullV0s, candidates);
1374+ fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
13161375 }
13171376 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDstarToD0Pi, " Provide Mc for DstarToD0Pi" , false );
13181377
13191378 void processMcDstarToD0PiWithML (FemtoFullCollisionMc const & col,
13201379 aod::BCsWithTimestamps const &,
13211380 FemtoHFMcTracks const & tracks,
13221381 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1323- aod::McParticles const &,
1382+ aod::McParticles const & mcParticles ,
13241383 soa::Join<CandidateDstarMc,
13251384 aod::HfMlDstarToD0Pi> const & candidates)
13261385 {
13271386 // get magnetic field for run
13281387 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1329- fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , true >(col, tracks, fullV0s, candidates);
1388+ fillCharmHadronTable<DecayChannel::DstarToD0Pi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
13301389 }
13311390 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDstarToD0PiWithML, " Provide Mc for DstarToD0Pi with ml" , false );
13321391
@@ -1368,26 +1427,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
13681427 aod::BCsWithTimestamps const &,
13691428 FemtoHFMcTracks const & tracks,
13701429 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1371- aod::McParticles const &,
1430+ aod::McParticles const & mcParticles ,
13721431 CandidateDplusMc const & candidates)
13731432 {
13741433 // get magnetic field for run
13751434 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1376- fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , false >(col, tracks, fullV0s, candidates);
1435+ fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
13771436 }
13781437 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDplusToPiKPi, " Provide Mc for DplusToPiKPi" , false );
13791438
13801439 void processMcDplusToPiKPiWithML (FemtoFullCollisionMc const & col,
13811440 aod::BCsWithTimestamps const &,
13821441 FemtoHFMcTracks const & tracks,
13831442 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1384- aod::McParticles const &,
1443+ aod::McParticles const & mcParticles ,
13851444 soa::Join<CandidateDplusMc,
13861445 aod::HfMlDplusToPiKPi> const & candidates)
13871446 {
13881447 // get magnetic field for run
13891448 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1390- fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , true >(col, tracks, fullV0s, candidates);
1449+ fillCharmHadronTable<DecayChannel::DplusToPiKPi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
13911450 }
13921451 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcDplusToPiKPiWithML, " Provide Mc for DplusToPiKPi with ml" , false );
13931452
@@ -1429,26 +1488,26 @@ struct HfProducerCharmHadronsV0FemtoDream {
14291488 aod::BCsWithTimestamps const &,
14301489 FemtoHFMcTracks const & tracks,
14311490 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1432- aod::McParticles const &,
1491+ aod::McParticles const & mcParticles ,
14331492 CandidateLcMc const & candidates)
14341493 {
14351494 // get magnetic field for run
14361495 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1437- fillCharmHadronTable<DecayChannel::LcToPKPi, true , false >(col, tracks, fullV0s, candidates);
1496+ fillCharmHadronTable<DecayChannel::LcToPKPi, true , false >(col, tracks, fullV0s, candidates, &mcParticles );
14381497 }
14391498 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcLcToPKPi, " Provide Mc for lctopkpi" , false );
14401499
14411500 void processMcLcToPKPiWithML (FemtoFullCollisionMc const & col,
14421501 aod::BCsWithTimestamps const &,
14431502 FemtoHFMcTracks const & tracks,
14441503 soa::Join<o2::aod::V0Datas, aod::McV0Labels> const & fullV0s,
1445- aod::McParticles const &,
1504+ aod::McParticles const & mcParticles ,
14461505 soa::Join<CandidateLcMc,
14471506 aod::HfMlLcToPKPi> const & candidates)
14481507 {
14491508 // get magnetic field for run
14501509 getMagneticFieldTesla (col.bc_as <aod::BCsWithTimestamps>());
1451- fillCharmHadronTable<DecayChannel::LcToPKPi, true , true >(col, tracks, fullV0s, candidates);
1510+ fillCharmHadronTable<DecayChannel::LcToPKPi, true , true >(col, tracks, fullV0s, candidates, &mcParticles );
14521511 }
14531512 PROCESS_SWITCH (HfProducerCharmHadronsV0FemtoDream, processMcLcToPKPiWithML, " Provide Mc for lctopkpi with ml" , false );
14541513
0 commit comments