@@ -65,6 +65,17 @@ struct HfTaskLc {
6565 Configurable<bool > fillTHn{" fillTHn" , false , " fill THn" };
6666 Configurable<bool > storeOccupancy{" storeOccupancy" , true , " Flag to store occupancy information" };
6767 Configurable<int > occEstimator{" occEstimator" , 2 , " Occupancy estimation (None: 0, ITS: 1, FT0C: 2)" };
68+ Configurable<bool > storeProperLifetime{" storeProperLifetime" , false , " Flag to store proper lifetime" };
69+
70+ constexpr static float CtToProperLifetimePs = 1 .f / o2::constants::physics::LightSpeedCm2PS;
71+ constexpr static float NanoToPico = 1000 .f;
72+
73+ enum MlClasses : int {
74+ MlClassBackground = 0 ,
75+ MlClassPrompt,
76+ MlClassNonPrompt,
77+ NumberOfMlClasses
78+ };
6879
6980 HfHelper hfHelper;
7081 SliceCache cache;
@@ -100,6 +111,7 @@ struct HfTaskLc {
100111 ConfigurableAxis thnConfigAxisGenPtB{" thnConfigAxisGenPtB" , {1000 , 0 , 100 }, " Gen Pt B" };
101112 ConfigurableAxis thnConfigAxisNumPvContr{" thnConfigAxisNumPvContr" , {200 , -0.5 , 199.5 }, " Number of PV contributors" };
102113 ConfigurableAxis thnConfigAxisOccupancy{" thnConfigAxisOccupancy" , {14 , 0 , 14000 }, " axis for centrality" };
114+ ConfigurableAxis thnConfigAxisProperLifetime{" thnConfigAxisProperLifetime" , {200 , 0 , 2 }, " Proper lifetime, ps" };
103115
104116 HistogramRegistry registry{
105117 " registry" ,
@@ -317,6 +329,7 @@ struct HfTaskLc {
317329 const AxisSpec thnAxisPtB{thnConfigAxisGenPtB, " #it{p}_{T}^{B} (GeV/#it{c})" };
318330 const AxisSpec thnAxisTracklets{thnConfigAxisNumPvContr, " Number of PV contributors" };
319331 const AxisSpec thnAxisOccupancy{thnConfigAxisOccupancy, " Occupancy" };
332+ const AxisSpec thnAxisProperLifetime{thnConfigAxisProperLifetime, " T_{proper} (ps)" };
320333
321334 bool isDataWithMl = doprocessDataWithMl || doprocessDataWithMlWithFT0C || doprocessDataWithMlWithFT0M;
322335 bool isMcWithMl = doprocessMcWithMl || doprocessMcWithMlWithFT0C || doprocessMcWithMlWithFT0M;
@@ -342,12 +355,18 @@ struct HfTaskLc {
342355 }
343356
344357 if (storeOccupancy) {
345- if (!axesWithBdt.empty ())
346- axesWithBdt.push_back (thnAxisOccupancy);
347- if (!axesStd.empty ())
348- axesStd.push_back (thnAxisOccupancy);
349- if (!axesGen.empty ())
350- axesGen.push_back (thnAxisOccupancy);
358+ for (const auto & axes : std::array<std::vector<AxisSpec>*, 3 >{&axesWithBdt, &axesStd, &axesGen}) {
359+ if (!axes->empty ()) {
360+ axes->push_back (thnAxisOccupancy);
361+ }
362+ }
363+ }
364+ if (storeProperLifetime) {
365+ for (const auto & axes : std::array<std::vector<AxisSpec>*, 3 >{&axesWithBdt, &axesStd, &axesGen}) {
366+ if (!axes->empty ()) {
367+ axes->push_back (thnAxisProperLifetime);
368+ }
369+ }
351370 }
352371
353372 if (isDataWithMl) {
@@ -542,55 +561,63 @@ struct HfTaskLc {
542561 }
543562 double massLc (-1 );
544563 double outputBkg (-1 ), outputPrompt (-1 ), outputFD (-1 );
564+ const float properLifetime = hfHelper.ctLc (candidate) * CtToProperLifetimePs;
545565 if ((candidate.isSelLcToPKPi () >= selectionFlagLc) && pdgCodeProng0 == kProton ) {
546566 massLc = hfHelper.invMassLcToPKPi (candidate);
547567
548568 if constexpr (fillMl) {
549- if (candidate.mlProbLcToPKPi ().size () == 3 ) {
550- outputBkg = candidate.mlProbLcToPKPi ()[0 ]; // / bkg score
551- outputPrompt = candidate.mlProbLcToPKPi ()[1 ]; // / prompt score
552- outputFD = candidate.mlProbLcToPKPi ()[2 ]; // / non-prompt score
569+ if (candidate.mlProbLcToPKPi ().size () == NumberOfMlClasses ) {
570+ outputBkg = candidate.mlProbLcToPKPi ()[MlClassBackground]; // / bkg score
571+ outputPrompt = candidate.mlProbLcToPKPi ()[MlClassPrompt]; // / prompt score
572+ outputFD = candidate.mlProbLcToPKPi ()[MlClassNonPrompt]; // / non-prompt score
553573 }
554574 // / Fill the ML outputScores and variables of candidate
575+ std::vector<double > valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast <double >(numPvContributors), ptRecB, static_cast <double >(originType)};
555576 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
556- registry.get <THnSparse>(HIST (" hnLcVarsWithBdt" ))->Fill (massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, ptRecB, originType, occ);
557- } else {
558- registry.get <THnSparse>(HIST (" hnLcVarsWithBdt" ))->Fill (massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, ptRecB, originType);
577+ valuesToFill.push_back (occ);
559578 }
560-
579+ if (storeProperLifetime) {
580+ valuesToFill.push_back (properLifetime);
581+ }
582+ registry.get <THnSparse>(HIST (" hnLcVarsWithBdt" ))->Fill (valuesToFill.data ());
561583 } else {
562-
584+ std::vector< double > valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast < double >(numPvContributors), ptRecB, static_cast < double >(originType)};
563585 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
564- registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, ptRecB, originType, occ);
565-
566- } else {
567-
568- registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, ptRecB, originType);
586+ valuesToFill.push_back (occ);
587+ }
588+ if (storeProperLifetime) {
589+ valuesToFill.push_back (properLifetime);
569590 }
591+ registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (valuesToFill.data ());
570592 }
571593 }
572594 if ((candidate.isSelLcToPiKP () >= selectionFlagLc) && pdgCodeProng0 == kPiPlus ) {
573595 massLc = hfHelper.invMassLcToPiKP (candidate);
574596
575597 if constexpr (fillMl) {
576- if (candidate.mlProbLcToPiKP ().size () == 3 ) {
577- outputBkg = candidate.mlProbLcToPiKP ()[0 ]; // / bkg score
578- outputPrompt = candidate.mlProbLcToPiKP ()[1 ]; // / prompt score
579- outputFD = candidate.mlProbLcToPiKP ()[2 ]; // / non-prompt score
598+ if (candidate.mlProbLcToPiKP ().size () == NumberOfMlClasses ) {
599+ outputBkg = candidate.mlProbLcToPiKP ()[MlClassBackground]; // / bkg score
600+ outputPrompt = candidate.mlProbLcToPiKP ()[MlClassPrompt]; // / prompt score
601+ outputFD = candidate.mlProbLcToPiKP ()[MlClassNonPrompt]; // / non-prompt score
580602 }
581603 // / Fill the ML outputScores and variables of candidate (todo: add multiplicity)
604+ std::vector<double > valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast <double >(numPvContributors), ptRecB, static_cast <double >(originType)};
582605 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
583- registry. get <THnSparse>( HIST ( " hnLcVarsWithBdt " ))-> Fill (massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, ptRecB, originType, occ);
584-
585- } else {
586- registry. get <THnSparse>( HIST ( " hnLcVarsWithBdt " ))-> Fill (massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, ptRecB, originType );
606+ valuesToFill. push_back ( occ);
607+ }
608+ if (storeProperLifetime) {
609+ valuesToFill. push_back (properLifetime );
587610 }
611+ registry.get <THnSparse>(HIST (" hnLcVarsWithBdt" ))->Fill (valuesToFill.data ());
588612 } else {
613+ std::vector<double > valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast <double >(numPvContributors), ptRecB, static_cast <double >(originType)};
589614 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
590- registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, ptRecB, originType, occ);
591- } else {
592- registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, ptRecB, originType);
615+ valuesToFill.push_back (occ);
593616 }
617+ if (storeProperLifetime) {
618+ valuesToFill.push_back (properLifetime);
619+ }
620+ registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (valuesToFill.data ());
594621 }
595622 }
596623 }
@@ -624,6 +651,11 @@ struct HfTaskLc {
624651 occ = o2::hf_occupancy::getOccupancyGenColl (recoCollsPerMcColl, occEstimator);
625652 }
626653
654+ const auto mcDaughter0 = particle.template daughters_as <soa::Join<aod::McParticles, aod::HfCand3ProngMcGen>>().begin ();
655+ const float p2m = particle.p () / o2::constants::physics::MassLambdaCPlus;
656+ const float gamma = std::sqrt (1 + p2m * p2m); // mother's particle Lorentz factor
657+ const float properLifetime = mcDaughter0.vt () * NanoToPico / gamma; // from ns to ps * from lab time to proper time
658+
627659 registry.fill (HIST (" MC/generated/signal/hPtGen" ), ptGen);
628660 registry.fill (HIST (" MC/generated/signal/hEtaGen" ), particle.eta ());
629661 registry.fill (HIST (" MC/generated/signal/hYGen" ), yGen);
@@ -634,12 +666,14 @@ struct HfTaskLc {
634666
635667 if (particle.originMcGen () == RecoDecay::OriginType::Prompt) {
636668 if (fillTHn) {
669+ std::vector<double > valuesToFill{ptGen, cent, yGen, static_cast <double >(numPvContributors), ptGenB, static_cast <double >(originType)};
637670 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
638- registry. get <THnSparse>( HIST ( " hnLcVarsGen " ))-> Fill (ptGen, cent, yGen, numPvContributors, ptGenB, originType, occ);
639-
640- } else {
641- registry. get <THnSparse>( HIST ( " hnLcVarsGen " ))-> Fill (ptGen, cent, yGen, numPvContributors, ptGenB, originType );
671+ valuesToFill. push_back ( occ);
672+ }
673+ if (storeProperLifetime) {
674+ valuesToFill. push_back (properLifetime );
642675 }
676+ registry.get <THnSparse>(HIST (" hnLcVarsGen" ))->Fill (valuesToFill.data ());
643677 }
644678 registry.fill (HIST (" MC/generated/prompt/hPtGenPrompt" ), ptGen);
645679 registry.fill (HIST (" MC/generated/prompt/hEtaGenPrompt" ), particle.eta ());
@@ -652,12 +686,14 @@ struct HfTaskLc {
652686 if (particle.originMcGen () == RecoDecay::OriginType::NonPrompt) {
653687 ptGenB = mcParticles.rawIteratorAt (particle.idxBhadMotherPart ()).pt ();
654688 if (fillTHn) {
689+ std::vector<double > valuesToFill{ptGen, cent, yGen, static_cast <double >(numPvContributors), ptGenB, static_cast <double >(originType)};
655690 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
656- registry.get <THnSparse>(HIST (" hnLcVarsGen" ))->Fill (ptGen, cent, yGen, numPvContributors, ptGenB, originType, occ);
657-
658- } else {
659- registry.get <THnSparse>(HIST (" hnLcVarsGen" ))->Fill (ptGen, cent, yGen, numPvContributors, ptGenB, originType);
691+ valuesToFill.push_back (occ);
660692 }
693+ if (storeProperLifetime) {
694+ valuesToFill.push_back (properLifetime);
695+ }
696+ registry.get <THnSparse>(HIST (" hnLcVarsGen" ))->Fill (valuesToFill.data ());
661697 }
662698 registry.fill (HIST (" MC/generated/nonprompt/hPtGenNonPrompt" ), ptGen);
663699 registry.fill (HIST (" MC/generated/nonprompt/hEtaGenNonPrompt" ), particle.eta ());
@@ -748,53 +784,63 @@ struct HfTaskLc {
748784 }
749785 double massLc (-1 );
750786 double outputBkg (-1 ), outputPrompt (-1 ), outputFD (-1 );
787+ const float properLifetime = hfHelper.ctLc (candidate) * CtToProperLifetimePs;
751788 if (candidate.isSelLcToPKPi () >= selectionFlagLc) {
752789 massLc = hfHelper.invMassLcToPKPi (candidate);
753790
754791 if constexpr (fillMl) {
755- if (candidate.mlProbLcToPKPi ().size () == 3 ) {
756- outputBkg = candidate.mlProbLcToPKPi ()[0 ]; // / bkg score
757- outputPrompt = candidate.mlProbLcToPKPi ()[1 ]; // / prompt score
758- outputFD = candidate.mlProbLcToPKPi ()[2 ]; // / non-prompt score
792+ if (candidate.mlProbLcToPKPi ().size () == NumberOfMlClasses ) {
793+ outputBkg = candidate.mlProbLcToPKPi ()[MlClassBackground]; // / bkg score
794+ outputPrompt = candidate.mlProbLcToPKPi ()[MlClassPrompt]; // / prompt score
795+ outputFD = candidate.mlProbLcToPKPi ()[MlClassNonPrompt]; // / non-prompt score
759796 }
760797 // / Fill the ML outputScores and variables of candidate
798+ std::vector<double > valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast <double >(numPvContributors)};
761799 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
762- registry. get <THnSparse>( HIST ( " hnLcVarsWithBdt " ))-> Fill (massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, occ);
763-
764- } else {
765- registry. get <THnSparse>( HIST ( " hnLcVarsWithBdt " ))-> Fill (massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors );
800+ valuesToFill. push_back ( occ);
801+ }
802+ if (storeProperLifetime) {
803+ valuesToFill. push_back (properLifetime );
766804 }
805+ registry.get <THnSparse>(HIST (" hnLcVarsWithBdt" ))->Fill (valuesToFill.data ());
767806 } else {
807+ std::vector<double > valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast <double >(numPvContributors)};
768808 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
769-
770- registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, occ);
771- } else {
772-
773- registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors);
809+ valuesToFill.push_back (occ);
810+ }
811+ if (storeProperLifetime) {
812+ valuesToFill.push_back (properLifetime);
774813 }
814+ registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (valuesToFill.data ());
775815 }
776816 }
777817 if (candidate.isSelLcToPiKP () >= selectionFlagLc) {
778818 massLc = hfHelper.invMassLcToPiKP (candidate);
779819
780820 if constexpr (fillMl) {
781- if (candidate.mlProbLcToPiKP ().size () == 3 ) {
782- outputBkg = candidate.mlProbLcToPiKP ()[0 ]; // / bkg score
783- outputPrompt = candidate.mlProbLcToPiKP ()[1 ]; // / prompt score
784- outputFD = candidate.mlProbLcToPiKP ()[2 ]; // / non-prompt score
821+ if (candidate.mlProbLcToPiKP ().size () == NumberOfMlClasses ) {
822+ outputBkg = candidate.mlProbLcToPiKP ()[MlClassBackground]; // / bkg score
823+ outputPrompt = candidate.mlProbLcToPiKP ()[MlClassPrompt]; // / prompt score
824+ outputFD = candidate.mlProbLcToPiKP ()[MlClassNonPrompt]; // / non-prompt score
785825 }
786826 // / Fill the ML outputScores and variables of candidate
827+ std::vector<double > valuesToFill{massLc, pt, cent, outputBkg, outputPrompt, outputFD, static_cast <double >(numPvContributors)};
787828 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
788- registry.get <THnSparse>(HIST (" hnLcVarsWithBdt" ))->Fill (massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors, occ);
789- } else {
790- registry.get <THnSparse>(HIST (" hnLcVarsWithBdt" ))->Fill (massLc, pt, cent, outputBkg, outputPrompt, outputFD, numPvContributors);
829+ valuesToFill.push_back (occ);
830+ }
831+ if (storeProperLifetime) {
832+ valuesToFill.push_back (properLifetime);
791833 }
834+ registry.get <THnSparse>(HIST (" hnLcVarsWithBdt" ))->Fill (valuesToFill.data ());
792835 } else {
836+ std::vector<double > valuesToFill{massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, static_cast <double >(numPvContributors)};
793837 if (storeOccupancy && occEstimator != o2::hf_occupancy::OccupancyEstimator::None) {
794- registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors, occ);
795- } else {
796- registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (massLc, pt, cent, ptProng0, ptProng1, ptProng2, chi2PCA, decayLength, cpa, numPvContributors);
838+ valuesToFill.push_back (occ);
839+ }
840+ if (storeProperLifetime) {
841+ valuesToFill.push_back (properLifetime);
797842 }
843+ registry.get <THnSparse>(HIST (" hnLcVars" ))->Fill (valuesToFill.data ());
798844 }
799845 }
800846 }
0 commit comments