@@ -98,8 +98,10 @@ enum DecayChannel { DplusToPiKPi = 0,
9898 DstarToD0Pi
9999};
100100
101- enum V0Channel { K0S = 0 ,
102- Lambda
101+ enum V0Channel {
102+ None = 0 ,
103+ K0S,
104+ Lambda
103105};
104106
105107struct HfProducerCharmHadronsV0FemtoDream {
@@ -135,12 +137,12 @@ struct HfProducerCharmHadronsV0FemtoDream {
135137
136138 Configurable<bool > isDebug{" isDebug" , true , " Enable Debug tables" };
137139 Configurable<bool > isRun3{" isRun3" , true , " Running on Run3 or pilot" };
138- Configurable<bool > selectionFlagV0{" selectionFlagV0" , 0 , " Activate filling of V0: 0 for K0S, 1 for Lambda" };
140+ Configurable<int > selectionFlagV0{" selectionFlagV0" , 1 , " Activate filling of V0: 0 for none, 1 for K0S, 2 for Lambda" };
139141 // / Charm hadron table
140142 Configurable<int > selectionFlagCharmHadron{" selectionFlagCharmHadron" , 1 , " Selection Flag for Charm Hadron: 1 for Lc, 7 for Dplus (Topologic and PID cuts)" };
141143 Configurable<bool > useCent{" useCent" , false , " Enable centrality for Charm Hadron" };
142144
143- Configurable<int > v0PDGCode{" v0PDGCode" , 2212 , " PDG code of the selected track for Monte Carlo truth" };
145+ Configurable<int > v0PDGCode{" v0PDGCode" , 310 , " PDG code of the selected V0 (310: K0S, 3122: Lambda) for Monte Carlo truth " };
144146 Configurable<float > trkPIDnSigmaOffsetTPC{" trkPIDnSigmaOffsetTPC" , 0 ., " Offset for TPC nSigma because of bad calibration" }; // set to zero for run3 or so
145147 Configurable<float > trkPIDnSigmaOffsetTOF{" trkPIDnSigmaOffsetTOF" , 0 ., " Offset for TOF nSigma because of bad calibration" };
146148 Configurable<bool > trkRejectNotPropagated{" trkRejectNotPropagated" , false , " True: reject not propagated tracks" };
@@ -193,7 +195,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
193195 Configurable<std::vector<float >> confK0shortChildTPCnClsMin{" confK0shortChildTPCnClsMin" , std::vector<float >{80 .f , 70 .f , 60 .f }, " V0 Child sel: Min. nCls TPC" };
194196 Configurable<std::vector<float >> confK0shortChildDCAMin{" confK0shortChildDCAMin" , std::vector<float >{0 .05f , 0 .06f }, " V0 Child sel: Max. DCA Daugh to PV (cm)" };
195197 Configurable<std::vector<float >> confK0shortChildPIDnSigmaMax{" confK0shortChildPIDnSigmaMax" , std::vector<float >{5 .f , 4 .f }, " V0 Child sel: Max. PID nSigma TPC" };
196- Configurable<std::vector<int >> confK0shortChildPIDspecies{" confK0shortChildPIDspecies" , std::vector<int >{o2::track::PID::Pion, o2::track::PID::Proton }, " V0 Child sel: Particles species for PID" };
198+ Configurable<std::vector<int >> confK0shortChildPIDspecies{" confK0shortChildPIDspecies" , std::vector<int >{o2::track::PID::Pion, o2::track::PID::Pion }, " V0 Child sel: Particles species for PID" };
197199 } V0Sel;
198200
199201 // ML inference
@@ -431,7 +433,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
431433 }
432434
433435 template <bool isTrackOrV0, typename ParticleType>
434- void fillDebugParticle (ParticleType const & particle)
436+ void fillDebugParticle (ParticleType const & particle, int const & signV0 = 0 )
435437 {
436438 if constexpr (isTrackOrV0) {
437439 outputDebugParts (particle.sign (),
@@ -464,7 +466,8 @@ struct HfProducerCharmHadronsV0FemtoDream {
464466 -999 ., -999 ., -999 ., -999 .,
465467 -999 ., -999 ., -999 .);
466468 } else {
467- outputDebugParts (-999 ., // sign
469+ auto sign = signV0;
470+ outputDebugParts (sign, // sign
468471 -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., // track properties (DCA, NCls, crossed rows, etc.)
469472 -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., // TPC PID (TPC signal + particle hypothesis)
470473 -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., -999 ., // TOF PID
@@ -551,11 +554,11 @@ struct HfProducerCharmHadronsV0FemtoDream {
551554 }
552555
553556 template <bool IsMc = false , typename V0Type, typename CollisionType, typename TrackType>
554- bool fillV0sForCharmHadron (CollisionType const & col, V0Type const & fullV0s, TrackType const &)
557+ bool fillV0sForCharmHadron (CollisionType const & col, V0Type const & fullV0s, TrackType const & /* tracks */ )
555558 {
556559 const bool isK0S = (selectionFlagV0 == V0Channel::K0S);
557- const bool isLam = (selectionFlagV0 == V0Channel::Lambda);
558- if (!isK0S && !isLam ) {
560+ const bool isLambda = (selectionFlagV0 == V0Channel::Lambda);
561+ if (!isK0S && !isLambda ) {
559562 LOG (fatal) << " Invalid V0 particle !! Please check the configuration" ;
560563 }
561564
@@ -567,6 +570,7 @@ struct HfProducerCharmHadronsV0FemtoDream {
567570 int64_t timeStamp = bc.timestamp ();
568571
569572 for (const auto & v0 : fullV0s) {
573+
570574 auto postrack = v0.template posTrack_as <TrackType>();
571575 auto negtrack = v0.template negTrack_as <TrackType>();
572576
@@ -586,7 +590,6 @@ struct HfProducerCharmHadronsV0FemtoDream {
586590 cutContainerV0 = K0SCuts.getCutContainer <aod::femtodreamparticle::cutContainerType>(col, v0, postrack, negtrack);
587591 massV0 = v0.mK0Short ();
588592 antiMassV0 = v0.mK0Short ();
589-
590593 } else { // Lambda
591594 LambdaCuts.fillLambdaQA <aod::femtodreamparticle::ParticleType::kV0 >(col, v0, postrack, negtrack);
592595 if (!LambdaCuts.isSelectedMinimal (col, v0, postrack, negtrack)) {
@@ -599,18 +602,15 @@ struct HfProducerCharmHadronsV0FemtoDream {
599602 antiMassV0 = v0.mAntiLambda ();
600603 }
601604
602- int rowPos = getRowDaughters (v0.posTrackId (), tmpIDtrack);
603- int rowNeg = getRowDaughters (v0.negTrackId (), tmpIDtrack);
604- if (rowPos < 0 || rowNeg < 0 )
605- continue ;
606-
607605 // --- pos child
606+ int rowPos = getRowDaughters (v0.posTrackId (), tmpIDtrack);
608607 childIDs[0 ] = rowPos;
609608 childIDs[1 ] = 0 ;
610609
611610 auto daughType = isK0S ? aod::femtodreamparticle::ParticleType::kV0K0ShortChild
612611 : aod::femtodreamparticle::ParticleType::kV0Child ;
613-
612+ outputPartsTime (timeStamp);
613+ outputPartsIndex (v0.posTrackId ());
614614 outputParts (outputCollision.lastIndex (),
615615 v0.positivept (), v0.positiveeta (), v0.positivephi (),
616616 daughType,
@@ -623,9 +623,11 @@ struct HfProducerCharmHadronsV0FemtoDream {
623623 const int rowOfPosTrack = outputParts.lastIndex ();
624624
625625 // --- neg child
626+ int rowNeg = getRowDaughters (v0.negTrackId (), tmpIDtrack);
626627 childIDs[0 ] = 0 ;
627628 childIDs[1 ] = rowNeg;
628-
629+ outputPartsTime (timeStamp);
630+ outputPartsIndex (v0.negTrackId ());
629631 outputParts (outputCollision.lastIndex (),
630632 v0.negativept (), v0.negativeeta (), v0.negativephi (),
631633 daughType,
@@ -641,7 +643,8 @@ struct HfProducerCharmHadronsV0FemtoDream {
641643 std::vector<int > indexChildID = {rowOfPosTrack, rowOfNegTrack};
642644 auto motherType = isK0S ? aod::femtodreamparticle::ParticleType::kV0K0Short
643645 : aod::femtodreamparticle::ParticleType::kV0 ;
644-
646+ outputPartsTime (timeStamp);
647+ outputPartsIndex (v0.globalIndex ());
645648 outputParts (outputCollision.lastIndex (),
646649 v0.pt (), v0.eta (), v0.phi (),
647650 motherType,
@@ -651,20 +654,17 @@ struct HfProducerCharmHadronsV0FemtoDream {
651654 indexChildID,
652655 massV0,
653656 antiMassV0);
654-
655- outputPartsTime (timeStamp);
656- outputPartsIndex (v0.globalIndex ());
657+ auto signV0 = determineV0Sign (v0, postrack, negtrack);
657658
658659 if (isDebug.value ) {
659660 fillDebugParticle<true >(postrack);
660661 fillDebugParticle<true >(negtrack);
661- fillDebugParticle<false >(v0);
662+ fillDebugParticle<false >(v0, signV0 );
662663 }
663664
664665 if constexpr (IsMc) {
665666 fillMcParticle (col, v0, o2::aod::femtodreamparticle::ParticleType::kV0 );
666667 }
667-
668668 fIsV0Filled = true ;
669669 }
670670 return fIsV0Filled ;
@@ -771,10 +771,18 @@ struct HfProducerCharmHadronsV0FemtoDream {
771771 bdtScoreFd);
772772
773773 } else if constexpr (Channel == DecayChannel::D0ToPiK) {
774+ int signD0 = 0 ;
775+ if (candFlag == 0 ) {
776+ signD0 = +1 ; // D0
777+ } else if (candFlag == 1 ) {
778+ signD0 = -1 ; // anti-D0
779+ } else {
780+ LOG (error) << " Unexpected candFlag = " << candFlag;
781+ }
774782 rowCandCharm2Prong (
775783 outputCollision.lastIndex (),
776784 timeStamp,
777- trackPos1. sign () + trackNeg. sign () ,
785+ signD0 ,
778786 trackPos1.globalIndex (),
779787 trackNeg.globalIndex (),
780788 trackPos1.pt (),
@@ -945,7 +953,6 @@ struct HfProducerCharmHadronsV0FemtoDream {
945953 }
946954 }
947955 isV0Filled = fillV0sForCharmHadron<IsMc>(col, fullV0s, tracks);
948-
949956 aod::femtodreamcollision::BitMaskType bitV0 = 0 ;
950957 if (isV0Filled) {
951958 bitV0 |= 1 << 0 ;
@@ -967,6 +974,58 @@ struct HfProducerCharmHadronsV0FemtoDream {
967974 0 );
968975 }
969976
977+ template <typename V0Type, typename TrackType>
978+ int determineV0Sign (V0Type const & v0, TrackType const & posTrack, TrackType const & negTrack)
979+ {
980+ const bool isK0S = (selectionFlagV0 == V0Channel::K0S);
981+ const bool isLambda = (selectionFlagV0 == V0Channel::Lambda);
982+ if (!isK0S && !isLambda) {
983+ LOG (fatal) << " Invalid V0 particle !! Please check the configuration" ;
984+ }
985+ // K0S self-conjugate: keep your convention
986+ if (isK0S) {
987+ return +1 ;
988+ }
989+
990+ // Lambda / Anti-Lambda case
991+
992+ const float mLamPDG = o2::constants::physics::MassLambda;
993+ const float mLamHyp = v0.mLambda ();
994+ const float mAntiLamHyp = v0.mAntiLambda ();
995+
996+ const float diffLam = std::abs (mLamPDG - mLamHyp );
997+ const float diffAntiLam = std::abs (mLamPDG - mAntiLamHyp );
998+
999+ const float offTPC = trkPIDnSigmaOffsetTPC.value ;
1000+ const float nSigmaPIDMax = V0Sel.confLambdaChildPIDnSigmaMax .value [0 ];
1001+
1002+ // TPC n-sigma (apply offset by subtraction)
1003+ const float prNeg = negTrack.tpcNSigmaPr () - offTPC;
1004+ const float piPos = posTrack.tpcNSigmaPi () - offTPC;
1005+ const float piNeg = negTrack.tpcNSigmaPi () - offTPC;
1006+ const float prPos = posTrack.tpcNSigmaPr () - offTPC;
1007+
1008+ const bool pidAntiLam = (std::abs (prNeg) < nSigmaPIDMax) && (std::abs (piPos) < nSigmaPIDMax);
1009+ const bool pidLam = (std::abs (prPos) < nSigmaPIDMax) && (std::abs (piNeg) < nSigmaPIDMax);
1010+
1011+ int sign = 0 ; // 0 = undecided
1012+
1013+ // prefer: PID + mass preference (closer to PDG)
1014+ if (pidAntiLam && (diffAntiLam < diffLam)) {
1015+ sign = -1 ;
1016+ } else if (pidLam && (diffLam <= diffAntiLam)) {
1017+ sign = +1 ;
1018+ } else {
1019+ // fallback: PID only
1020+ if (pidAntiLam) {
1021+ sign = -1 ;
1022+ } else {
1023+ sign = +1 ;
1024+ }
1025+ }
1026+ return sign;
1027+ }
1028+
9701029 // check if there is no selected v0
9711030 // / \param C type of the collision
9721031 // / \param T type of the V0s
0 commit comments