Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
HadronOriginClassifier.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
6 
7 
8 namespace {
10  struct Sample {
12 
14  Sample(int low, int high, GEN_id gen, bool ttbb=false) :
15  low(low), high(high), gen(gen), ttbb(ttbb) {}
16 
18  Sample(int id, GEN_id gen, bool ttbb=false) :
19  Sample(id, id, gen, ttbb) {}
20 
21  int low{};
22  int high{};
23  GEN_id gen{GEN_id::Pythia6};
24  bool ttbb{false};
25  };
26 }
27 
28 namespace DerivationFramework{
29 
30  HadronOriginClassifier::HadronOriginClassifier(const std::string& t, const std::string& n, const IInterface* p):
31  AthAlgTool(t,n,p)
32  {
33  declareInterface<DerivationFramework::HadronOriginClassifier>(this);
34  }
35 
37 
39  ATH_MSG_INFO("Initialize " );
40  ATH_MSG_INFO("DSID " << m_DSID );
41 
42  static const std::vector<Sample> samples = {
43  // all Herwig++/Herwig7 showered samples
44  {410003, GEN_id::HerwigPP}, {410008, GEN_id::HerwigPP}, //aMC@NLO+Hpp
45  {410004, GEN_id::HerwigPP}, {410163, GEN_id::HerwigPP}, //Powheg+Hpp
46  {410232, 410233, GEN_id::HerwigPP}, //first attempt for Powheg+H7 / aMC@NLO+H7
47  {410525, 410530, GEN_id::HerwigPP}, //New Powheg+H7 samples
48  {407037, 407040, GEN_id::HerwigPP}, //Powheg+Hpp MET/HT sliced
49  {410536, 410537, GEN_id::HerwigPP}, {410245, GEN_id::HerwigPP, true}, //aMC@NLO+H++ , ttbb
50  {410557, 410559, GEN_id::HerwigPP}, // new Powheg+H7, mc16
51  {411082, 411090, GEN_id::HerwigPP}, //Powheg+H7 HF-filtered
52  {407354, 407356, GEN_id::HerwigPP}, //Powheg+H7 ttbar HT-filtered
53  {411233, 411234, GEN_id::HerwigPP}, //Powheg+H7.1.3 ttbar
54  {411316, GEN_id::HerwigPP}, //Powheg+H7 allhad ttbar
55  {411329, 411334, GEN_id::HerwigPP}, //Powheg+H7.1.3 ttbar HF-filtered
56  {411335, 411337, GEN_id::HerwigPP}, //Powheg+H7.1.3 ttbar HT-filtered
57  {412116, 412117, GEN_id::HerwigPP}, //amc@NLO+H7.1.3 ttbar
58  {504329, GEN_id::HerwigPP}, {504333, GEN_id::HerwigPP}, {504341, GEN_id::HerwigPP}, //amc@NLO+H7.2.1 refined ttZ
59  {601239, 601240, GEN_id::HerwigPP, true},
60  {601668, GEN_id::HerwigPP, true},
61  {603905, 603906, GEN_id::HerwigPP, true}, // ttbb Powheg+H7 dilep, ljet, allhad
62 
63  // all Pythia8 showered samples
64  {410006, GEN_id::Pythia8}, //Powheg+P8 old main31
65  {410500, GEN_id::Pythia8}, //Powheg+P8 new main31, hdamp=mt
66  {410501, 410508, GEN_id::Pythia8}, //Powheg+P8 new main31, hdamp=1.5m // Boosted samples are included 410507 410508
67  {410511, 410524, GEN_id::Pythia8}, //Powheg+P8 new main31, hdamp=1.5mt, radiation systematics
68  {410531, 410535, GEN_id::Pythia8}, //Powheg+P8 allhad samples
69  {346343, 346345, GEN_id::Pythia8}, //Powheg+P8 ttH
70  {412123, GEN_id::Pythia8}, // MG+P8 ttW
71  {410155, GEN_id::Pythia8}, // aMC@NlO+P8 ttW
72  {410159, 410160, GEN_id::Pythia8}, //aMC@NLO+P8, old settings
73  {410218, 410220, GEN_id::Pythia8}, // aMC@NlO+P8 ttZ
74  {410276, 410278, GEN_id::Pythia8}, // aMC@NlO+P8 ttZ_lowMass
75  {410225, 410227, GEN_id::Pythia8}, {410274, 410275, GEN_id::Pythia8}, //aMC@NLO+P8, new settings
76  {410568, 410569, GEN_id::Pythia8}, // nonallhad boosted c-filtered
77  {410244, GEN_id::Pythia8, true}, //aMC@NLO+P8, ttbb (old)
78  {410441, 410442, GEN_id::Pythia8}, //new aMC@NLO+P8 mc16, new shower starting scale
79  {410464, 410466, GEN_id::Pythia8}, //new aMC@NLO+P8 mc16, new shower starting scale, no shower weights
80  {410470, 410472, GEN_id::Pythia8}, {410480, 410482, GEN_id::Pythia8}, //new Powheg+P8 mc16
81  {410452, GEN_id::Pythia8}, //new aMC@NLO+P8 FxFx mc16
82  {411073, 411081, GEN_id::Pythia8}, //Powheg+P8 HF-filtered
83  {412066, 412074, GEN_id::Pythia8}, //aMC@NLO+P8 HF-filtered
84  {411068, 411070, GEN_id::Pythia8, true}, //Powheg+P8 ttbb
85  {410265, 410267, GEN_id::Pythia8, true}, //aMC@NLO+P8 ttbb
86  {411178, 411180, GEN_id::Pythia8, true}, {411275, GEN_id::Pythia8, true}, //Powheg+P8 ttbb OTF production - ATLMCPROD-7240
87  {600791, 600792, GEN_id::Pythia8, true}, //Powheg+P8 ttbb - ATLMCPROD-9179
88  {600737, 600738, GEN_id::Pythia8, true}, //Powheg+P8 ttbb - ATLMCPROD-9179
89  {601226, 601227, GEN_id::Pythia8, true}, // Powheg+P8 ttbb bornzerodamp cut 5, ATLMCPROD-9694
90  {407342, 407344, GEN_id::Pythia8}, //Powheg+P8 ttbar HT-filtered
91  {407345, 407347, GEN_id::Pythia8}, //Powheg+P8 ttbar MET-filtered
92  {407348, 407350, GEN_id::Pythia8}, //aMC@NLO+P8 ttbar HT-filtered
93  {504330, 504332, GEN_id::Pythia8}, {504334, 504336, GEN_id::Pythia8}, {504338, GEN_id::Pythia8}, {504342, 504344, GEN_id::Pythia8}, {504346, GEN_id::Pythia8}, //aMC@NLO+P8 refined ttZ
94  {601491, 601492, GEN_id::Pythia8}, //Pow+Py8 ttbar pTHard variations - ATLMCPROD-10168
95  {601495, 601498, GEN_id::Pythia8}, //Pow+Py8 ttbar pTHard variations - ATLMCPROD-10168
96  {601229, 601230, GEN_id::Pythia8}, // mc23 ttbar dilep, singlelep
97  {601237, GEN_id::Pythia8}, // mc23 ttbar allhad
98  {601398, 601399, GEN_id::Pythia8}, // mc23 ttbar dilep, singlelep hdamp517p5
99  {601491, GEN_id::Pythia8}, {601495, GEN_id::Pythia8}, {601497, GEN_id::Pythia8}, // mc23 ttbar pThard variations, dilep, singlelep, allhad
100  {601783, 601784, GEN_id::Pythia8, true}, // Powheg+P8 ttbb bornzerodamp cut 5 pThard variations - ATLMCPROD-10527
101  {603003, 603004, GEN_id::Pythia8, true}, // Powheg+P8 ttbb nominal and pthard1 allhad
102  {603190, 603193, GEN_id::Pythia8, true}, // Powheg+P8 ttbb nominal and pthard1 dilep, ljet
103 
104  // all Sherpa showered samples
105  {410186, 410189, GEN_id::Sherpa}, //Sherpa 2.2.0
106  {410249, 410252, GEN_id::Sherpa}, //Sherpa 2.2.1
107  {410342, 410347, GEN_id::Sherpa}, //Sherpa 2.2.1 sys
108  {410350, 410355, GEN_id::Sherpa}, //Sherpa 2.2.1 sys
109  {410357, 410359, GEN_id::Sherpa}, //Sherpa 2.2.1 sys
110  {410361, 410367, GEN_id::Sherpa}, //Sherpa 2.2.1 sys
111  {410281, 410283, GEN_id::Sherpa}, //Sherpa BFilter
112  {410051, GEN_id::Sherpa, true}, //Sherpa ttbb (ICHEP sample)
113  {410323, 410325, GEN_id::Sherpa, true}, {410369, GEN_id::Sherpa, true}, //New Sherpa 2.2.1 ttbb
114  {364345, 364348, GEN_id::Sherpa}, //Sherpa 2.2.4 (test)
115  {410424, 410427, GEN_id::Sherpa}, //Sherpa 2.2.4
116  {410661, 410664, GEN_id::Sherpa, true}, //Sherpa 2.2.4 ttbb
117  {421152, 421158, GEN_id::Sherpa}, //Sherpa2.2.8 ttbar
118  {413023, GEN_id::Sherpa}, // sherpa 2.2.1 ttZ
119  {700000, GEN_id::Sherpa}, // Sherpa 2.2.8 ttW
120  {700168, GEN_id::Sherpa}, // Sherpa 2.2.10 ttW
121  {700205, GEN_id::Sherpa}, // Sherpa 2.2.10 ttW EWK
122  {700309, GEN_id::Sherpa}, // Sherpa 2.2.11 ttZ
123  {700051, 700054, GEN_id::Sherpa, true}, //Sherpa2.2.8 ttbb
124  {700121, 700124, GEN_id::Sherpa}, //Sherpa2.2.10 ttbar
125  {700164, 700167, GEN_id::Sherpa, true}, //Sherpa2.2.10 ttbb
126  {700807, 700809, GEN_id::Sherpa}, //Sherpa2.2.14 ttbar
127 
128  };
129 
130  // Linear search for sample and assign properties:
131  for (const auto& s : samples) {
132  if (m_DSID>=s.low && m_DSID<=s.high) {
133  m_GenUsed = s.gen;
134  m_ttbb = s.ttbb;
135  return StatusCode::SUCCESS;
136  }
137  }
138 
139  // the default is Pythia6, so no need to list the Pythia6 showered samples
140  // these are:
141  // 410000-410002
142  // 410007, 410009, 410120-410121
143  // 301528-301532
144  // 303722-303726
145  // 407009-407012
146  // 407029-407036
147  // 410120
148  // 426090-426097
149  // 429007
151 
152  return StatusCode::SUCCESS;
153  }
154 
155  /*
156  --------------------------------------------------------------------------------------------------------------------------------------
157  ------------------------------------------------------------- Hadron Map -------------------------------------------------------------
158  --------------------------------------------------------------------------------------------------------------------------------------
159  */
160 
161  // Define the function GetOriginMap that determines the origin of the hadrons.
162  std::map<const xAOD::TruthParticle*, DerivationFramework::HadronOriginClassifier::HF_id> HadronOriginClassifier::GetOriginMap() const {
163  // Create a set of maps to store the information about the hadrons and the partons
164  std::map<const xAOD::TruthParticle*, int> mainHadronMap; // Map with main hadrons and their flavor.
165  std::map<const xAOD::TruthParticle*, HF_id> partonsOrigin; // Map with partons and their category (from top, W, H, MPI, FSR, extra).
166  std::map<const xAOD::TruthParticle*, const xAOD::TruthParticle*> hadronsPartons; // Map with hadrons and their matched parton.
167  std::map<const xAOD::TruthParticle*, HF_id> hadronsOrigin; // Map with hadrons and their category (from top, W, H, MPI, FSR, extra)
168  // Fill the maps mainHadronMap and partonsOrigin
169  buildPartonsHadronsMaps(mainHadronMap, partonsOrigin);
170  // Create two maps to know which partons and hadrons have already been matched.
171  std::vector<const xAOD::TruthParticle*> matched_partons;
172  std::vector<const xAOD::TruthParticle*> matched_hadrons;
173  // Use a while to go through the HF hadrons in mainHadronMap and partons in partonsOrigin.
174  while (matched_partons.size()<partonsOrigin.size() && matched_hadrons.size()<mainHadronMap.size()){
175  // Create a float variable to store the DeltaR between a parton and the closest hadron.
176  float dR=999.;
177  // Create two pointers for TruthParticle type to go through the partons and hadrons.
178  const xAOD::TruthParticle* hadron=nullptr;
179  const xAOD::TruthParticle* parton=nullptr;
180  // Use a for to go through the partonsOrigin.
181  for(std::map<const xAOD::TruthParticle*, HF_id>::iterator itr = partonsOrigin.begin(); itr!=partonsOrigin.end(); ++itr){
182  // Check if the parton has already been matched to an hadron.
183  if(std::find(matched_partons.begin(), matched_partons.end(), (*itr).first) != matched_partons.end()) continue;
184  // Extract the pt of the parton.
185  TVector3 v, vtmp;
186  if ((*itr).first->pt()>0.)
187  v.SetPtEtaPhi((*itr).first->pt(),(*itr).first->eta(),(*itr).first->phi());
188  else // Protection against FPE from eta and phi calculation
189  v.SetXYZ(0.,0.,(*itr).first->pz());
190  // Use a for to go through the HF hadrons in mainHadronMap.
191  for(std::map<const xAOD::TruthParticle*, int>::iterator it = mainHadronMap.begin(); it!=mainHadronMap.end(); ++it){
192  // Check if the hadron has already been matched to a parton.
193  if(std::find(matched_hadrons.begin(), matched_hadrons.end(), (*it).first) != matched_hadrons.end()) continue;
194  // Check if the hadron's flavour mathces the one of the parton.
195  if((*it).second != abs((*itr).first->pdgId()) ) continue;
196  // Extract the pt of the hadron.
197  vtmp.SetPtEtaPhi((*it).first->pt(),(*it).first->eta(),(*it).first->phi());
198  // Compute Delta R between hadron and parton and store in dR if it is smaller than the current value.
199  // Also store the parton and hadron in the pointers that have been previous created.
200  if(vtmp.DeltaR(v) < dR){
201  dR = vtmp.DeltaR(v);
202  hadron = (*it).first;
203  parton = (*itr).first;
204  }
205  }//loop hadrons
206  }//loop partons
207  // Add the matched part-hadron pair in the corresponding maps.
208  matched_partons.push_back(parton);
209  matched_hadrons.push_back(hadron);
210  hadronsPartons[ hadron ] = parton;
211  }
212 
213  // Use a for to go through the HF hadrons in mainHadronMap.
214  for(std::map<const xAOD::TruthParticle*, int>::iterator it = mainHadronMap.begin(); it!=mainHadronMap.end(); ++it){
215  // Extract the current hadron.
216  const xAOD::TruthParticle* hadron = (*it).first;
217  // Check if the hadron has been matched to a parton.
218  // If it has been matched to any hadron, use it to determine the origin.
219  // Otherwise, the hadron is considered extra.
220  if(hadronsPartons.find(hadron)!=hadronsPartons.end()){
221  hadronsOrigin[hadron] = partonsOrigin[ hadronsPartons[hadron] ];
222  } else{
223  hadronsOrigin[hadron] = extrajet;
224  }
225  }
226  return hadronsOrigin;
227  }
228 
229  // Define the function buildPartonsHadronsMaps that determines the flavour of the hadrons and the origin of the partons.
230  void HadronOriginClassifier::buildPartonsHadronsMaps(std::map<const xAOD::TruthParticle*,int>& mainHadronMap, std::map<const xAOD::TruthParticle*,HF_id>& partonsOrigin) const {
231  // Extract the TruthParticles container.
232  const xAOD::TruthEventContainer* xTruthEventContainer = nullptr;
233  if (evtStore()->retrieve(xTruthEventContainer,m_mcName).isFailure()) {
234  ATH_MSG_WARNING("could not retrieve TruthEventContainer " <<m_mcName);
235  }
236  // Create a container with TruthParticles to store the hadrons that has already been saved.
237  std::set<const xAOD::TruthParticle*> usedHadron;
238  for ( const auto* truthevent : *xTruthEventContainer ) {
239  // Use a for to go through the TruthParticles.
240  for(unsigned int i = 0; i < truthevent->nTruthParticles(); i++){
241  // Extract the i-th particle.
242  const xAOD::TruthParticle* part = truthevent->truthParticle(i);
243  if(!part) continue;
244  // Simulated particles are not considered.
246  // Create a set of boolean variables to indicate the type of particle.
247  bool isbquark = false; // The particle is a b-quark.
248  bool iscquark = false; // The particle is a c-quark.
249  bool isHFhadron = false; // The particle is a HF hadron.
250  // Extract the pdgid of the particle and use it to determine the type of particle.
251  int pdgid = abs(part->pdgId());
252  if( MC::isBottom(pdgid) ){
253  isbquark=true;
254  }
255  else if( MC::isCharm(pdgid) ){
256  iscquark=true;
257  }
259  isHFhadron=true;
260  }
261  else{
262  continue;
263  }
264  // For HF quarks (b or c), check their category.
265  // The category is determined looking for the parents.
266  if(isbquark){
267  // In this case, the parton is a b-quark.
268  // Create a boolean that indicates when to stop to look for parents.
269  bool islooping = isLooping(part);
270  // Check the category of the b-quark.
271  if(isDirectlyFromWTop(part, islooping)){
272  partonsOrigin[ part ] = b_from_W;
273  }
274  else if(isDirectlyFromTop(part, islooping)){
275  partonsOrigin[ part ] = b_from_top;
276  }
277  else if(!IsTtBb()&&(IsHerwigPP()||IsSherpa())&&isDirectlyFSR(part,islooping)){
278  partonsOrigin[ part ] = b_FSR;
279  }
280  else if(!IsTtBb()&&IsPythia8()&&isDirectlyFSRPythia8(part,islooping)){
281  partonsOrigin[ part ] = b_FSR;
282  }
283  else if(!IsTtBb()&&IsPythia6()&&isDirectlyFSRPythia6(part,islooping)){
284  partonsOrigin[ part ] = b_FSR;
285  }
286  else if(!IsTtBb()&&IsPythia6()&&isDirectlyMPIPythia6(part, islooping)){
287  partonsOrigin[ part ] = b_MPI;
288  }
289  else if(!IsTtBb()&&IsPythia8()&&isDirectlyMPIPythia8(part, islooping)){
290  partonsOrigin[ part ] = b_MPI;
291  }
292  else if(!IsTtBb()&&IsSherpa()&&isDirectlyMPISherpa(part)){
293  partonsOrigin[ part ] = b_MPI;
294  }
295  }
296  if(iscquark){
297  // In this case, the parton is a c-quark.
298  // Create a boolean that indicates when to stop to look for parents.
299  bool islooping = isLooping(part);
300  // Check the category of the b-quark.
301  if(isDirectlyFromWTop(part, islooping)){
302  partonsOrigin[ part ] = c_from_W;
303  }
304  else if(isDirectlyFromTop(part, islooping)){
305  partonsOrigin[ part ] = c_from_top;
306  }
307  else if(!IsTtBb()&&(IsHerwigPP()&&IsSherpa())&&isDirectlyFSR(part,islooping)){
308  partonsOrigin[ part ] = c_FSR;
309  }
310  else if(!IsTtBb()&&IsPythia8()&&isDirectlyFSRPythia8(part,islooping)){
311  partonsOrigin[ part ] = c_FSR;
312  }
313  else if(!IsTtBb()&&IsPythia6()&&isDirectlyFSRPythia6(part,islooping)){
314  partonsOrigin[ part ] = c_FSR;
315  }
316  else if(!IsTtBb()&&IsPythia6()&&isDirectlyMPIPythia6(part, islooping)){
317  partonsOrigin[ part ] = c_MPI;
318  }
319  else if(!IsTtBb()&&IsPythia8()&&isDirectlyMPIPythia8(part, islooping)){
320  partonsOrigin[ part ] = c_MPI;
321  }
322  else if(!IsTtBb()&&IsSherpa()&&isDirectlyMPISherpa(part)){
323  partonsOrigin[ part ] = c_MPI;
324  }
325  }
326  // The HF hadrons are stored in the map mainHadronMap if they are not repeated.
327  if(isHFhadron && !isCHadronFromB(part)){
328  // In this case, the particle is a HF hadron but not a C-Hadron from a B-hadron.
329  // If the hadron is not in usedHadron, then add it in mainHadronMap with fillHadronMap function.
330  if(usedHadron.insert(part).second) {
331  fillHadronMap(usedHadron, mainHadronMap,part,part);
332  }
333  }
334  }//loop on particles
335  }//loop on truthevent container
336  }
337 
338  /*
339  ---------------------------------------------------------------------------------------------------------------------------------------
340  ------------------------------------------------------------ Particle Type ------------------------------------------------------------
341  ---------------------------------------------------------------------------------------------------------------------------------------
342  */
343  bool HadronOriginClassifier::isCHadronFromB(const xAOD::TruthParticle* part, std::shared_ptr<std::set<const xAOD::TruthParticle*>> checked ) const{
344  if(!MC::isCharmHadron(part)) return false;
345  if (!checked) checked = std::make_shared<std::set<const xAOD::TruthParticle*>>();
346  checked ->insert(part);
347 
348  for(unsigned int i=0; i<part->nParents(); ++i){
349  const xAOD::TruthParticle* parent = part->parent(i);
350  if(!parent) continue;
351  if(checked->count(parent)) continue;
352  checked->insert(parent);
353  if( MC::isBottomHadron(parent) ){
354  return true;
355  }
357  if(isCHadronFromB(parent))return true;
358  }
359  }
360 
361  return false;
362  }
363 
364  // Define the function fillHadronMap that fills the map of hadrons with their flavour.
365  void HadronOriginClassifier::fillHadronMap(std::set<const xAOD::TruthParticle*>& usedHadron, std::map<const xAOD::TruthParticle*,int>& mainHadronMap, const xAOD::TruthParticle* mainhad, const xAOD::TruthParticle* ihad, bool decayed) const {
366  // Fist, check that the consdired hadron has a non-null pointer
367  if (!ihad) return;
368  usedHadron.insert(ihad);
369  // Create two variables to indicate the flavour of the parents and childrens particles that will be considered.
370  // Create a boolean to indicate if the particles considered are from the final state.
371  int parent_flav,child_flav;
372  bool isFinal = true;
373  // Check if the considered hadron has children.
374  if(!ihad->nChildren()) return;
375  // Use a for to go through the children.
376  for(unsigned int j=0; j<ihad->nChildren(); ++j){
377  // Extract the j-th children.
378  const xAOD::TruthParticle* child = ihad->child(j);
379  if(!child) continue;
380  if(decayed){
381  fillHadronMap(usedHadron, mainHadronMap,mainhad,child,true);
382  isFinal=false;
383  }
384  else{
385  child_flav = std::abs(MC::leadingQuark(child));
386  if(child_flav!=4 && child_flav!=5) continue;
387  parent_flav = std::abs(MC::leadingQuark(mainhad));
388  if(child_flav!=parent_flav) continue;
389  fillHadronMap(usedHadron, mainHadronMap,mainhad,child);
390  isFinal=false;
391  }
392  }
393 
394  if(isFinal && !decayed){
395  mainHadronMap[mainhad]=std::abs(MC::leadingQuark(mainhad));
396  for(unsigned int j=0; j<ihad->nChildren(); ++j){
397  const xAOD::TruthParticle* child = ihad->child(j);
398  if(!child) continue;
399  fillHadronMap(usedHadron, mainHadronMap,mainhad,child,true);
400  }
401  }
402  }
403 
404  /*
405  ---------------------------------------------------------------------------------------------------------------------------------------
406  ----------------------------------------------------------- Particle Origin -----------------------------------------------------------
407  ---------------------------------------------------------------------------------------------------------------------------------------
408  */
409 
410  // Define the function isFromTop that indicates if a particle comes from top.
411 
413  // Find the first parent of the considered particle that is different from the particle.
414  const xAOD::TruthParticle* initpart = findInitial(part, looping);
415  // Check if this parent comes from the top with function isDirectlyFromTop.
416  return isDirectlyFromTop(initpart, looping);
417  }
418 
419  // Define the function isDirectlyFromTop that indicates if a particle comes from the direct decay of top.
421  // First, make sure the consdired particle has a non-null pointer and it has parents.
422  // Otherwise, return false.
423  if(!part || !part->nParents()) return false;
424  // Go through the parents of the particle.
425  for(unsigned int i=0; i<part->nParents(); ++i){
426  // Extract the i-th parent.
427  const xAOD::TruthParticle* parent = part->parent(i);
428  if(!parent) continue;
429  if(looping) continue;
430  // If the i-th parent is a top, then return true
431  if( MC::isTop(parent) ) return true;
432  }
433  // If a top is no the parent, then return false.
434  return false;
435  }
436 
437  // Define the function isFromWTop that indicates if a particle comes from the decay chain t->Wb.
438 
440  // Find the first parent of the considered particle that is different from the particle.
441  const xAOD::TruthParticle* initpart = findInitial(part, looping);
442  return isDirectlyFromWTop(initpart, looping);
443  }
444 
445  // Define the function isDirectlyFromWTop that indicates if a particle comes from the direct decay of a W from a top.
447  // First, make sure the consdired particle has a non-null pointer and it has parents.
448  // Otherwise, return false.
449  if(!part || !part->nParents()) return false;
450  // Use a for to go though the parents.
451  for(unsigned int i=0; i<part->nParents(); ++i){
452  // Get the i-th parent.
453  const xAOD::TruthParticle* parent = part->parent(i);
454  if(!parent) continue;
455  if(looping) continue;
456  if( MC::isW(parent)){
457  if( isFromTop(parent, looping) ) return true;
458  }
459  }
460  // In this case, none of the parents of the particle is a W from top.
461  // Hence, return false.
462  return false;
463  }
464 
466  if(!part->nParents()) return false;
467  for(unsigned int i=0; i<part->nParents(); ++i){
468  const xAOD::TruthParticle* parent = part->parent(i);
469  if(!parent) continue;
470  if( looping ) continue;
471  if( MC::isPhoton(parent) || abs(parent->pdgId())<MC::BQUARK ) return true;
472  }
473  return false;
474  }
475 
477  const xAOD::TruthParticle* initpart = findInitial(part, looping);
478  return isDirectlyFromGluonQuark(initpart, looping);
479  }
480 
482  if(!part->nParents()) return false;
483  for(unsigned int i=0; i<part->nParents(); ++i){
484  const xAOD::TruthParticle* parent = part->parent(i);
485  if(!parent) continue;
486  if(looping ) continue;
487  if(!MC::isW(parent)) continue;
488  if(MC::isCharm(part)){
489  //trick to get at least 50% of PowhegPythia c from FSR
490  if(part->pdgId()==-(parent->pdgId())/6){
491  if( isFromGluonQuark(parent, looping) ) return true;
492  }
493  }
494  else{
495  if( isFromGluonQuark(parent, looping) ) return true;
496  }
497  }
498  return false;
499  }
500 
502  if(!part->nParents()) return false;
503  for(unsigned int i=0; i<part->nParents(); ++i){
504  const xAOD::TruthParticle* parent = part->parent(i);
505  if(!parent) continue;
506  if( looping ) continue;
508  if( isFromQuarkTop( parent,looping ) ) return true;
509  }
510  }
511  return false;
512  }
513 
515  if(!part->nParents()) return false;
516  for(unsigned int i=0; i<part->nParents(); ++i){
517  const xAOD::TruthParticle* parent = part->parent(i);
518  if(!parent) continue;
519  if( looping ) continue;
520  if( abs(parent->pdgId())<MC::TQUARK ) {
521 
522  if(isFromTop(parent,looping)){
523  return true;
524  }
525  else if(isFromWTop(parent,looping)){
526  return true;
527  }
528  }
529  }
530 
531  return false;
532  }
533 
535  const xAOD::TruthParticle* initpart = findInitial(part, looping);
536  return isDirectlyFromQuarkTop(initpart, looping);
537  }
538 
539  // Define the function isDirectlyFSRPythia8 that indicates if a particle comes from Final State Radiation in samples generated with Pythia8.
540 
542  // First, check if the particle has parents and return false if it does not.
543  if(!part->nParents()) return false;
544  // Use a for to go through the parents.
545  for(unsigned int i=0; i<part->nParents(); ++i){
546 
547  // Extract the i-th parent.
548 
549  const xAOD::TruthParticle* parent = part->parent(i);
550  if(!parent) continue;
551  if( looping ) continue;
553  if( isFromQuarkTopPythia8( parent,looping ) ) return true;
554  }
555  }
556  // In this case, no parent from the particle is a gluon or a photon coming from a top
557  // Hence, the particle is not from FSR and false is not returned.
558  return false;
559  }
560 
561  // Define the function isDirectlyFromQuarkTopPythia8 that indicates if a particle comes from direct decay of the top in samples generated with Pythia8.
563  // First, make sure the consdired particle has a non-null pointer and it has parents.
564  // Otherwise, return false.
565  if(!part->nParents()) return false;
566  // Use a for to go through the parents.
567  for(unsigned int i=0; i<part->nParents(); ++i){
568  // Extract the i-th parent.
569  const xAOD::TruthParticle* parent = part->parent(i);
570  if(!parent) continue;
571  if(looping ) continue;
572  // Check if the parent is a quark different from the top.
573  if( abs(parent->pdgId())<MC::TQUARK ) {
574  // In this case, the parent is a quark different from top.
575  // Check if it comes from the decay chain of the t->Wb.
576  // If it is the case, return true.
577  if(isFromWTop(parent,looping)){
578  return true;
579  }
580  }
581  }
582  // In this case, any of the parents of the particle comes from t->Wb chaing.
583  // Hence, the particle does not come from the top directly and false is returned.
584  return false;
585  }
586 
587  // Define the function isFromQuarkTopPythia8 that indicates if a particle comes from top in samples generated with Pythia8.
589  // Find the first parent of the considered particle that is different from the particle.
590  const xAOD::TruthParticle* initpart = findInitial(part, looping);
591  // Check if this parent comes from the top with function isDirectlyFromQuarkTopPythia8.
592  return isDirectlyFromQuarkTopPythia8(initpart, looping);
593  }
594 
596  if(!part->nParents()) return false;
597  for(unsigned int i=0; i<part->nParents(); ++i){
598  const xAOD::TruthParticle* parent = part->parent(i);
599  if(!parent) continue;
600  if( looping ) continue;
601  if( abs(parent->pdgId()) == MC::PROTON && MC::isPhysical(part) ) return true;
602  }
603  return false;
604  }
605 
607  const xAOD::TruthParticle* initpart = findInitial(part, looping);
608  return MC::Pythia8::isConditionC(initpart);
609  }
610 
612  if(!part->hasProdVtx()) return false;
613  const xAOD::TruthVertex* vertex = part->prodVtx();
614  return HepMC::status(vertex) == 2;
615  }
616 
617  /*
618  --------------------------------------------------------------------------------------------------------------------------------------
619  ---------------------------------------------------------- Particle Parents ----------------------------------------------------------
620  --------------------------------------------------------------------------------------------------------------------------------------
621  */
622 
623  // Define the function isLooping that determines when to stop to look at the parents of a particle.
624  bool HadronOriginClassifier::isLooping(const xAOD::TruthParticle* part, std::shared_ptr<std::set<const xAOD::TruthParticle*>> init_part) const{
625  // First, check if the particle has parents and return false if it does not.
626  if(!part->nParents()) return false;
627  // In this case, the particle has parents.
628  // Store the particle in the container init_part.
629  if (!init_part) init_part = std::make_shared<std::set<const xAOD::TruthParticle*>>();
630  init_part->insert(part);
631  // Use a for to go through the parents.
632  for(unsigned int i=0; i<part->nParents(); ++i){
633  // Get the i-th parent and check if it is in the container init_part.
634  // If it is not, return true because the parent need to be checked.
635  // Otherwise, check the parent of the parent and keep going until there is a parent to check or all parents are checked.
636  const xAOD::TruthParticle* parent = part->parent(i);
637  if(!parent) continue;
638  if( init_part->count(parent)) return true;
639  if( isLooping(parent, init_part) ) return true;
640  }
641  // If this point is reached, then it means that no parent needs to be checked.
642  // Hence, return false.
643  return false;
644  }
645 
646  // Define the function findInitial which finds the first parent of a particle that is not the particle itself.
647  const xAOD::TruthParticle* HadronOriginClassifier::findInitial(const xAOD::TruthParticle* part, bool looping, std::shared_ptr<std::set<const xAOD::TruthParticle*>> checked ) const{
648  // If the particle has no parent, return the particle.
649  if(!part->nParents()) return part;
650  if (!checked) checked = std::make_shared<std::set<const xAOD::TruthParticle*>>();
651  // Use a for to go through the parents.
652  for(unsigned int i=0; i<part->nParents(); ++i){
653  // Extract the i-th parent.
654  const xAOD::TruthParticle* parent = part->parent(i);
655  if(!parent) continue;
656  if(checked->count(parent) && looping) continue;
657  checked->insert(parent);
658  // If the parent has the same pdgId as the particle, then it means that the parent is the same as the considered particle.
659  // This happens if the particle irradiates for example.
660  // In this case, try to look for the first parent of i-th parent that is being considered.
661  // Repeat the process until you find a particle different from the considred one or that has no parent.
662 
663  if( part->pdgId() == parent->pdgId() ){
664  return findInitial(parent, looping, checked);
665  }
666  }
667  // In this case, no parent different from the considered particle has been found.
668  // Hence, return the particle.
669  return part;
670  }
671 
672 }//namespace
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
DerivationFramework::HadronOriginClassifier::isDirectlyMPIPythia8
bool isDirectlyMPIPythia8(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:606
DerivationFramework::HadronOriginClassifier::m_DSID
Gaudi::Property< int > m_DSID
Definition: HadronOriginClassifier.h:100
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
MCTruthPartClassifier::hadron
@ hadron
Definition: TruthClassifiers.h:148
DerivationFramework::HadronOriginClassifier::isFromTop
bool isFromTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:412
DerivationFramework::HadronOriginClassifier::isDirectlyMPISherpa
static bool isDirectlyMPISherpa(const xAOD::TruthParticle *part)
Definition: HadronOriginClassifier.cxx:611
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
DerivationFramework::HadronOriginClassifier::GEN_id::HerwigPP
@ HerwigPP
DerivationFramework::HadronOriginClassifier::b_FSR
@ b_FSR
Definition: HadronOriginClassifier.h:43
HadronOriginClassifier.h
DerivationFramework::HadronOriginClassifier::GEN_id::Sherpa
@ Sherpa
MC::Pythia8::isConditionC
bool isConditionC(const T &p)
Definition: HepMCHelpers.h:27
DerivationFramework::HadronOriginClassifier::c_FSR
@ c_FSR
Definition: HadronOriginClassifier.h:43
DerivationFramework::HadronOriginClassifier::IsHerwigPP
bool IsHerwigPP() const
Definition: HadronOriginClassifier.h:91
skel.it
it
Definition: skel.GENtoEVGEN.py:401
DerivationFramework::HadronOriginClassifier::GetOriginMap
std::map< const xAOD::TruthParticle *, HF_id > GetOriginMap() const
Definition: HadronOriginClassifier.cxx:162
DerivationFramework::HadronOriginClassifier::c_MPI
@ c_MPI
Definition: HadronOriginClassifier.h:42
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
DerivationFramework::HadronOriginClassifier::c_from_W
@ c_from_W
Definition: HadronOriginClassifier.h:44
DerivationFramework::HadronOriginClassifier::isDirectlyFSR
bool isDirectlyFSR(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:501
isBottomHadron
bool isBottomHadron(const T &p)
Definition: AtlasPID.h:812
master.gen
gen
Definition: master.py:32
DerivationFramework::HadronOriginClassifier::isFromGluonQuark
bool isFromGluonQuark(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:476
DerivationFramework::HadronOriginClassifier::c_from_top
@ c_from_top
Definition: HadronOriginClassifier.h:45
isGluon
bool isGluon(const T &p)
Definition: AtlasPID.h:328
DerivationFramework::HadronOriginClassifier::b_from_W
@ b_from_W
Definition: HadronOriginClassifier.h:44
DerivationFramework::HadronOriginClassifier::isFromQuarkTop
bool isFromQuarkTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:534
DerivationFramework::HadronOriginClassifier::fillHadronMap
void fillHadronMap(std::set< const xAOD::TruthParticle * > &usedHadron, std::map< const xAOD::TruthParticle *, int > &mainHadronMap, const xAOD::TruthParticle *mainhad, const xAOD::TruthParticle *ihad, bool decayed=false) const
Definition: HadronOriginClassifier.cxx:365
DerivationFramework::HadronOriginClassifier::~HadronOriginClassifier
virtual ~HadronOriginClassifier()
Definition: HadronOriginClassifier.cxx:36
MC::isPhysical
bool isPhysical(const T &p)
Identify if the particle is physical, i.e. is stable or decayed.
Definition: HepMCHelpers.h:51
DerivationFramework::HadronOriginClassifier::IsSherpa
bool IsSherpa() const
Definition: HadronOriginClassifier.h:94
AthCommonDataStore< AthCommonMsg< AlgTool > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
DerivationFramework::HadronOriginClassifier::findInitial
const xAOD::TruthParticle * findInitial(const xAOD::TruthParticle *part, bool looping, std::shared_ptr< std::set< const xAOD::TruthParticle * >> checked=nullptr) const
Definition: HadronOriginClassifier.cxx:647
DerivationFramework::HadronOriginClassifier::m_ttbb
bool m_ttbb
Definition: HadronOriginClassifier.h:102
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
DerivationFramework::HadronOriginClassifier::isDirectlyMPIPythia6
static bool isDirectlyMPIPythia6(const xAOD::TruthParticle *part, bool looping)
Definition: HadronOriginClassifier.cxx:595
isBottom
bool isBottom(const T &p)
Definition: AtlasPID.h:154
HepMC::is_simulation_particle
bool is_simulation_particle(const T &p)
Method to establish if a particle (or barcode) was created during the simulation (TODO update to be s...
Definition: MagicNumbers.h:355
DerivationFramework::HadronOriginClassifier::b_MPI
@ b_MPI
Definition: HadronOriginClassifier.h:42
lumiFormat.i
int i
Definition: lumiFormat.py:85
leadingQuark
int leadingQuark(const T &p)
Definition: AtlasPID.h:789
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
DerivationFramework::HadronOriginClassifier::GEN_id
GEN_id
Definition: HadronOriginClassifier.h:48
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:37
DerivationFramework::HadronOriginClassifier::isFromWTop
bool isFromWTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:439
DerivationFramework::HadronOriginClassifier::isDirectlyFSRPythia8
bool isDirectlyFSRPythia8(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:541
DerivationFramework::HadronOriginClassifier::m_GenUsed
GEN_id m_GenUsed
Definition: HadronOriginClassifier.h:101
test_pyathena.parent
parent
Definition: test_pyathena.py:15
DerivationFramework::HadronOriginClassifier::GEN_id::Pythia8
@ Pythia8
DerivationFramework::HadronOriginClassifier::isDirectlyFSRPythia6
bool isDirectlyFSRPythia6(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:481
DerivationFramework
THE reconstruction tool.
Definition: ParticleSortingAlg.h:24
DerivationFramework::HadronOriginClassifier::isDirectlyFromGluonQuark
static bool isDirectlyFromGluonQuark(const xAOD::TruthParticle *part, bool looping)
Definition: HadronOriginClassifier.cxx:465
DataVector
Derived DataVector<T>.
Definition: DataVector.h:794
DerivationFramework::HadronOriginClassifier::HadronOriginClassifier
HadronOriginClassifier(const std::string &t, const std::string &n, const IInterface *p)
Definition: HadronOriginClassifier.cxx:30
DerivationFramework::HadronOriginClassifier::isDirectlyFromQuarkTopPythia8
bool isDirectlyFromQuarkTopPythia8(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:562
DerivationFramework::HadronOriginClassifier::isDirectlyFromQuarkTop
bool isDirectlyFromQuarkTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:514
xAOD::TruthVertex_v1
Class describing a truth vertex in the MC record.
Definition: TruthVertex_v1.h:37
xAOD::TruthParticle_v1::nChildren
size_t nChildren() const
Number of children of this particle.
Definition: TruthParticle_v1.cxx:140
DerivationFramework::HadronOriginClassifier::isDirectlyFromTop
static bool isDirectlyFromTop(const xAOD::TruthParticle *part, bool looping)
Definition: HadronOriginClassifier.cxx:420
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:227
DerivationFramework::HadronOriginClassifier::IsPythia6
bool IsPythia6() const
Definition: HadronOriginClassifier.h:93
xAOD::TruthParticle_v1::child
const TruthParticle_v1 * child(size_t i) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
Definition: TruthParticle_v1.cxx:149
DerivationFramework::HadronOriginClassifier::m_mcName
Gaudi::Property< std::string > m_mcName
Definition: HadronOriginClassifier.h:97
python.PyAthena.v
v
Definition: PyAthena.py:154
DerivationFramework::HadronOriginClassifier::IsPythia8
bool IsPythia8() const
Definition: HadronOriginClassifier.h:92
isW
bool isW(const T &p)
Definition: AtlasPID.h:337
isTop
bool isTop(const T &p)
Definition: AtlasPID.h:157
DerivationFramework::HadronOriginClassifier::isDirectlyFromWTop
bool isDirectlyFromWTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:446
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
DerivationFramework::HadronOriginClassifier::IsTtBb
bool IsTtBb() const
Definition: HadronOriginClassifier.h:95
DerivationFramework::HadronOriginClassifier::isFromQuarkTopPythia8
bool isFromQuarkTopPythia8(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:588
xAOD::EgammaHelpers::isPhoton
bool isPhoton(const xAOD::Egamma *eg)
is the object a photon
Definition: EgammaxAODHelpers.cxx:21
isCharm
bool isCharm(const T &p)
Definition: AtlasPID.h:151
isCharmHadron
bool isCharmHadron(const T &p)
Definition: AtlasPID.h:811
DerivationFramework::HadronOriginClassifier::extrajet
@ extrajet
Definition: HadronOriginClassifier.h:41
AthAlgTool
Definition: AthAlgTool.h:26
HepMC::status
int status(const T &p)
Definition: MagicNumbers.h:138
DerivationFramework::HadronOriginClassifier::buildPartonsHadronsMaps
void buildPartonsHadronsMaps(std::map< const xAOD::TruthParticle *, int > &mainHadronMap, std::map< const xAOD::TruthParticle *, HF_id > &partonsOrigin) const
Definition: HadronOriginClassifier.cxx:230
HepMCHelpers.h
DerivationFramework::HadronOriginClassifier::b_from_top
@ b_from_top
Definition: HadronOriginClassifier.h:45
DerivationFramework::HadronOriginClassifier::isLooping
bool isLooping(const xAOD::TruthParticle *part, std::shared_ptr< std::set< const xAOD::TruthParticle * >> checked=nullptr) const
init_part needed to detect looping graphs (sherpa) up to know only seen at parton level
Definition: HadronOriginClassifier.cxx:624
DerivationFramework::HadronOriginClassifier::isCHadronFromB
bool isCHadronFromB(const xAOD::TruthParticle *part, std::shared_ptr< std::set< const xAOD::TruthParticle * >> checked=nullptr) const
Definition: HadronOriginClassifier.cxx:343
DerivationFramework::HadronOriginClassifier::GEN_id::Pythia6
@ Pythia6
DerivationFramework::HadronOriginClassifier::initialize
virtual StatusCode initialize() override
Definition: HadronOriginClassifier.cxx:38