@@ -55,6 +55,18 @@ enum McParticleHist {
5555 kMotherEta ,
5656 kMotherPhi ,
5757 kMotherSign ,
58+ // origin (kept in sync with TrackHist, even though some categories
59+ // are not expected to be populated for pure MC truth particles)
60+ kOrigin ,
61+ kNoMcParticle ,
62+ kPrimary ,
63+ kFromWrongCollision ,
64+ kFromMaterial ,
65+ kMissidentified ,
66+ kSecondary1 ,
67+ kSecondary2 ,
68+ kSecondary3 ,
69+ kSecondaryOther ,
5870
5971 kMcParticleHistLast
6072};
@@ -69,6 +81,8 @@ struct ConfMcParticleBinning : o2::framework::ConfigurableGroup {
6981 o2::framework::ConfigurableAxis phi{" phi" , {{720 , 0 , 1 .f * o2::constants::math::TwoPI}}, " Phi" };
7082 o2::framework::ConfigurableAxis sign{" sign" , {{3 , -1.5 , 1.5 }}, " Sign" };
7183 o2::framework::ConfigurableAxis pdgCodes{" pdgCodes" , {{8001 , -4000.5 , 4000.5 }}, " PDG codes of selected particles" };
84+ o2::framework::Configurable<bool > plotOrigins{" plotOrigins" , true , " Plot pt distributions for different particle origins" };
85+ o2::framework::Configurable<std::vector<int >> pdgCodesForMothersOfSecondary{" pdgCodesForMothersOfSecondary" , {3122 }, " PDG codes of mothers of secondaries (Max 3 will be considered)" };
7286};
7387
7488constexpr const char PrefixMcParticleBinning1[] = " McParticleBinning1" ;
@@ -92,6 +106,16 @@ constexpr std::array<histmanager::HistInfo<McParticleHist>, kMcParticleHistLast>
92106 {kMotherEta , o2::framework::HistType::kTH1F , " hMotherEta" , " Mother pseudorapidity; #eta; Entries" },
93107 {kMotherPhi , o2::framework::HistType::kTH1F , " hMotherPhi" , " Mother azimuthal angle; #varphi; Entries" },
94108 {kMotherSign , o2::framework::HistType::kTH1F , " hMotherSign" , " Sign of mother charge; Sign; Entries" },
109+ {kOrigin , o2::framework::HistType::kTH1F , " hOrigin" , " Status Codes (=Origin); Status Code; Entries" },
110+ {kNoMcParticle , o2::framework::HistType::kTH1F , " hNoMcParticle" , " Particles with no associated MC information; p_{T} (GeV/#it{c}); Entries" },
111+ {kPrimary , o2::framework::HistType::kTH1F , " hPrimary" , " Primary particles; p_{T} (GeV/#it{c}); Entries" },
112+ {kFromWrongCollision , o2::framework::HistType::kTH1F , " hFromWrongCollision" , " Particles associated to wrong collision; p_{T} (GeV/#it{c}); Entries" },
113+ {kFromMaterial , o2::framework::HistType::kTH1F , " hFromMaterial" , " Particles from material; p_{T} (GeV/#it{c}); Entries" },
114+ {kMissidentified , o2::framework::HistType::kTH1F , " hMissidentified" , " Missidentified particles (fake/wrong PDG code); p_{T} (GeV/#it{c}); Entries" },
115+ {kSecondary1 , o2::framework::HistType::kTH1F , " hFromSecondary1" , " Particles from secondary decay; p_{T} (GeV/#it{c}); Entries" },
116+ {kSecondary2 , o2::framework::HistType::kTH1F , " hFromSecondary2" , " Particles from secondary decay; p_{T} (GeV/#it{c}); Entries" },
117+ {kSecondary3 , o2::framework::HistType::kTH1F , " hFromSecondary3" , " Particles from secondary decay; p_{T} (GeV/#it{c}); Entries" },
118+ {kSecondaryOther , o2::framework::HistType::kTH1F , " hFromSecondaryOther" , " Particles from every other secondary decay; p_{T} (GeV/#it{c}); Entries" },
95119 }};
96120
97121template <typename T>
@@ -109,6 +133,15 @@ auto makeMcParticleHistSpecMap(const T& confBinning)
109133 {kMotherEta , {confBinning.eta }},
110134 {kMotherPhi , {confBinning.phi }},
111135 {kMotherSign , {confBinning.sign }},
136+ {kNoMcParticle , {confBinning.pt }},
137+ {kPrimary , {confBinning.pt }},
138+ {kFromWrongCollision , {confBinning.pt }},
139+ {kFromMaterial , {confBinning.pt }},
140+ {kMissidentified , {confBinning.pt }},
141+ {kSecondary1 , {confBinning.pt }},
142+ {kSecondary2 , {confBinning.pt }},
143+ {kSecondary3 , {confBinning.pt }},
144+ {kSecondaryOther , {confBinning.pt }},
112145 };
113146}
114147
@@ -124,8 +157,11 @@ class McParticleHistManager
124157 McParticleHistManager () = default ;
125158 ~McParticleHistManager () = default ;
126159
160+ // init with origin histograms enabled, controlled via confBinning.plotOrigins
161+ template <typename T>
127162 void init (o2::framework::HistogramRegistry* registry,
128- std::map<McParticleHist, std::vector<o2::framework::AxisSpec>> const & Specs)
163+ std::map<McParticleHist, std::vector<o2::framework::AxisSpec>> const & Specs,
164+ T const & confBinning)
129165 {
130166 mHistogramRegistry = registry;
131167
@@ -141,12 +177,11 @@ class McParticleHistManager
141177 mHistogramRegistry ->add (mcDir + getHistNameV2 (kMotherEta , HistTable), getHistDesc (kMotherEta , HistTable), getHistType (kMotherEta , HistTable), {Specs.at (kMotherEta )});
142178 mHistogramRegistry ->add (mcDir + getHistNameV2 (kMotherPhi , HistTable), getHistDesc (kMotherPhi , HistTable), getHistType (kMotherPhi , HistTable), {Specs.at (kMotherPhi )});
143179 mHistogramRegistry ->add (mcDir + getHistNameV2 (kMotherSign , HistTable), getHistDesc (kMotherSign , HistTable), getHistType (kMotherSign , HistTable), {Specs.at (kMotherSign )});
180+
181+ this ->enableOptionalHistograms (confBinning);
182+ this ->initOrigin (Specs);
144183 }
145184
146- // / T1 = mc particle row — must carry FMcMotherId/FMcPartMothId, i.e. this should be
147- // / a row from o2::soa::Join<FMcParticles, FMcMotherLabels>, not bare FMcParticles
148- // / T2 = FMcMothers (now with kinematics: Origin, PdgCode, SignedPt, Eta, Phi)
149- // / T3 = FMcPartMoths
150185 template <typename T1 , typename T2 , typename T3 >
151186 void fill (T1 const & mcParticle, T2 const & /* mcMothers*/ , T3 const & /* mcPartonicMothers*/ )
152187 {
@@ -156,7 +191,8 @@ class McParticleHistManager
156191 mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kSign , HistTable)), mcParticle.sign ());
157192 mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kPdg , HistTable)), mcParticle.pdgCode ());
158193
159- if (mcParticle.has_fMcMother ()) {
194+ bool hasMother = mcParticle.has_fMcMother ();
195+ if (hasMother) {
160196 auto mother = mcParticle.template fMcMother_as <T2 >();
161197 mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kPdgMother , HistTable)), mother.pdgCode ());
162198 mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kMotherPt , HistTable)), mother.pt ());
@@ -173,11 +209,108 @@ class McParticleHistManager
173209 } else {
174210 mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kPdgPartonicMother , HistTable)), 0 );
175211 }
212+
213+ if (mPlotOrigins ) {
214+ // NOTE: kNoMcParticle and kMissidentified are kept here only for enum/histogram
215+ // symmetry with TrackHist — they describe reco-vs-truth mismatches that cannot
216+ // occur for a pure MC-truth particle, so these bins are expected to stay empty
217+ // unless the producer assigns those origin codes for some other reason
218+ // (e.g. pileup-associated particles tagged as kFromWrongCollision).
219+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kOrigin , HistTable)), mcParticle.origin ());
220+ switch (static_cast <modes::McOrigin>(mcParticle.origin ())) {
221+ case modes::McOrigin::kNoMcParticle :
222+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kNoMcParticle , HistTable)), mcParticle.pt ());
223+ break ;
224+ case modes::McOrigin::kPhysicalPrimary :
225+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kPrimary , HistTable)), mcParticle.pt ());
226+ break ;
227+ case modes::McOrigin::kFromWrongCollision :
228+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kFromWrongCollision , HistTable)), mcParticle.pt ());
229+ break ;
230+ case modes::McOrigin::kFromMaterial :
231+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kFromMaterial , HistTable)), mcParticle.pt ());
232+ break ;
233+ case modes::McOrigin::kMissidentified :
234+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kMissidentified , HistTable)), mcParticle.pt ());
235+ break ;
236+ case modes::McOrigin::kFromSecondaryDecay :
237+ if (hasMother) {
238+ auto mother = mcParticle.template fMcMother_as <T2 >();
239+ int motherPdgCode = std::abs (mother.pdgCode ());
240+ if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel1 && motherPdgCode == mPdgCodesSecondaryMother [0 ]) {
241+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kSecondary1 , HistTable)), mcParticle.pt ());
242+ } else if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel2 && motherPdgCode == mPdgCodesSecondaryMother [1 ]) {
243+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kSecondary2 , HistTable)), mcParticle.pt ());
244+ } else if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel3 && motherPdgCode == mPdgCodesSecondaryMother [2 ]) {
245+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kSecondary3 , HistTable)), mcParticle.pt ());
246+ } else {
247+ mHistogramRegistry ->fill (HIST (prefix) + HIST (McDir) + HIST (getHistName (kSecondaryOther , HistTable)), mcParticle.pt ());
248+ }
249+ }
250+ break ;
251+ default :
252+ LOG (warn) << " Encountered mc particle with unknown origin!" ;
253+ break ;
254+ }
255+ }
176256 }
177257
178258 private:
259+ template <typename T>
260+ void enableOptionalHistograms (T const & confBinning)
261+ {
262+ mPlotOrigins = confBinning.plotOrigins .value ;
263+ mPlotNSecondaries = confBinning.pdgCodesForMothersOfSecondary .value .size ();
264+
265+ for (std::size_t i = 0 ; i < MaxSecondary; i++) {
266+ if (i < confBinning.pdgCodesForMothersOfSecondary .value .size ()) {
267+ mPdgCodesSecondaryMother .at (i) = std::abs (confBinning.pdgCodesForMothersOfSecondary .value .at (i));
268+ } else {
269+ mPdgCodesSecondaryMother .at (i) = 0 ;
270+ }
271+ }
272+ }
273+
274+ void initOrigin (std::map<McParticleHist, std::vector<o2::framework::AxisSpec>> const & Specs)
275+ {
276+ if (!mPlotOrigins ) {
277+ return ;
278+ }
279+ std::string mcDir = std::string (prefix) + std::string (McDir);
280+
281+ // mc origin axis can be configured here
282+ const o2::framework::AxisSpec axisOrigin = {static_cast <int >(modes::McOrigin::kMcOriginLast ), -0.5 , static_cast <double >(modes::McOrigin::kMcOriginLast ) - 0.5 };
283+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kOrigin , HistTable), getHistDesc (kOrigin , HistTable), getHistType (kOrigin , HistTable), {axisOrigin});
284+ mHistogramRegistry ->get <TH1 >(HIST (prefix) + HIST (McDir) + HIST (histmanager::getHistName (kOrigin , HistTable)))->GetXaxis ()->SetBinLabel (1 + static_cast <int >(modes::McOrigin::kNoMcParticle ), modes::mcOriginToString (modes::McOrigin::kNoMcParticle ));
285+ mHistogramRegistry ->get <TH1 >(HIST (prefix) + HIST (McDir) + HIST (histmanager::getHistName (kOrigin , HistTable)))->GetXaxis ()->SetBinLabel (1 + static_cast <int >(modes::McOrigin::kFromWrongCollision ), modes::mcOriginToString (modes::McOrigin::kFromWrongCollision ));
286+ mHistogramRegistry ->get <TH1 >(HIST (prefix) + HIST (McDir) + HIST (histmanager::getHistName (kOrigin , HistTable)))->GetXaxis ()->SetBinLabel (1 + static_cast <int >(modes::McOrigin::kPhysicalPrimary ), modes::mcOriginToString (modes::McOrigin::kPhysicalPrimary ));
287+ mHistogramRegistry ->get <TH1 >(HIST (prefix) + HIST (McDir) + HIST (histmanager::getHistName (kOrigin , HistTable)))->GetXaxis ()->SetBinLabel (1 + static_cast <int >(modes::McOrigin::kFromSecondaryDecay ), modes::mcOriginToString (modes::McOrigin::kFromSecondaryDecay ));
288+ mHistogramRegistry ->get <TH1 >(HIST (prefix) + HIST (McDir) + HIST (histmanager::getHistName (kOrigin , HistTable)))->GetXaxis ()->SetBinLabel (1 + static_cast <int >(modes::McOrigin::kFromMaterial ), modes::mcOriginToString (modes::McOrigin::kFromMaterial ));
289+ mHistogramRegistry ->get <TH1 >(HIST (prefix) + HIST (McDir) + HIST (histmanager::getHistName (kOrigin , HistTable)))->GetXaxis ()->SetBinLabel (1 + static_cast <int >(modes::McOrigin::kMissidentified ), modes::mcOriginToString (modes::McOrigin::kMissidentified ));
290+
291+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kNoMcParticle , HistTable), getHistDesc (kNoMcParticle , HistTable), getHistType (kNoMcParticle , HistTable), {Specs.at (kNoMcParticle )});
292+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kPrimary , HistTable), getHistDesc (kPrimary , HistTable), getHistType (kPrimary , HistTable), {Specs.at (kPrimary )});
293+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kFromWrongCollision , HistTable), getHistDesc (kFromWrongCollision , HistTable), getHistType (kFromWrongCollision , HistTable), {Specs.at (kFromWrongCollision )});
294+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kFromMaterial , HistTable), getHistDesc (kFromMaterial , HistTable), getHistType (kFromMaterial , HistTable), {Specs.at (kFromMaterial )});
295+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kMissidentified , HistTable), getHistDesc (kMissidentified , HistTable), getHistType (kMissidentified , HistTable), {Specs.at (kMissidentified )});
296+
297+ if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel1 ) {
298+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kSecondary1 , HistTable), getHistDesc (kSecondary1 , HistTable), getHistType (kSecondary1 , HistTable), {Specs.at (kSecondary1 )});
299+ }
300+ if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel2 ) {
301+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kSecondary2 , HistTable), getHistDesc (kSecondary2 , HistTable), getHistType (kSecondary2 , HistTable), {Specs.at (kSecondary2 )});
302+ }
303+ if (mPlotNSecondaries >= histmanager::kSecondaryPlotLevel3 ) {
304+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kSecondary3 , HistTable), getHistDesc (kSecondary3 , HistTable), getHistType (kSecondary3 , HistTable), {Specs.at (kSecondary3 )});
305+ }
306+ mHistogramRegistry ->add (mcDir + getHistNameV2 (kSecondaryOther , HistTable), getHistDesc (kSecondaryOther , HistTable), getHistType (kSecondaryOther , HistTable), {Specs.at (kSecondaryOther )});
307+ }
308+
179309 o2::framework::HistogramRegistry* mHistogramRegistry = nullptr ;
310+ bool mPlotOrigins = true ;
311+ int mPlotNSecondaries = 0 ;
312+ std::array<int , MaxSecondary> mPdgCodesSecondaryMother = {0 };
180313};
181- }; // namespace mcparticlehistmanager
182- }; // namespace o2::analysis::femto
314+ } // namespace mcparticlehistmanager
315+ } // namespace o2::analysis::femto
183316#endif // PWGCF_FEMTO_CORE_MCPARTICLEHISTMANAGER_H_
0 commit comments