@@ -120,6 +120,8 @@ static const std::vector<std::string> labelsCutScore = {"Background score", "Sig
120120
121121struct cascadeFlow {
122122
123+ PresliceUnsorted<soa::Join<aod::StraCollisions, aod::StraCents, aod::StraEvSels, aod::StraCollLabels>> perMcCollision = aod::v0data::straMCCollisionId;
124+
123125 // axes
124126 ConfigurableAxis axisQVs{" axisQVs" , {500 , -10 .f , 10 .f }, " axisQVs" };
125127 ConfigurableAxis axisQVsNorm{" axisQVsNorm" , {200 , -1 .f , 1 .f }, " axisQVsNorm" };
@@ -144,6 +146,7 @@ struct cascadeFlow {
144146 Configurable<float > nsigmatpcPr{" nsigmatpcPr" , 5 , " nsigmatpcPr" };
145147 Configurable<float > nsigmatpcPi{" nsigmatpcPi" , 5 , " nsigmatpcPi" };
146148 Configurable<float > mintpccrrows{" mintpccrrows" , 70 , " mintpccrrows" };
149+ Configurable<float > etaCascMCGen{" etaCascMCGen" , 0.8 , " etaCascMCGen" };
147150
148151 Configurable<std::string> ccdbUrl{" ccdbUrl" , " http://alice-ccdb.cern.ch" , " url of the ccdb repository" };
149152 Configurable<std::vector<std::string>> modelPathsCCDBXi{" modelPathsCCDBXi" , std::vector<std::string>{" Users/c/chdemart/CascadesFlow" }, " Paths of models on CCDB" };
@@ -255,6 +258,7 @@ struct cascadeFlow {
255258 }
256259
257260 HistogramRegistry histos{" histos" , {}, OutputObjHandlingPolicy::AnalysisObject};
261+ HistogramRegistry histosMCGen{" histosMCGen" , {}, OutputObjHandlingPolicy::AnalysisObject};
258262 HistogramRegistry resolution{" resolution" , {}, OutputObjHandlingPolicy::AnalysisObject};
259263
260264 // Tables to produce
@@ -298,7 +302,7 @@ struct cascadeFlow {
298302 }
299303
300304 template <class collision_t , class cascade_t >
301- void fillAnalysedTable (collision_t coll, cascade_t casc, float v2CSP, float v2CEP, float PsiT0C, float BDTresponseXi, float BDTresponseOmega)
305+ void fillAnalysedTable (collision_t coll, cascade_t casc, float v2CSP, float v2CEP, float PsiT0C, float BDTresponseXi, float BDTresponseOmega, int pdgCode )
302306 {
303307 double masses[2 ]{o2::constants::physics::MassXiMinus, o2::constants::physics::MassOmegaMinus};
304308 ROOT ::Math::PxPyPzMVector cascadeVector[2 ], lambdaVector, protonVector;
@@ -333,7 +337,8 @@ struct cascadeFlow {
333337 BDTresponseOmega,
334338 cosThetaStarLambda[0 ],
335339 cosThetaStarLambda[1 ],
336- cosThetaStarProton);
340+ cosThetaStarProton,
341+ pdgCode);
337342 }
338343
339344 void init (InitContext const &)
@@ -380,6 +385,11 @@ struct cascadeFlow {
380385 histos.add (" hcascminuspsiT0C" , " hcascminuspsiT0C" , HistType::kTH1F , {{100 , 0 , TMath::Pi ()}});
381386 histos.add (" hv2CEPvsFT0C" , " hv2CEPvsFT0C" , HistType::kTH2F , {CentAxis, {100 , -1 , 1 }});
382387 histos.add (" hv2CEPvsv2CSP" , " hv2CEPvsV2CSP" , HistType::kTH2F , {{100 , -1 , 1 }, {100 , -1 , 1 }});
388+
389+ histosMCGen.add (" h2DGenXi" , " h2DGenXi" , HistType::kTH2F , {{100 , 0 , 00 }, {200 , 0 , 20 }});
390+ histosMCGen.add (" h2DGenOmega" , " h2DGenOmega" , HistType::kTH2F , {{100 , 0 , 100 }, {200 , 0 , 20 }});
391+ histosMCGen.add (" hGenEta" , " hGenEta" , HistType::kTH1F , {{100 , -1 , 1 }});
392+
383393 for (int iS{0 }; iS < 2 ; ++iS) {
384394 cascadev2::hMassBeforeSelVsPt[iS] = histos.add <TH2 >(Form (" hMassBeforeSelVsPt%s" , cascadev2::speciesNames[iS].data ()), " hMassBeforeSelVsPt" , HistType::kTH2F , {massCascAxis[iS], ptAxis});
385395 cascadev2::hMassAfterSelVsPt[iS] = histos.add <TH2 >(Form (" hMassAfterSelVsPt%s" , cascadev2::speciesNames[iS].data ()), " hMassAfterSelVsPt" , HistType::kTH2F , {massCascAxis[iS], ptAxis});
@@ -610,7 +620,7 @@ struct cascadeFlow {
610620 BDTresponse[1 ] = bdtScore[1 ][1 ];
611621 }
612622 if (isSelectedCasc[0 ] || isSelectedCasc[1 ])
613- fillAnalysedTable (coll, casc, v2CSP, v2CEP, PsiT0C, BDTresponse[0 ], BDTresponse[1 ]);
623+ fillAnalysedTable (coll, casc, v2CSP, v2CEP, PsiT0C, BDTresponse[0 ], BDTresponse[1 ], 0 );
614624 }
615625 }
616626
@@ -738,14 +748,177 @@ struct cascadeFlow {
738748 BDTresponse[1 ] = bdtScore[1 ][1 ];
739749 }
740750 if (isSelectedCasc[0 ] || isSelectedCasc[1 ])
741- fillAnalysedTable (coll, casc, v2CSP, v2CEP, PsiT0C, BDTresponse[0 ], BDTresponse[1 ]);
751+ fillAnalysedTable (coll, casc, v2CSP, v2CEP, PsiT0C, BDTresponse[0 ], BDTresponse[1 ], 0 );
752+ }
753+ }
754+
755+ void processAnalyseMC (soa::Join<aod::StraCollisions, aod::StraCents, aod::StraEvSels, aod::StraRawCents>::iterator const & coll, CascMCCandidates const & Cascades, DauTracks const &, soa::Join<aod::CascMCCores, aod::CascMCCollRefs> const &)
756+ {
757+
758+ if (!AcceptEvent (coll)) {
759+ return ;
760+ }
761+
762+ histos.fill (HIST (" hNEvents" ), 7.5 );
763+ histos.fill (HIST (" hEventNchCorrelationAfterEP" ), coll.multNTracksPVeta1 (), coll.multNTracksGlobal ());
764+ histos.fill (HIST (" hEventPVcontributorsVsCentralityAfterEP" ), coll.centFT0C (), coll.multNTracksPVeta1 ());
765+ histos.fill (HIST (" hEventGlobalTracksVsCentralityAfterEP" ), coll.centFT0C (), coll.multNTracksGlobal ());
766+ histos.fill (HIST (" hEventCentrality" ), coll.centFT0C ());
767+ histos.fill (HIST (" hEventVertexZ" ), coll.posZ ());
768+
769+ std::vector<float > bdtScore[2 ];
770+ for (auto & casc : Cascades) {
771+
772+ if (!casc.has_cascMCCore ())
773+ continue ;
774+
775+ auto cascMC = casc.cascMCCore_as <soa::Join<aod::CascMCCores, aod::CascMCCollRefs>>();
776+ int pdgCode{cascMC.pdgCode ()};
777+ if (!(std::abs (pdgCode) == 3312 && std::abs (cascMC.pdgCodeV0 ()) == 3122 && std::abs (cascMC.pdgCodeBachelor ()) == 211 ) // Xi
778+ && !(std::abs (pdgCode) == 3334 && std::abs (cascMC.pdgCodeV0 ()) == 3122 && std::abs (cascMC.pdgCodeBachelor ()) == 321 )) // Omega
779+ {
780+ pdgCode = 0 ;
781+ }
782+
783+ // / Add some minimal cuts for single track variables (min number of TPC clusters)
784+ auto negExtra = casc.negTrackExtra_as <DauTracks>();
785+ auto posExtra = casc.posTrackExtra_as <DauTracks>();
786+ auto bachExtra = casc.bachTrackExtra_as <DauTracks>();
787+
788+ int counter = 0 ;
789+ IsCascAccepted (casc, negExtra, posExtra, bachExtra, counter);
790+ histos.fill (HIST (" hCascade" ), counter);
791+
792+ // ML selections
793+ bool isSelectedCasc[2 ]{false , false };
794+
795+ std::vector<float > inputFeaturesCasc{casc.cascradius (),
796+ casc.v0radius (),
797+ casc.casccosPA (coll.posX (), coll.posY (), coll.posZ ()),
798+ casc.v0cosPA (coll.posX (), coll.posY (), coll.posZ ()),
799+ casc.dcapostopv (),
800+ casc.dcanegtopv (),
801+ casc.dcabachtopv (),
802+ casc.dcacascdaughters (),
803+ casc.dcaV0daughters (),
804+ casc.dcav0topv (coll.posX (), coll.posY (), coll.posZ ()),
805+ casc.bachBaryonCosPA (),
806+ casc.bachBaryonDCAxyToPV ()};
807+
808+ float massCasc[2 ]{casc.mXi (), casc.mOmega ()};
809+
810+ // inv mass loose cut
811+ if (casc.pt () < MinPt || casc.pt () > MaxPt) {
812+ continue ;
813+ }
814+
815+ cascadev2::hMassBeforeSelVsPt[0 ]->Fill (massCasc[0 ], casc.pt ());
816+ cascadev2::hMassBeforeSelVsPt[1 ]->Fill (massCasc[1 ], casc.pt ());
817+
818+ if (isApplyML) {
819+ // Retrieve model output and selection outcome
820+ isSelectedCasc[0 ] = mlResponseXi.isSelectedMl (inputFeaturesCasc, casc.pt (), bdtScore[0 ]);
821+ isSelectedCasc[1 ] = mlResponseOmega.isSelectedMl (inputFeaturesCasc, casc.pt (), bdtScore[1 ]);
822+
823+ for (int iS{0 }; iS < 2 ; ++iS) {
824+ // Fill BDT score histograms before selection
825+ cascadev2::hSignalScoreBeforeSel[iS]->Fill (bdtScore[0 ][1 ]);
826+ cascadev2::hBkgScoreBeforeSel[iS]->Fill (bdtScore[1 ][0 ]);
827+
828+ // Fill histograms for selected candidates
829+ if (isSelectedCasc[iS]) {
830+ cascadev2::hSignalScoreAfterSel[iS]->Fill (bdtScore[0 ][1 ]);
831+ cascadev2::hBkgScoreAfterSel[iS]->Fill (bdtScore[1 ][0 ]);
832+ cascadev2::hMassAfterSelVsPt[iS]->Fill (massCasc[iS], casc.pt ());
833+ }
834+ }
835+ } else {
836+ isSelectedCasc[0 ] = true ;
837+ isSelectedCasc[1 ] = true ;
838+ }
839+
840+ histos.fill (HIST (" hCascadePhi" ), casc.phi ());
841+
842+ float BDTresponse[2 ]{0 .f , 0 .f };
843+ const float PsiT0C = 0 ; // not defined in MC for now
844+ auto v2CSP = 0 ; // not defined in MC for now
845+ auto v2CEP = 0 ; // not defined in MC for now
846+
847+ if (isApplyML) {
848+ BDTresponse[0 ] = bdtScore[0 ][1 ];
849+ BDTresponse[1 ] = bdtScore[1 ][1 ];
850+ }
851+ if (isSelectedCasc[0 ] || isSelectedCasc[1 ])
852+ fillAnalysedTable (coll, casc, v2CSP, v2CEP, PsiT0C, BDTresponse[0 ], BDTresponse[1 ], pdgCode);
853+ }
854+ }
855+ void processMCGen (soa::Join<aod::StraMCCollisions, aod::StraMCCollMults>::iterator const & mcCollision, soa::Join<aod::StraCollisions, aod::StraCents, aod::StraEvSels, aod::StraCollLabels> const & collisions, soa::Join<aod::CascMCCores, aod::CascMCCollRefs> const & CascMCCores)
856+ {
857+ // Generated with accepted z vertex
858+ if (TMath::Abs (mcCollision.posZ ()) > cutzvertex) {
859+ return ;
860+ }
861+
862+ // Check if there is at least one of the reconstructed collisions associated to this MC collision
863+ auto groupedCollisions = collisions.sliceBy (perMcCollision, mcCollision.globalIndex ());
864+ int biggestNContribs = -1 ;
865+ int bestCollisionIndex = -1 ;
866+ float centrality = 100 .5f ;
867+ int nCollisions = 0 ;
868+ for (auto const & collision : groupedCollisions) {
869+
870+ if (!AcceptEvent (collision)) {
871+ continue ;
872+ }
873+ if (biggestNContribs < collision.multPVTotalContributors ()) {
874+ biggestNContribs = collision.multPVTotalContributors ();
875+ bestCollisionIndex = collision.globalIndex ();
876+ centrality = collision.centFT0C ();
877+ }
878+ nCollisions++;
879+ }
880+ if (nCollisions < 1 ) {
881+ return ;
882+ }
883+ for (auto const & cascMC : CascMCCores) {
884+ if (!cascMC.has_straMCCollision ())
885+ continue ;
886+
887+ if (!cascMC.isPhysicalPrimary ())
888+ continue ;
889+
890+ float ptmc = RecoDecay::sqrtSumOfSquares (cascMC.pxMC (), cascMC.pyMC ());
891+
892+ float theta = std::atan (ptmc / cascMC.pzMC ()); // -pi/2 < theta < pi/2
893+
894+ float theta1 = 0 ;
895+
896+ // if pz is positive (i.e. positive rapidity): 0 < theta < pi/2
897+ if (theta > 0 )
898+ theta1 = theta; // 0 < theta1/2 < pi/4 --> 0 < tan (theta1/2) < 1 --> positive eta
899+ // if pz is negative (i.e. negative rapidity): -pi/2 < theta < 0 --> we need 0 < theta1/2 < pi/2 for the ln to be defined
900+ else
901+ theta1 = TMath::Pi () + theta; // pi/2 < theta1 < pi --> pi/4 < theta1/2 < pi/2 --> 1 < tan (theta1/2) --> negative eta
902+
903+ float cascMCeta = -log (std::tan (theta1 / 2 ));
904+ if (TMath::Abs (cascMCeta) > etaCascMCGen)
905+ continue ;
906+ histosMCGen.fill (HIST (" hGenEta" ), cascMCeta);
907+
908+ if (TMath::Abs (cascMC.pdgCode ()) == 3312 ) {
909+ histosMCGen.fill (HIST (" h2dGenXi" ), centrality, ptmc);
910+ } else if (TMath::Abs (cascMC.pdgCode () == 3334 )) {
911+ histosMCGen.fill (HIST (" h2dGenOmega" ), centrality, ptmc);
912+ }
742913 }
743914 }
744915
745916 PROCESS_SWITCH (cascadeFlow, processTrainingBackground, " Process to create the training dataset for the background" , true );
746917 PROCESS_SWITCH (cascadeFlow, processTrainingSignal, " Process to create the training dataset for the signal" , false );
747918 PROCESS_SWITCH (cascadeFlow, processAnalyseData, " Process to apply ML model to the data" , false );
748919 PROCESS_SWITCH (cascadeFlow, processAnalyseDataEPCentralFW, " Process to apply ML model to the data - event plane calibration from central framework" , false );
920+ PROCESS_SWITCH (cascadeFlow, processAnalyseMC, " Process to apply ML model to the MC" , false );
921+ PROCESS_SWITCH (cascadeFlow, processMCGen, " Process to store MC generated particles" , false );
749922};
750923
751924WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
0 commit comments