2828#include < Framework/runDataProcessing.h>
2929#include < ReconstructionDataFormats/TrackParametrization.h>
3030
31+ #include < TDatabasePDG.h>
3132#include < TMCProcess.h>
3233#include < TMath.h>
3334#include < TPDGCode.h>
@@ -53,7 +54,7 @@ struct NucleiAntineutronCex {
5354 static constexpr double kIts2MaxR = 48.0 ; // ITS2 max radius [cm]
5455 static constexpr double kIts2MaxVz = 39.0 ; // ITS2 max |vz| [cm]
5556 static constexpr double kAccMaxEta = 1.2 ; // acceptance |eta|
56- static constexpr double kAccMaxVz = 5.3 ; // acceptance |vz| [cm]
57+ static constexpr double kAccMaxVz = 10.0 ; // acceptance |vz| [cm]
5758 static constexpr double kStrictEta = 0.9 ; // tighter eta cut
5859 static constexpr double kInitDplane = 10.0 ; // init dplane
5960 static constexpr double kHuge = 1e9 ; // fallback for bad denom
@@ -105,6 +106,25 @@ struct NucleiAntineutronCex {
105106 // test (MC)
106107 histos.add (" antip_test" , " Secondary antiprotons;|p| (GeV/c);Entries" , kTH1F , {{100 , 0 ., 10 .}});
107108
109+ // Process enum breakdown (secondary antiproton that anchors the SV)
110+ histos.add (" hProcEnumAP_CEX" , " procEnum of secondary #bar{p} (CEX);procEnum;Entries" , kTH1I , {{100 , -0.5 , 99.5 }});
111+ histos.add (" hProcEnumAP_BG" , " procEnum of secondary #bar{p} (BG);procEnum;Entries" , kTH1I , {{100 , -0.5 , 99.5 }});
112+
113+ // Multiplicity/composition at the SV (MC truth, for FINAL selected candidates)
114+ histos.add (" hVtxNAll_CEX" , " N(all) secondaries at SV (CEX);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
115+ histos.add (" hVtxNAll_BG" , " N(all) secondaries at SV (BG);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
116+ histos.add (" hVtxNCh_CEX" , " N(charged) secondaries at SV (CEX);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
117+ histos.add (" hVtxNCh_BG" , " N(charged) secondaries at SV (BG);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
118+ histos.add (" hVtxNNeut_CEX" , " N(neutral) secondaries at SV (CEX);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
119+ histos.add (" hVtxNNeut_BG" , " N(neutral) secondaries at SV (BG);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
120+
121+ histos.add (" hVtxNPi0_CEX" , " N(#pi^{0}) at SV (CEX);N;Entries" , kTH1I , {{40 , -0.5 , 39.5 }});
122+ histos.add (" hVtxNPi0_BG" , " N(#pi^{0}) at SV (BG);N;Entries" , kTH1I , {{40 , -0.5 , 39.5 }});
123+ histos.add (" hVtxNGamma_CEX" , " N(#gamma) at SV (CEX);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
124+ histos.add (" hVtxNGamma_BG" , " N(#gamma) at SV (BG);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
125+ histos.add (" hVtxNN_CEX" , " N(n) at SV (CEX);N;Entries" , kTH1I , {{40 , -0.5 , 39.5 }});
126+ histos.add (" hVtxNN_BG" , " N(n) at SV (BG);N;Entries" , kTH1I , {{40 , -0.5 , 39.5 }});
127+
108128 // CEX pair from antineutron (MC)
109129 histos.add (" cexPairMcP" , " CEX pair total momentum;|p| (GeV/c);Entries" , kTH1F , {{100 , 0 ., 10 .}});
110130 histos.add (" cexPairMcPt" , " CEX pair p_{T};p_{T} (GeV/c);Entries" , kTH1F , {{100 , 0 ., 10 .}});
@@ -130,6 +150,13 @@ struct NucleiAntineutronCex {
130150 histos.add (" cexbg_pairmc_vtxz" , " Background secondary vertex Z;Z (cm);Entries" , kTH1F , {{200 , -60 ., 60 .}});
131151 histos.add (" cexbg_pairmc_pITScuts" , " Background momentum (ITS cuts);|p| (GeV/c);Entries" , kTH1F , {{100 , 0 ., 10 .}});
132152
153+ histos.add (" hDeltaP_CEX" , " |p_{mother}-Σp_{SV}| (CEX);Δp (GeV/c);Entries" , kTH1F , {{200 , 0 ., 10 .}});
154+ histos.add (" hDeltaP_BG" , " |p_{mother}-Σp_{SV}| (BG);Δp (GeV/c);Entries" , kTH1F , {{200 , 0 ., 10 .}});
155+
156+ // Mother IB hits
157+ histos.add (" hMotherNHitIB_CEX" , " Mother #bar{p} IB hit layers (L0-L2) (CEX);N_{IB layers};Entries" , kTH1I , {{4 , -0.5 , 3.5 }});
158+ histos.add (" hMotherNHitIB_BG" , " Mother #bar{p} IB hit layers (L0-L2) (BG);N_{IB layers};Entries" , kTH1I , {{4 , -0.5 , 3.5 }});
159+
133160 // CEX pair from antineutron (TRK)
134161 histos.add (" cex_pairtrk_angle" , " Pair opening angle (tracks);Angle (°);Entries" , kTH1F , {{180 , 0 ., 180 .}});
135162 histos.add (" cexPairTrkP" , " Pair momentum (tracks);|p| (GeV/c);Entries" , kTH1F , {{120 , 0 ., 12 .}});
@@ -265,21 +292,27 @@ struct NucleiAntineutronCex {
265292 // Primary mother
266293 bool hasPrimaryMotherAntip = false ;
267294 double motherPt = 0.0 ;
295+ double motherPx = 0.0 ;
296+ double motherPy = 0.0 ;
268297 double motherPz = 0.0 ;
269298 double motherVz = 0.0 ;
270299 double motherP = 0.0 ;
271300 double motherEta = 0.0 ;
272301 int motherPdg = 0 ;
302+ int motherId = -1 ;
273303
274304 for (const auto & mother : particle.mothers_as <aod::McParticles>()) {
275305 if (mother.isPhysicalPrimary ()) {
276306 hasPrimaryMotherAntip = true ;
277307 motherPt = mother.pt ();
308+ motherPx = mother.px ();
309+ motherPy = mother.py ();
278310 motherPz = mother.pz ();
279311 motherVz = mother.vz ();
280312 motherP = mother.p ();
281313 motherEta = mother.eta ();
282314 motherPdg = mother.pdgCode ();
315+ motherId = mother.globalIndex ();
283316 break ;
284317 }
285318 }
@@ -530,6 +563,10 @@ struct NucleiAntineutronCex {
530563 int8_t antipTrkItsPidValid = 0 ;
531564 float antipTrkTgl = 0 .f ;
532565
566+ bool motherHasTrack = false ;
567+ uint16_t motherItsMap = 0 ;
568+ int motherNHitIB = 0 ; // number of hits in IB (L0-L2)
569+
533570 o2::aod::ITSResponse itsResponse;
534571
535572 for (const auto & track : tracks) {
@@ -557,6 +594,12 @@ struct NucleiAntineutronCex {
557594 int nITS = track.itsNCls ();
558595 bool layerCondition = (!hitIB) && hitOuter && (nITS >= kMinItsHits );
559596
597+ if (mc.globalIndex () == motherId) {
598+ motherHasTrack = true ;
599+ motherItsMap = static_cast <uint16_t >(track.itsClusterMap ());
600+ motherNHitIB = static_cast <int >(hitL0) + static_cast <int >(hitL1) + static_cast <int >(hitL2);
601+ }
602+
560603 if (mc.globalIndex () == antipId) {
561604 antipTrkP = track.p ();
562605 antipTrkPx = track.px ();
@@ -695,6 +738,9 @@ struct NucleiAntineutronCex {
695738 const TVector3 pv2sv (secX - pvtxX, secY - pvtxY, secZ - pvtxZ);
696739 const double pairPointingAngleDeg = pv2sv.Angle (total_trk_pVec) * Rad2Deg;
697740
741+ const TVector3 zAxis (0 ., 0 ., 1 .);
742+ const double pvsvAngleZDeg = pv2sv.Angle (zAxis) * Rad2Deg;
743+
698744 const double pP = pVecProton_trk.Mag ();
699745 const double pAP = AntipVecProton_trk.Mag ();
700746 const double ptP = pVecProton_trk.Pt ();
@@ -757,11 +803,106 @@ struct NucleiAntineutronCex {
757803
758804 const bool isCex = (motherPdg == -kNeutron );
759805
806+ // Nature of the process
807+ if (isCex) {
808+ histos.fill (HIST (" hProcEnumAP_CEX" ), static_cast <int >(procEnum));
809+ } else {
810+ histos.fill (HIST (" hProcEnumAP_BG" ), static_cast <int >(procEnum));
811+ }
812+
813+ // Count material secondaries produced at the same SV as the selected secondary antiproton.
814+ int vtxNAll = 0 ;
815+ int vtxNCh = 0 ;
816+ int vtxNNeut = 0 ;
817+ int vtxNPi0 = 0 ;
818+ int vtxNGamma = 0 ;
819+ int vtxNN = 0 ;
820+ double sumPx_vtx = 0.0 ;
821+ double sumPy_vtx = 0.0 ;
822+ double sumPz_vtx = 0.0 ;
823+ auto * pdgDB = TDatabasePDG::Instance ();
824+
825+ for (const auto & particle5 : mcPartsThis) {
826+ if (particle5.mcCollisionId () != colId) {
827+ continue ;
828+ }
829+ // Same SV (use the SV of the selected secondary antiproton)
830+ if (std::abs (particle5.vx () - antipVx) >= kVtxTol || std::abs (particle5.vy () - antipVy) >= kVtxTol || std::abs (particle5.vz () - antipVz) >= kVtxTol ) {
831+ continue ;
832+ }
833+ const auto proc5Enum = particle5.getProcess ();
834+ const bool isSecondaryFromMaterial5 =
835+ (!particle5.producedByGenerator ()) && (proc5Enum == kPHadronic || proc5Enum == kPHInhelastic );
836+ if (!isSecondaryFromMaterial5) {
837+ continue ;
838+ }
839+ ++vtxNAll;
840+ sumPx_vtx += particle5.px ();
841+ sumPy_vtx += particle5.py ();
842+ sumPz_vtx += particle5.pz ();
843+ const int pdg = particle5.pdgCode ();
844+ if (pdg == kPi0 ) {
845+ ++vtxNPi0;
846+ }
847+ if (pdg == kGamma ) {
848+ ++vtxNGamma;
849+ }
850+ if (pdg == kNeutron ) {
851+ ++vtxNN;
852+ }
853+ // Charged vs neutral via PDG database (Charge() is in units of e/3)
854+ double q = 0.0 ;
855+ if (auto * part = pdgDB->GetParticle (pdg)) {
856+ q = part->Charge () / 3.0 ;
857+ }
858+ if (std::abs (q) > 0.0 ) {
859+ ++vtxNCh;
860+ } else {
861+ ++vtxNN;
862+ }
863+ }
864+
865+ // Fill histos (final selected candidates only)
866+ if (isCex) {
867+ histos.fill (HIST (" hVtxNAll_CEX" ), vtxNAll);
868+ histos.fill (HIST (" hVtxNCh_CEX" ), vtxNCh);
869+ histos.fill (HIST (" hVtxNNeut_CEX" ), vtxNNeut);
870+ histos.fill (HIST (" hVtxNPi0_CEX" ), vtxNPi0);
871+ histos.fill (HIST (" hVtxNGamma_CEX" ), vtxNGamma);
872+ histos.fill (HIST (" hVtxNN_CEX" ), vtxNN);
873+ } else {
874+ histos.fill (HIST (" hVtxNAll_BG" ), vtxNAll);
875+ histos.fill (HIST (" hVtxNCh_BG" ), vtxNCh);
876+ histos.fill (HIST (" hVtxNNeut_BG" ), vtxNNeut);
877+ histos.fill (HIST (" hVtxNPi0_BG" ), vtxNPi0);
878+ histos.fill (HIST (" hVtxNGamma_BG" ), vtxNGamma);
879+ histos.fill (HIST (" hVtxNN_BG" ), vtxNN);
880+ }
881+
760882 const float vtxfitDX = secX - antipVx;
761883 const float vtxfitDY = secY - antipVy;
762884 const float vtxfitDZ = secZ - antipVz;
763885 const float vtxfitD3D = std::sqrt (vtxfitDX * vtxfitDX + vtxfitDY * vtxfitDY + vtxfitDZ * vtxfitDZ);
764886
887+ const double dPx = motherPx - sumPx_vtx;
888+ const double dPy = motherPy - sumPy_vtx;
889+ const double dPz = motherPz - sumPz_vtx;
890+ const double deltaP = std::sqrt (dPx * dPx + dPy * dPy + dPz * dPz);
891+
892+ if (isCex) {
893+ histos.fill (HIST (" hDeltaP_CEX" ), deltaP);
894+ } else {
895+ histos.fill (HIST (" hDeltaP_BG" ), deltaP);
896+ }
897+
898+ if (motherHasTrack) {
899+ if (isCex) {
900+ histos.fill (HIST (" hMotherNHitIB_CEX" ), motherNHitIB);
901+ } else {
902+ histos.fill (HIST (" hMotherNHitIB_BG" ), motherNHitIB);
903+ }
904+ }
905+
765906 const uint32_t selMask = 0u ;
766907
767908 outPairs (
@@ -780,6 +921,13 @@ struct NucleiAntineutronCex {
780921 antipVy,
781922 antipVz,
782923
924+ static_cast <int16_t >(vtxNAll),
925+ static_cast <int16_t >(vtxNCh),
926+ static_cast <int16_t >(vtxNNeut),
927+ static_cast <int16_t >(vtxNPi0),
928+ static_cast <int16_t >(vtxNGamma),
929+ static_cast <int16_t >(vtxNN),
930+
783931 cexPairTrkP,
784932 cexPairTrkPt,
785933 cexPairTrkPz,
@@ -818,6 +966,7 @@ struct NucleiAntineutronCex {
818966 selMask,
819967
820968 pairPointingAngleDeg,
969+ pvsvAngleZDeg,
821970 pairPBalance,
822971 pairPtBalance,
823972 pairQ,
0 commit comments