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
@@ -102,8 +103,24 @@ struct NucleiAntineutronCex {
102103 histos.add (" pEta" , " Pseudorapidity;#eta;Entries" , kTH1F , {{100 , -10 ., 10 .}});
103104 histos.add (" pP_ITScuts" , " Momentum with ITS cuts;|p| (GeV/c);Entries" , kTH1F , {{100 , 0 ., 10 .}});
104105
105- // test (MC)
106- histos.add (" antip_test" , " Secondary antiprotons;|p| (GeV/c);Entries" , kTH1F , {{100 , 0 ., 10 .}});
106+ // Process enum breakdown (secondary antiproton that anchors the SV)
107+ histos.add (" hProcEnumAP_CEX" , " procEnum of secondary #bar{p} (CEX);procEnum;Entries" , kTH1I , {{100 , -0.5 , 99.5 }});
108+ histos.add (" hProcEnumAP_BG" , " procEnum of secondary #bar{p} (BG);procEnum;Entries" , kTH1I , {{100 , -0.5 , 99.5 }});
109+
110+ // Multiplicity/composition at the SV (MC truth, for FINAL selected candidates)
111+ histos.add (" hVtxNAll_CEX" , " N(all) secondaries at SV (CEX);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
112+ histos.add (" hVtxNAll_BG" , " N(all) secondaries at SV (BG);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
113+ histos.add (" hVtxNCh_CEX" , " N(charged) secondaries at SV (CEX);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
114+ histos.add (" hVtxNCh_BG" , " N(charged) secondaries at SV (BG);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
115+ histos.add (" hVtxNNeut_CEX" , " N(neutral) secondaries at SV (CEX);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
116+ histos.add (" hVtxNNeut_BG" , " N(neutral) secondaries at SV (BG);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
117+
118+ histos.add (" hVtxNPi0_CEX" , " N(#pi^{0}) at SV (CEX);N;Entries" , kTH1I , {{40 , -0.5 , 39.5 }});
119+ histos.add (" hVtxNPi0_BG" , " N(#pi^{0}) at SV (BG);N;Entries" , kTH1I , {{40 , -0.5 , 39.5 }});
120+ histos.add (" hVtxNGamma_CEX" , " N(#gamma) at SV (CEX);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
121+ histos.add (" hVtxNGamma_BG" , " N(#gamma) at SV (BG);N;Entries" , kTH1I , {{60 , -0.5 , 59.5 }});
122+ histos.add (" hVtxNN_CEX" , " N(n) at SV (CEX);N;Entries" , kTH1I , {{40 , -0.5 , 39.5 }});
123+ histos.add (" hVtxNN_BG" , " N(n) at SV (BG);N;Entries" , kTH1I , {{40 , -0.5 , 39.5 }});
107124
108125 // CEX pair from antineutron (MC)
109126 histos.add (" cexPairMcP" , " CEX pair total momentum;|p| (GeV/c);Entries" , kTH1F , {{100 , 0 ., 10 .}});
@@ -130,6 +147,13 @@ struct NucleiAntineutronCex {
130147 histos.add (" cexbg_pairmc_vtxz" , " Background secondary vertex Z;Z (cm);Entries" , kTH1F , {{200 , -60 ., 60 .}});
131148 histos.add (" cexbg_pairmc_pITScuts" , " Background momentum (ITS cuts);|p| (GeV/c);Entries" , kTH1F , {{100 , 0 ., 10 .}});
132149
150+ histos.add (" hDeltaP_CEX" , " |p_{mother}-Σp_{SV}| (CEX);Δp (GeV/c);Entries" , kTH1F , {{200 , 0 ., 10 .}});
151+ histos.add (" hDeltaP_BG" , " |p_{mother}-Σp_{SV}| (BG);Δp (GeV/c);Entries" , kTH1F , {{200 , 0 ., 10 .}});
152+
153+ // Mother IB hits
154+ histos.add (" hMotherNHitIB_CEX" , " Mother IB hit layers (L0-L2) (CEX);N_{IB layers};Entries" , kTH1I , {{5 , -1.5 , 4.5 }});
155+ histos.add (" hMotherNHitIB_BG" , " Mother IB hit layers (L0-L2) (BG);N_{IB layers};Entries" , kTH1I , {{5 , -1.5 , 4.5 }});
156+
133157 // CEX pair from antineutron (TRK)
134158 histos.add (" cex_pairtrk_angle" , " Pair opening angle (tracks);Angle (°);Entries" , kTH1F , {{180 , 0 ., 180 .}});
135159 histos.add (" cexPairTrkP" , " Pair momentum (tracks);|p| (GeV/c);Entries" , kTH1F , {{120 , 0 ., 12 .}});
@@ -260,26 +284,31 @@ struct NucleiAntineutronCex {
260284 const bool isSecondaryFromMaterial = (!particle.producedByGenerator ()) && (procEnum == kPHadronic || procEnum == kPHInhelastic );
261285 if (particle.pdgCode () != -kProton || !isSecondaryFromMaterial || particle.mothersIds ().empty ())
262286 continue ;
263- histos.fill (HIST (" antip_test" ), particle.p ());
264287
265288 // Primary mother
266289 bool hasPrimaryMotherAntip = false ;
267290 double motherPt = 0.0 ;
291+ double motherPx = 0.0 ;
292+ double motherPy = 0.0 ;
268293 double motherPz = 0.0 ;
269294 double motherVz = 0.0 ;
270295 double motherP = 0.0 ;
271296 double motherEta = 0.0 ;
272297 int motherPdg = 0 ;
298+ int motherId = -1 ;
273299
274300 for (const auto & mother : particle.mothers_as <aod::McParticles>()) {
275301 if (mother.isPhysicalPrimary ()) {
276302 hasPrimaryMotherAntip = true ;
277303 motherPt = mother.pt ();
304+ motherPx = mother.px ();
305+ motherPy = mother.py ();
278306 motherPz = mother.pz ();
279307 motherVz = mother.vz ();
280308 motherP = mother.p ();
281309 motherEta = mother.eta ();
282310 motherPdg = mother.pdgCode ();
311+ motherId = mother.globalIndex ();
283312 break ;
284313 }
285314 }
@@ -530,6 +559,9 @@ struct NucleiAntineutronCex {
530559 int8_t antipTrkItsPidValid = 0 ;
531560 float antipTrkTgl = 0 .f ;
532561
562+ bool motherHasTrack = false ;
563+ int motherNHitIB = -1 ; // number of hits in IB (L0-L2)
564+
533565 o2::aod::ITSResponse itsResponse;
534566
535567 for (const auto & track : tracks) {
@@ -557,6 +589,11 @@ struct NucleiAntineutronCex {
557589 int nITS = track.itsNCls ();
558590 bool layerCondition = (!hitIB) && hitOuter && (nITS >= kMinItsHits );
559591
592+ if (mc.globalIndex () == motherId) {
593+ motherHasTrack = true ;
594+ motherNHitIB = static_cast <int >(hitL0) + static_cast <int >(hitL1) + static_cast <int >(hitL2);
595+ }
596+
560597 if (mc.globalIndex () == antipId) {
561598 antipTrkP = track.p ();
562599 antipTrkPx = track.px ();
@@ -695,6 +732,13 @@ struct NucleiAntineutronCex {
695732 const TVector3 pv2sv (secX - pvtxX, secY - pvtxY, secZ - pvtxZ);
696733 const double pairPointingAngleDeg = pv2sv.Angle (total_trk_pVec) * Rad2Deg;
697734
735+ const double pvsvThetaDeg = pv2sv.Theta () * Rad2Deg;
736+
737+ double pvsvPhiDeg = pv2sv.Phi () * Rad2Deg;
738+ if (pvsvPhiDeg < 0 .) {
739+ pvsvPhiDeg += 360 .;
740+ }
741+
698742 const double pP = pVecProton_trk.Mag ();
699743 const double pAP = AntipVecProton_trk.Mag ();
700744 const double ptP = pVecProton_trk.Pt ();
@@ -757,16 +801,112 @@ struct NucleiAntineutronCex {
757801
758802 const bool isCex = (motherPdg == -kNeutron );
759803
804+ // Nature of the process
805+ if (isCex) {
806+ histos.fill (HIST (" hProcEnumAP_CEX" ), static_cast <int >(procEnum));
807+ } else {
808+ histos.fill (HIST (" hProcEnumAP_BG" ), static_cast <int >(procEnum));
809+ }
810+
811+ // Count material secondaries produced at the same SV as the selected secondary antiproton.
812+ int vtxNAll = 0 ;
813+ int vtxNCh = 0 ;
814+ int vtxNNeut = 0 ;
815+ int vtxNPi0 = 0 ;
816+ int vtxNGamma = 0 ;
817+ int vtxNN = 0 ;
818+ double sumPx_vtx = 0.0 ;
819+ double sumPy_vtx = 0.0 ;
820+ double sumPz_vtx = 0.0 ;
821+ auto * pdgDB = TDatabasePDG::Instance ();
822+
823+ for (const auto & particle5 : mcPartsThis) {
824+ if (particle5.mcCollisionId () != colId) {
825+ continue ;
826+ }
827+ // Same SV (use the SV of the selected secondary antiproton)
828+ if (std::abs (particle5.vx () - antipVx) >= kVtxTol || std::abs (particle5.vy () - antipVy) >= kVtxTol || std::abs (particle5.vz () - antipVz) >= kVtxTol ) {
829+ continue ;
830+ }
831+ const auto proc5Enum = particle5.getProcess ();
832+ const bool isSecondaryFromMaterial5 =
833+ (!particle5.producedByGenerator ()) && (proc5Enum == kPHadronic || proc5Enum == kPHInhelastic );
834+ if (!isSecondaryFromMaterial5) {
835+ continue ;
836+ }
837+ ++vtxNAll;
838+ sumPx_vtx += particle5.px ();
839+ sumPy_vtx += particle5.py ();
840+ sumPz_vtx += particle5.pz ();
841+ const int pdg = particle5.pdgCode ();
842+ if (pdg == kPi0 ) {
843+ ++vtxNPi0;
844+ }
845+ if (pdg == kGamma ) {
846+ ++vtxNGamma;
847+ }
848+ if (pdg == kNeutron ) {
849+ ++vtxNN;
850+ }
851+ // Charged vs neutral via PDG database (Charge() is in units of e/3)
852+ double q = 0.0 ;
853+ if (auto * part = pdgDB->GetParticle (pdg)) {
854+ q = part->Charge () / 3.0 ;
855+ }
856+ if (std::abs (q) > 0.0 ) {
857+ ++vtxNCh;
858+ } else {
859+ ++vtxNNeut;
860+ }
861+ }
862+
863+ // Fill histos (final selected candidates only)
864+ if (isCex) {
865+ histos.fill (HIST (" hVtxNAll_CEX" ), vtxNAll);
866+ histos.fill (HIST (" hVtxNCh_CEX" ), vtxNCh);
867+ histos.fill (HIST (" hVtxNNeut_CEX" ), vtxNNeut);
868+ histos.fill (HIST (" hVtxNPi0_CEX" ), vtxNPi0);
869+ histos.fill (HIST (" hVtxNGamma_CEX" ), vtxNGamma);
870+ histos.fill (HIST (" hVtxNN_CEX" ), vtxNN);
871+ } else {
872+ histos.fill (HIST (" hVtxNAll_BG" ), vtxNAll);
873+ histos.fill (HIST (" hVtxNCh_BG" ), vtxNCh);
874+ histos.fill (HIST (" hVtxNNeut_BG" ), vtxNNeut);
875+ histos.fill (HIST (" hVtxNPi0_BG" ), vtxNPi0);
876+ histos.fill (HIST (" hVtxNGamma_BG" ), vtxNGamma);
877+ histos.fill (HIST (" hVtxNN_BG" ), vtxNN);
878+ }
879+
760880 const float vtxfitDX = secX - antipVx;
761881 const float vtxfitDY = secY - antipVy;
762882 const float vtxfitDZ = secZ - antipVz;
763883 const float vtxfitD3D = std::sqrt (vtxfitDX * vtxfitDX + vtxfitDY * vtxfitDY + vtxfitDZ * vtxfitDZ);
764884
885+ const double dPx = motherPx - sumPx_vtx;
886+ const double dPy = motherPy - sumPy_vtx;
887+ const double dPz = motherPz - sumPz_vtx;
888+ const double deltaP = std::sqrt (dPx * dPx + dPy * dPy + dPz * dPz);
889+
890+ if (isCex) {
891+ histos.fill (HIST (" hDeltaP_CEX" ), deltaP);
892+ } else {
893+ histos.fill (HIST (" hDeltaP_BG" ), deltaP);
894+ }
895+
896+ if (motherHasTrack) {
897+ if (isCex) {
898+ histos.fill (HIST (" hMotherNHitIB_CEX" ), motherNHitIB);
899+ } else {
900+ histos.fill (HIST (" hMotherNHitIB_BG" ), motherNHitIB);
901+ }
902+ }
903+
765904 const uint32_t selMask = 0u ;
766905
767906 outPairs (
768907 isCex,
769908 motherPdg,
909+ motherNHitIB,
770910 colId,
771911 pId,
772912 antipId,
@@ -780,6 +920,13 @@ struct NucleiAntineutronCex {
780920 antipVy,
781921 antipVz,
782922
923+ static_cast <int16_t >(vtxNAll),
924+ static_cast <int16_t >(vtxNCh),
925+ static_cast <int16_t >(vtxNNeut),
926+ static_cast <int16_t >(vtxNPi0),
927+ static_cast <int16_t >(vtxNGamma),
928+ static_cast <int16_t >(vtxNN),
929+
783930 cexPairTrkP,
784931 cexPairTrkPt,
785932 cexPairTrkPz,
@@ -818,6 +965,8 @@ struct NucleiAntineutronCex {
818965 selMask,
819966
820967 pairPointingAngleDeg,
968+ pvsvThetaDeg,
969+ pvsvPhiDeg,
821970 pairPBalance,
822971 pairPtBalance,
823972 pairQ,
0 commit comments