ATLAS Offline Software
HadronOriginClassifier.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
6 
7 namespace DerivationFramework{
8 
9  HadronOriginClassifier::HadronOriginClassifier(const std::string& t, const std::string& n, const IInterface* p):
10  AthAlgTool(t,n,p),
11  m_mcName("TruthEvents"),
12  m_HadronPtMinCut(0),
13  m_HadronEtaMaxCut(0),
14  m_DSID(0)
15  {
16  declareInterface<DerivationFramework::HadronOriginClassifier>(this);
17 
18  declareProperty("MCCollectionName",m_mcName="TruthEvents");
19  declareProperty("HadronpTMinCut",m_HadronPtMinCut=5000.);
20  declareProperty("HadronetaMaxCut",m_HadronEtaMaxCut=2.5);
21  declareProperty("DSID",m_DSID=410000);
22  }
23 
24  //--------------------------------------------------------------------------
27  }
28 
29  //---------------------------------------------------------------------------
31  ATH_MSG_INFO("Initialize " );
32  ATH_MSG_INFO("DSID " << m_DSID );
33  // all Herwig++/Herwig7 showered samples
34  if( m_DSID==410003 || m_DSID == 410008 //aMC@NLO+Hpp
35  || m_DSID == 410004 || m_DSID == 410163 //Powheg+Hpp
36  || m_DSID == 410232 //first attempt for Powheg+H7
37  || m_DSID == 410233 //first attempt for aMC@NLO+H7
38  || (m_DSID>=410525 && m_DSID<=410530) //New Powheg+H7 samples
39  || (m_DSID>=407037 && m_DSID<=407040) //Powheg+Hpp MET/HT sliced
40  || m_DSID ==410536 || m_DSID == 410537
41  || m_DSID == 410245 //aMC@NLO+H++ , ttbb
42  || (m_DSID>=410557 && m_DSID<=410559) // new Powheg+H7, mc16
43  || (m_DSID>=411082 && m_DSID<=411090) //Powheg+H7 HF-filtered
44  || (m_DSID>=407354 && m_DSID<=407356) //Powheg+H7 ttbar HT-filtered
45  || m_DSID ==411233 || m_DSID==411234 //Powheg+H7.1.3 ttbar
46  || m_DSID == 411316 //Powheg+H7 allhad ttbar
47  || (m_DSID>=411329 && m_DSID<=411334) //Powheg+H7.1.3 ttbar HF-filtered
48  || (m_DSID>=411335 && m_DSID<=411337) //Powheg+H7.1.3 ttbar HT-filtered
49  || m_DSID ==412116 || m_DSID == 412117 //amc@NLO+H7.1.3 ttbar
50  || m_DSID ==504329 || m_DSID == 504333 || m_DSID == 504341 //amc@NLO+H7.2.1 refined ttZ
51  || (m_DSID >= 601239 && m_DSID <= 601240)
52  ){
54  if (m_DSID==410245 || (m_DSID >= 601239 && m_DSID <= 601240)){
55  m_ttbb=true;
56  }
57  }
58  // all Pythia8 showered samples
59  else if( m_DSID==410006 //Powheg+P8 old main31
60  || m_DSID==410500 //Powheg+P8 new main31, hdamp=mt
61  || (m_DSID>=410501 && m_DSID<=410508) //Powheg+P8 new main31, hdamp=1.5m // Boosted samples are included 410507 410508
62  || (m_DSID>=410511 && m_DSID<=410524) //Powheg+P8 new main31, hdamp=1.5mt, radiation systematics
63  || (m_DSID>=410531 && m_DSID<=410535) //Powheg+P8 allhad samples
64  || (m_DSID>=346343 && m_DSID<=346345) //Powheg+P8 ttH
65  || m_DSID==412123 // MG+P8 ttW
66  || m_DSID==410155 // aMC@NlO+P8 ttW
67  || m_DSID==410159 || m_DSID==410160 //aMC@NLO+P8, old settings
68  || (m_DSID>=410218 && m_DSID<=410220) // aMC@NlO+P8 ttZ
69  || (m_DSID>=410276 && m_DSID<=410278) // aMC@NlO+P8 ttZ_lowMass
70  || (m_DSID>=410225 && m_DSID<=410227) || m_DSID==410274 || m_DSID==410275 //aMC@NLO+P8, new settings
71  || m_DSID==410568 || m_DSID==410569 // nonallhad boosted c-filtered
72  || m_DSID==410244 //aMC@NLO+P8, ttbb (old)
73  || m_DSID==410441 || m_DSID==410442 //new aMC@NLO+P8 mc16, new shower starting scale
74  || (m_DSID>=410464 && m_DSID<=410466) //new aMC@NLO+P8 mc16, new shower starting scale, no shower weights
75  || (m_DSID>=410470 && m_DSID<=410472) || (m_DSID>=410480 && m_DSID<=410482) //new Powheg+P8 mc16
76  || m_DSID==410452 //new aMC@NLO+P8 FxFx mc16
77  || (m_DSID>=411073 && m_DSID<=411081) //Powheg+P8 HF-filtered
78  || (m_DSID>=412066 && m_DSID<=412074) //aMC@NLO+P8 HF-filtered
79  || (m_DSID>=411068 && m_DSID<=411070) //Powheg+P8 ttbb
80  || (m_DSID>=410265 && m_DSID<=410267) //aMC@NLO+P8 ttbb
81  || (m_DSID>=411178 && m_DSID<=411180) || (m_DSID==411275) //Powheg+P8 ttbb OTF production - ATLMCPROD-7240
82  || (m_DSID>=600791 && m_DSID<=600792) //Powheg+P8 ttbb - ATLMCPROD-9179
83  || (m_DSID>=600737 && m_DSID<=600738) //Powheg+P8 ttbb - ATLMCPROD-9179
84  || (m_DSID>=601226 && m_DSID<=601227) // Powheg+P8 ttbb bornzerodamp cut 5, ATLMCPROD-9694
85  || (m_DSID>=407342 && m_DSID<=407344) //Powheg+P8 ttbar HT-filtered
86  || (m_DSID>=407345 && m_DSID<=407347) //Powheg+P8 ttbar MET-filtered
87  || (m_DSID>=407348 && m_DSID<=407350) //aMC@NLO+P8 ttbar HT-filtered
88  || m_DSID==504330 || m_DSID==504331 || m_DSID==504332 || m_DSID==504334 || m_DSID==504335 || m_DSID==504336 || m_DSID==504338 || m_DSID==504342 || m_DSID==504343 || m_DSID==504344 || m_DSID==504346//aMC@NLO+P8 refined ttZ
89  || m_DSID==601491 || m_DSID==601492 //Pow+Py8 ttbar pTHard variations - ATLMCPROD-10168
90  || (m_DSID>=601495 && m_DSID<=601498) //Pow+Py8 ttbar pTHard variations - ATLMCPROD-10168
91  || (m_DSID>=601783 && m_DSID<=601784) // Powheg+P8 ttbb bornzerodamp cut 5 pThard variations - ATLMCPROD-10527
92  ){
94  if ( m_DSID==410244 //aMC@NLO+P8, ttbb (old)
95  || (m_DSID>=411068 && m_DSID<=411070) //Powheg+P8 ttbb
96  || (m_DSID>=410265 && m_DSID<=410267) //aMC@NLO+P8 ttbb
97  || (m_DSID>=411178 && m_DSID<=411180) || (m_DSID==411275) //Powheg+P8 ttbb OTF production - ATLMCPROD-7240
98  || (m_DSID>=600791 && m_DSID<=600792) // Powheg+P8 ttbb
99  || (m_DSID>=600737 && m_DSID<=600738) // Powheg+P8 ttbb dipole recoil
100  || (m_DSID>=601226 && m_DSID<=601227) // Powheg+P8 ttbb bornzerodamp cut 5
101  || (m_DSID>=601783 && m_DSID<=601784) // Powheg+P8 ttbb bornzerodamp cut 5 pThard variations - ATLMCPROD-10527
102  ){
103  m_ttbb=true;
104  }
105  }
106  // all Sherpa showered samples
107  else if( (m_DSID>=410186 && m_DSID<=410189) //Sherpa 2.2.0
108  || (m_DSID>=410249 && m_DSID<=410252) //Sherpa 2.2.1
109  || (m_DSID>=410342 && m_DSID<=410347) //Sherpa 2.2.1 sys
110  || (m_DSID>=410350 && m_DSID<=410355) //Sherpa 2.2.1 sys
111  || (m_DSID>=410357 && m_DSID<=410359) //Sherpa 2.2.1 sys
112  || (m_DSID>=410361 && m_DSID<=410367) //Sherpa 2.2.1 sys
113  || (m_DSID>=410281 && m_DSID<=410283) //Sherpa BFilter
114  || m_DSID==410051 //Sherpa ttbb (ICHEP sample)
115  || (m_DSID>=410323 && m_DSID<=410325) || (m_DSID==410369) //New Sherpa 2.2.1 ttbb
116  || (m_DSID>=364345 && m_DSID<=364348) //Sherpa 2.2.4 (test)
117  || (m_DSID>=410424 && m_DSID<=410427) //Sherpa 2.2.4
118  || (m_DSID>=410661 && m_DSID<=410664) //Sherpa 2.2.4 ttbb
119  || (m_DSID>=421152 && m_DSID<=421158) //Sherpa2.2.8 ttbar
120  || m_DSID==413023 // sherpa 2.2.1 ttZ
121  || m_DSID==700000 // Sherpa 2.2.8 ttW
122  || m_DSID==700168 // Sherpa 2.2.10 ttW
123  || m_DSID==700205 // Sherpa 2.2.10 ttW EWK
124  || m_DSID==700309 // Sherpa 2.2.11 ttZ
125  || (m_DSID>=700051 && m_DSID<=700054) //Sherpa2.2.8 ttbb
126  || (m_DSID>=700121 && m_DSID<=700124) //Sherpa2.2.10 ttbar
127  || (m_DSID>=700164 && m_DSID<=700167) //Sherpa2.2.10 ttbb
128  ){
130  if( m_DSID==410051
131  || (m_DSID>=410323 && m_DSID<=410325) || (m_DSID==410369)
132  || (m_DSID>=410661 && m_DSID<=410664)
133  || (m_DSID>=700051 && m_DSID<=700054)
134  || (m_DSID>=700164 && m_DSID<=700167)
135  ){
136  m_ttbb=true;
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
150  else{
152  }
153 
154  return StatusCode::SUCCESS;
155  }
156 
157  /*
158  --------------------------------------------------------------------------------------------------------------------------------------
159  ------------------------------------------------------------- Hadron Map -------------------------------------------------------------
160  --------------------------------------------------------------------------------------------------------------------------------------
161  */
162 
163  // Define the function GetOriginMap that determines the origin of the hadrons.
164 
165  std::map<const xAOD::TruthParticle*, DerivationFramework::HadronOriginClassifier::HF_id> HadronOriginClassifier::GetOriginMap() const {
166 
167  // Create a set of maps to store the information about the hadrons and the partons
168 
169  std::map<const xAOD::TruthParticle*, int> mainHadronMap; // Map with main hadrons and their flavor.
170  std::map<const xAOD::TruthParticle*, HF_id> partonsOrigin; // Map with partons and their category (from top, W, H, MPI, FSR, extra).
171  std::map<const xAOD::TruthParticle*, const xAOD::TruthParticle*> hadronsPartons; // Map with hadrons and their matched parton.
172  std::map<const xAOD::TruthParticle*, HF_id> hadronsOrigin; // Map with hadrons and their category (from top, W, H, MPI, FSR, extra)
173 
174  // Fill the maps mainHadronMap and partonsOrigin
175 
176  buildPartonsHadronsMaps(mainHadronMap, partonsOrigin);
177 
178  // Create two maps to know which partons and hadrons have already been matched.
179 
180  std::vector<const xAOD::TruthParticle*> matched_partons;
181  std::vector<const xAOD::TruthParticle*> matched_hadrons;
182 
183  // Use a while to go through the HF hadrons in mainHadronMap and partons in partonsOrigin.
184 
185  while (matched_partons.size()<partonsOrigin.size() && matched_hadrons.size()<mainHadronMap.size()){
186 
187  // Create a float variable to store the DeltaR between a parton and the closest hadron.
188 
189  float dR=999.;
190 
191  // Create two pointers for TruthParticle type to go through the partons and hadrons.
192 
193  const xAOD::TruthParticle* hadron=nullptr;
194  const xAOD::TruthParticle* parton=nullptr;
195 
196  // Use a for to go through the partonsOrigin.
197 
198  for(std::map<const xAOD::TruthParticle*, HF_id>::iterator itr = partonsOrigin.begin(); itr!=partonsOrigin.end(); ++itr){
199 
200  // Check if the parton has already been matched to an hadron.
201 
202  if(std::find(matched_partons.begin(), matched_partons.end(), (*itr).first) != matched_partons.end()) continue;
203 
204  // Extract the pt of the parton.
205 
206  TVector3 v, vtmp;
207  if ((*itr).first->pt()>0.)
208  v.SetPtEtaPhi((*itr).first->pt(),(*itr).first->eta(),(*itr).first->phi());
209  else // Protection against FPE from eta and phi calculation
210  v.SetXYZ(0.,0.,(*itr).first->pz());
211 
212  // Use a for to go through the HF hadrons in mainHadronMap.
213 
214  for(std::map<const xAOD::TruthParticle*, int>::iterator it = mainHadronMap.begin(); it!=mainHadronMap.end(); ++it){
215 
216  // Check if the hadron has already been matched to a parton.
217 
218  if(std::find(matched_hadrons.begin(), matched_hadrons.end(), (*it).first) != matched_hadrons.end()) continue;
219 
220  // Check if the hadron's flavour mathces the one of the parton.
221 
222  if((*it).second != abs((*itr).first->pdgId()) ) continue;
223 
224  // Extract the pt of the hadron.
225 
226  vtmp.SetPtEtaPhi((*it).first->pt(),(*it).first->eta(),(*it).first->phi());
227 
228  // Compute Delta R between hadron and parton and store in dR if it is smaller than the current value.
229  // Also store the parton and hadron in the pointers that have been previous created.
230 
231  if(vtmp.DeltaR(v) < dR){
232  dR = vtmp.DeltaR(v);
233  hadron = (*it).first;
234  parton = (*itr).first;
235  }
236 
237  }//loop hadrons
238 
239  }//loop partons
240 
241  // Add the matched part-hadron pair in the corresponding maps.
242 
243  matched_partons.push_back(parton);
244  matched_hadrons.push_back(hadron);
245 
246  hadronsPartons[ hadron ] = parton;
247  }
248 
249  // Use a for to go through the HF hadrons in mainHadronMap.
250 
251  for(std::map<const xAOD::TruthParticle*, int>::iterator it = mainHadronMap.begin(); it!=mainHadronMap.end(); ++it){
252 
253  // Extract the current hadron.
254 
255  const xAOD::TruthParticle* hadron = (*it).first;
256 
257  // Check if the hadron has been matched to a parton.
258  // If it has been matched to any hadron, use it to determine the origin.
259  // Otherwise, the hadron is considered extra.
260 
261  if(hadronsPartons.find(hadron)!=hadronsPartons.end()){
262  hadronsOrigin[hadron] = partonsOrigin[ hadronsPartons[hadron] ];
263  } else{
264  hadronsOrigin[hadron] = extrajet;
265  }
266  }
267 
268  return hadronsOrigin;
269  }
270 
271  // Define the function buildPartonsHadronsMaps that determines the flavour of the hadrons and the origin of the partons.
272 
273  void HadronOriginClassifier::buildPartonsHadronsMaps(std::map<const xAOD::TruthParticle*,int>& mainHadronMap, std::map<const xAOD::TruthParticle*,HF_id>& partonsOrigin) const {
274 
275  // Extract the TruthParticles container.
276 
277  const xAOD::TruthEventContainer* xTruthEventContainer = nullptr;
278  if (evtStore()->retrieve(xTruthEventContainer,m_mcName).isFailure()) {
279  ATH_MSG_WARNING("could not retrieve TruthEventContainer " <<m_mcName);
280  }
281 
282  // Create a container with TruthParticles to store the hadrons that has already been saved.
283 
284  std::set<const xAOD::TruthParticle*> usedHadron;
285 
286  for ( const auto* truthevent : *xTruthEventContainer ) {
287 
288  // Use a for to go through the TruthParticles.
289 
290  for(unsigned int i = 0; i < truthevent->nTruthParticles(); i++){
291 
292  // Extract the i-th particle.
293 
294  const xAOD::TruthParticle* part = truthevent->truthParticle(i);
295  if(!part) continue;
296 
297  // Simulated particles are not considered.
299 
300  // Create a set of boolean variables to indicate the type of particle.
301 
302  bool isbquark = false; // The particle is a b-quark.
303  bool iscquark = false; // The particle is a c-quark.
304  bool isHFhadron = false; // The particle is a HF hadron.
305 
306  // Extract the pdgid of the particle and use it to determine the type of particle.
307 
308  int pdgid = abs(part->pdgId());
309 
310  if(pdgid == 5 ){
311  isbquark=true;
312  }
313  else if(pdgid == 4 ){
314  iscquark=true;
315  }
317  isHFhadron=true;
318  }
319  else{
320  continue;
321  }
322 
323  // For HF quarks (b or c), check their category.
324  // The category is determined looking for the parents.
325 
326  if(isbquark){
327 
328  // In this case, the parton is a b-quark.
329  // Create a boolean that indicates when to stop to look for parents.
330 
331  bool islooping = isLooping(part);
332 
333  // Check the category of the b-quark.
334 
335  if(isDirectlyFromWTop(part, islooping)){
336  partonsOrigin[ part ] = b_from_W;
337  }
338  else if(isDirectlyFromTop(part, islooping)){
339  partonsOrigin[ part ] = b_from_top;
340  }
341  else if(!IsTtBb()&&(IsHerwigPP()||IsSherpa())&&isDirectlyFSR(part,islooping)){
342  partonsOrigin[ part ] = b_FSR;
343  }
344  else if(!IsTtBb()&&IsPythia8()&&isDirectlyFSRPythia8(part,islooping)){
345  partonsOrigin[ part ] = b_FSR;
346  }
347  else if(!IsTtBb()&&IsPythia6()&&isDirectlyFSRPythia6(part,islooping)){
348  partonsOrigin[ part ] = b_FSR;
349  }
350  else if(!IsTtBb()&&IsPythia6()&&isDirectlyMPIPythia6(part, islooping)){
351  partonsOrigin[ part ] = b_MPI;
352  }
353  else if(!IsTtBb()&&IsPythia8()&&isDirectlyMPIPythia8(part, islooping)){
354  partonsOrigin[ part ] = b_MPI;
355  }
356  else if(!IsTtBb()&&IsSherpa()&&isDirectlyMPISherpa(part)){
357  partonsOrigin[ part ] = b_MPI;
358  }
359  }
360  if(iscquark){
361 
362  // In this case, the parton is a c-quark.
363  // Create a boolean that indicates when to stop to look for parents.
364 
365  bool islooping = isLooping(part);
366 
367  // Check the category of the b-quark.
368 
369  if(isDirectlyFromWTop(part, islooping)){
370  partonsOrigin[ part ] = c_from_W;
371  }
372  else if(isDirectlyFromTop(part, islooping)){
373  partonsOrigin[ part ] = c_from_top;
374  }
375  else if(!IsTtBb()&&(IsHerwigPP()&&IsSherpa())&&isDirectlyFSR(part,islooping)){
376  partonsOrigin[ part ] = c_FSR;
377  }
378  else if(!IsTtBb()&&IsPythia8()&&isDirectlyFSRPythia8(part,islooping)){
379  partonsOrigin[ part ] = c_FSR;
380  }
381  else if(!IsTtBb()&&IsPythia6()&&isDirectlyFSRPythia6(part,islooping)){
382  partonsOrigin[ part ] = c_FSR;
383  }
384  else if(!IsTtBb()&&IsPythia6()&&isDirectlyMPIPythia6(part, islooping)){
385  partonsOrigin[ part ] = c_MPI;
386  }
387  else if(!IsTtBb()&&IsPythia8()&&isDirectlyMPIPythia8(part, islooping)){
388  partonsOrigin[ part ] = c_MPI;
389  }
390  else if(!IsTtBb()&&IsSherpa()&&isDirectlyMPISherpa(part)){
391  partonsOrigin[ part ] = c_MPI;
392  }
393  }
394 
395  // The HF hadrons are stored in the map mainHadronMap if they are not repeated.
396 
397  if(isHFhadron && !isCHadronFromB(part)){
398 
399  // In this case, the particle is a HF hadron but not a C-Hadron from a B-hadron.
400  // If the hadron is not in usedHadron, then add it in mainHadronMap with fillHadronMap function.
401 
402  if(usedHadron.insert(part).second) {
403  fillHadronMap(usedHadron, mainHadronMap,part,part);
404  }
405  }
406  }//loop on particles
407  }//loop on truthevent container
408 
409 
410 
411  }
412 
413  /*
414  ---------------------------------------------------------------------------------------------------------------------------------------
415  ------------------------------------------------------------ Particle Type ------------------------------------------------------------
416  ---------------------------------------------------------------------------------------------------------------------------------------
417  */
418 
420 
421  for(unsigned int i=0; i<part->nParents(); ++i){
422  const xAOD::TruthParticle* parent = part->parent(i);
423  if( HepMC::barcode(part) < HepMC::barcode(parent) ) continue;
424  int mothertype = std::abs(MC::leadingQuark(parent));
425  if( 4 == mothertype || 5 == mothertype ){
426  return true;
427  }
428  if(isQuarkFromHadron(parent))return true;
429  }
430 
431  return false;
432 
433  }
434 
436 
437  if(!MC::isCharmHadron(part)) return false;
438 
439  for(unsigned int i=0; i<part->nParents(); ++i){
440  const xAOD::TruthParticle* parent = part->parent(i);
441  if( HepMC::barcode(part) < HepMC::barcode(parent) ) continue;
442  if( MC::isBottomHadron(parent) ){
443  return true;
444  }
446  if(isCHadronFromB(parent))return true;
447  }
448  }
449 
450  return false;
451  }
452 
453  // Define the function fillHadronMap that fills the map of hadrons with their flavour.
454 
455  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 {
456 
457  // Fist, check that the consdired hadron has a non-null pointer
458 
459  if (!ihad) return;
460 
461  usedHadron.insert(ihad);
462 
463  // Create two variables to indicate the flavour of the parents and childrens particles that will be considered.
464  // Create a boolean to indicate if the particles considered are from the final state.
465 
466  int parent_flav,child_flav;
467  bool isFinal = true;
468 
469  // Check if the considered hadron has children.
470 
471  if(!ihad->nChildren()) return;
472 
473  // Use a for to go through the children.
474 
475  for(unsigned int j=0; j<ihad->nChildren(); ++j){
476 
477  // Extract the j-th children.
478 
479  const xAOD::TruthParticle* child = ihad->child(j);
480 
481  if(decayed){
482  fillHadronMap(usedHadron, mainHadronMap,mainhad,child,true);
483  isFinal=false;
484  }
485  else{
486  child_flav = std::abs(MC::leadingQuark(child));
487  if(child_flav!=4 && child_flav!=5) continue;
488  parent_flav = std::abs(MC::leadingQuark(mainhad));
489  if(child_flav!=parent_flav) continue;
490  fillHadronMap(usedHadron, mainHadronMap,mainhad,child);
491  isFinal=false;
492  }
493 
494  }
495 
496  if(isFinal && !decayed){
497 
498  mainHadronMap[mainhad]=std::abs(MC::leadingQuark(mainhad));
499 
500  for(unsigned int j=0; j<ihad->nChildren(); ++j){
501 
502  const xAOD::TruthParticle* child = ihad->child(j);
503 
504  fillHadronMap(usedHadron, mainHadronMap,mainhad,child,true);
505 
506  }
507  }
508 
509  }
510 
511 
512  //--------------------------------------------------------------------------
514  double pt = part->pt();
515  double eta = fabs(part->eta());
516 
517  if(pt<m_HadronPtMinCut) return false;
518  if(eta>m_HadronEtaMaxCut) return false;
519 
520  return true;
521  }
522 
523  /*
524  ---------------------------------------------------------------------------------------------------------------------------------------
525  ----------------------------------------------------------- Particle Origin -----------------------------------------------------------
526  ---------------------------------------------------------------------------------------------------------------------------------------
527  */
528 
529  // Define the function isFromTop that indicates if a particle comes from top.
530 
532 
533  // Find the first parent of the considered particle that is different from the particle.
534 
535  const xAOD::TruthParticle* initpart = findInitial(part, looping);
536 
537  // Check if this parent comes from the top with function isDirectlyFromTop.
538 
539  return isDirectlyFromTop(initpart, looping);
540  }
541 
542  // Define the function isDirectlyFromTop that indicates if a particle comes from the direct decay of top.
543 
545 
546  // First, make sure the consdired particle has a non-null pointer and it has parents.
547  // Otherwise, return false.
548 
549  if(!part || !part->nParents()) return false;
550 
551  // Go through the parents of the particle.
552 
553  for(unsigned int i=0; i<part->nParents(); ++i){
554 
555  // Extract the i-th parent.
556 
557  const xAOD::TruthParticle* parent = part->parent(i);
558 
559  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue; // protection for sherpa FIXME barcode-based
560 
561  // If the i-th parent is a top, then return true
562 
563  if( abs( parent->pdgId() ) == 6 ) return true;
564  }
565 
566  // If a top is no the parent, then return false.
567 
568  return false;
569  }
570 
571  // Define the function isFromWTop that indicates if a particle comes from the decay chain t->Wb.
572 
574 
575  // Find the first parent of the considered particle that is different from the particle.
576 
577  const xAOD::TruthParticle* initpart = findInitial(part, looping);
578 
579 
580 
581  return isDirectlyFromWTop(initpart, looping);
582  }
583 
584  // Define the function isDirectlyFromWTop that indicates if a particle comes from the direct decay of a W from a top.
585 
587 
588  // First, make sure the consdired particle has a non-null pointer and it has parents.
589  // Otherwise, return false.
590 
591  if(!part || !part->nParents()) return false;
592 
593  // Use a for to go though the parents.
594 
595  for(unsigned int i=0; i<part->nParents(); ++i){
596 
597  // Get the i-th parent.
598 
599  const xAOD::TruthParticle* parent = part->parent(i);
600  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue;
601  if( MC::isW(parent)){
602  if( isFromTop(parent, looping) ) return true;
603 
604  }
605  }
606 
607  // In this case, none of the parents of the particle is a W from top.
608  // Hence, return false.
609 
610  return false;
611  }
612 
614 
615 
616 
617  if(!part->nParents()) return false;
618 
619  for(unsigned int i=0; i<part->nParents(); ++i){
620  const xAOD::TruthParticle* parent = part->parent(i);
621  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue;
622  if( MC::isPhoton(parent) || abs(parent->pdgId())<5 ) return true;
623  }
624 
625  return false;
626  }
627 
629 
630  const xAOD::TruthParticle* initpart = findInitial(part, looping);
631  return isDirectlyFromGluonQuark(initpart, looping);
632 
633  }
634 
636 
637 
638  if(!part->nParents()) return false;
639 
640  for(unsigned int i=0; i<part->nParents(); ++i){
641  const xAOD::TruthParticle* parent = part->parent(i);
642  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue;
643  if(!MC::isW(parent)) continue;
644  if(abs(part->pdgId())==4){
645  //trick to get at least 50% of PowhegPythia c from FSR
646  if(part->pdgId()==-(parent->pdgId())/6){
647  if( isFromGluonQuark(parent, looping) ) return true;
648  }
649  }
650  else{
651  if( isFromGluonQuark(parent, looping) ) return true;
652  }
653  }
654  return false;
655  }
656 
658 
659 
660  if(!part->nParents()) return false;
661 
662  for(unsigned int i=0; i<part->nParents(); ++i){
663  const xAOD::TruthParticle* parent = part->parent(i);
664  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue;
666  if( isFromQuarkTop( parent,looping ) ) return true;
667  }
668 
669  }
670 
671  return false;
672 
673 
674  }
675 
677 
678 
679 
680  if(!part->nParents()) return false;
681 
682  for(unsigned int i=0; i<part->nParents(); ++i){
683  const xAOD::TruthParticle* parent = part->parent(i);
684  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue;
685  if( abs(parent->pdgId())<6 ) {
686 
687  if(isFromTop(parent,looping)){
688  return true;
689  }
690  else if(isFromWTop(parent,looping)){
691  return true;
692  }
693 
694  }
695  }
696 
697  return false;
698  }
699 
701 
702  const xAOD::TruthParticle* initpart = findInitial(part, looping);
703 
704  return isDirectlyFromQuarkTop(initpart, looping);
705 
706  }
707 
708  // Define the function isDirectlyFSRPythia8 that indicates if a particle comes from Final State Radiation in samples generated with Pythia8.
709 
711 
712  // First, check if the particle has parents and return false if it does not.
713 
714  if(!part->nParents()) return false;
715 
716  // Use a for to go through the parents.
717 
718  for(unsigned int i=0; i<part->nParents(); ++i){
719 
720  // Extract the i-th parent.
721 
722  const xAOD::TruthParticle* parent = part->parent(i);
723  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue;
725  if( isFromQuarkTopPythia8( parent,looping ) ) return true;
726  }
727 
728  }
729 
730  // In this case, no parent from the particle is a gluon or a photon coming from a top
731  // Hence, the particle is not from FSR and false is not returned.
732 
733  return false;
734 
735  }
736 
737  // Define the function isDirectlyFromQuarkTopPythia8 that indicates if a particle comes from direct decay of the top in samples generated with Pythia8.
738 
740 
741  // First, make sure the consdired particle has a non-null pointer and it has parents.
742  // Otherwise, return false.
743 
744  if(!part->nParents()) return false;
745 
746  // Use a for to go through the parents.
747 
748  for(unsigned int i=0; i<part->nParents(); ++i){
749 
750  // Extract the i-th parent.
751 
752  const xAOD::TruthParticle* parent = part->parent(i);
753 
754  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue; // protection for sherpa FIXME barcode-based.
755 
756  // Check if the parent is a quark different from the top.
757 
758  if( abs(parent->pdgId())<6 ) {
759 
760  // In this case, the parent is a quark different from top.
761  // Check if it comes from the decay chain of the t->Wb.
762  // If it is the case, return true.
763 
764  if(isFromWTop(parent,looping)){
765  return true;
766  }
767 
768  }
769  }
770 
771  // In this case, any of the parents of the particle comes from t->Wb chaing.
772  // Hence, the particle does not come from the top directly and false is returned.
773 
774  return false;
775  }
776 
777  // Define the function isFromQuarkTopPythia8 that indicates if a particle comes from top in samples generated with Pythia8.
778 
780 
781  // Find the first parent of the considered particle that is different from the particle.
782 
783  const xAOD::TruthParticle* initpart = findInitial(part, looping);
784 
785  // Check if this parent comes from the top with function isDirectlyFromQuarkTopPythia8.
786 
787  return isDirectlyFromQuarkTopPythia8(initpart, looping);
788 
789  }
790 
791 
792 
793 
794 
795 
797 
798  if(!part->nParents()) return false;
799 
800  for(unsigned int i=0; i<part->nParents(); ++i){
801  const xAOD::TruthParticle* parent = part->parent(i);
802  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping ) continue;
803  if( abs(parent->pdgId())== 2212 && MC::isPhysical(part)) return true;
804 
805  }
806 
807  return false;
808 
809  }
810 
811 
812 
814 
815 
816  const xAOD::TruthParticle* initpart = findInitial(part, looping);
817 
818  return initpart->status()>30 && initpart->status()<40;
819 
820  }
821 
823 
824  if(!part->hasProdVtx()) return false;
825 
826  const xAOD::TruthVertex* vertex = part->prodVtx();
827  return HepMC::status(vertex) == 2;
828 
829  }
830 
831  /*
832  --------------------------------------------------------------------------------------------------------------------------------------
833  ---------------------------------------------------------- Particle Parents ----------------------------------------------------------
834  --------------------------------------------------------------------------------------------------------------------------------------
835  */
836 
837  // Define the function isLooping that determines when to stop to look at the parents of a particle.
838 
839  bool HadronOriginClassifier::isLooping(const xAOD::TruthParticle* part, std::set<const xAOD::TruthParticle*> init_part) const{
840 
841  // First, check if the particle has parents and return false if it does not.
842 
843  if(!part->nParents()) return false;
844 
845  // In this case, the particle has parents.
846  // Store the particle in the container init_part.
847 
848  init_part.insert(part);
849 
850  // Use a for to go through the parents.
851 
852  for(unsigned int i=0; i<part->nParents(); ++i){
853 
854  // Get the i-th parent and check if it is in the container init_part.
855  // If it is not, return true because the parent need to be checked.
856  // Otherwise, check the parent of the parent and keep going until there is a parent to check or all parents are checked.
857 
858  const xAOD::TruthParticle* parent = part->parent(i);
859  if( init_part.find(parent) != init_part.end() ) return true;
860  if( isLooping(parent, init_part) ) return true;
861 
862  }
863 
864  // If this point is reached, then it means that no parent needs to be checked.
865  // Hence, return false.
866 
867  return false;
868 
869  }
870 
871  // Define the function findInitial which finds the first parent of a particle that is not the particle itself.
872 
874 
875  // If the particle has no parent, return the particle.
876 
877  if(!part->nParents()) return part;
878 
879  // Use a for to go through the parents.
880 
881  for(unsigned int i=0; i<part->nParents(); ++i){
882 
883  // Extract the i-th parent.
884 
885  const xAOD::TruthParticle* parent = part->parent(i);
886 
887  if( HepMC::barcode(part) < HepMC::barcode(parent) && looping) continue; // protection for sherpa FIXME barcode-based
888 
889  // If the parent has the same pdgId as the particle, then it means that the parent is the same as the considered particle.
890  // This happens if the particle irradiates for example.
891  // In this case, try to look for the first parent of i-th parent that is being considered.
892  // Repeat the process until you find a particle different from the considred one or that has no parent.
893 
894  if( part->pdgId() == parent->pdgId() ){
895  return findInitial(parent, looping);
896  }
897  }
898 
899  // In this case, no parent different from the considered particle has been found.
900  // Hence, return the particle.
901 
902  return part;
903  }
904 
905 }//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:813
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
MCTruthPartClassifier::hadron
@ hadron
Definition: TruthClassifiers.h:148
DerivationFramework::HadronOriginClassifier::isFromTop
bool isFromTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:531
DerivationFramework::HadronOriginClassifier::findInitial
const xAOD::TruthParticle * findInitial(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:873
DerivationFramework::HadronOriginClassifier::isDirectlyMPISherpa
static bool isDirectlyMPISherpa(const xAOD::TruthParticle *part)
Definition: HadronOriginClassifier.cxx:822
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
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
DerivationFramework::HadronOriginClassifier::b_FSR
@ b_FSR
Definition: HadronOriginClassifier.h:45
HadronOriginClassifier.h
DerivationFramework::HadronOriginClassifier::c_FSR
@ c_FSR
Definition: HadronOriginClassifier.h:45
DerivationFramework::HadronOriginClassifier::IsHerwigPP
bool IsHerwigPP() const
Definition: HadronOriginClassifier.h:98
skel.it
it
Definition: skel.GENtoEVGEN.py:423
test_pyathena.pt
pt
Definition: test_pyathena.py:11
DerivationFramework::HadronOriginClassifier::GetOriginMap
std::map< const xAOD::TruthParticle *, HF_id > GetOriginMap() const
Definition: HadronOriginClassifier.cxx:165
DerivationFramework::HadronOriginClassifier::HerwigPP
@ HerwigPP
Definition: HadronOriginClassifier.h:50
DerivationFramework::HadronOriginClassifier::c_MPI
@ c_MPI
Definition: HadronOriginClassifier.h:44
DerivationFramework::HadronOriginClassifier::m_HadronEtaMaxCut
double m_HadronEtaMaxCut
Definition: HadronOriginClassifier.h:106
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
DerivationFramework::HadronOriginClassifier::c_from_W
@ c_from_W
Definition: HadronOriginClassifier.h:46
DerivationFramework::HadronOriginClassifier::isDirectlyFSR
bool isDirectlyFSR(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:657
isBottomHadron
bool isBottomHadron(const T &p)
Definition: AtlasPID.h:466
DerivationFramework::HadronOriginClassifier::isFromGluonQuark
bool isFromGluonQuark(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:628
DerivationFramework::HadronOriginClassifier::c_from_top
@ c_from_top
Definition: HadronOriginClassifier.h:47
isGluon
bool isGluon(const T &p)
Definition: AtlasPID.h:158
DerivationFramework::HadronOriginClassifier::b_from_W
@ b_from_W
Definition: HadronOriginClassifier.h:46
DerivationFramework::HadronOriginClassifier::isFromQuarkTop
bool isFromQuarkTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:700
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:455
DerivationFramework::HadronOriginClassifier::~HadronOriginClassifier
virtual ~HadronOriginClassifier()
Definition: HadronOriginClassifier.cxx:25
MC::isPhysical
bool isPhysical(const T &p)
Definition: HepMCHelpers.h:32
DerivationFramework::HadronOriginClassifier::IsSherpa
bool IsSherpa() const
Definition: HadronOriginClassifier.h:101
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::m_ttbb
bool m_ttbb
Definition: HadronOriginClassifier.h:109
DerivationFramework::HadronOriginClassifier::isDirectlyMPIPythia6
static bool isDirectlyMPIPythia6(const xAOD::TruthParticle *part, bool looping)
Definition: HadronOriginClassifier.cxx:796
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:299
DerivationFramework::HadronOriginClassifier::b_MPI
@ b_MPI
Definition: HadronOriginClassifier.h:44
lumiFormat.i
int i
Definition: lumiFormat.py:92
leadingQuark
int leadingQuark(const T &p)
Definition: AtlasPID.h:444
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
HepMC::barcode
int barcode(const T *p)
Definition: Barcode.h:16
DerivationFramework::HadronOriginClassifier::Pythia8
@ Pythia8
Definition: HadronOriginClassifier.h:50
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:41
DerivationFramework::HadronOriginClassifier::isFromWTop
bool isFromWTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:573
DerivationFramework::HadronOriginClassifier::isDirectlyFSRPythia8
bool isDirectlyFSRPythia8(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:710
DerivationFramework::HadronOriginClassifier::m_GenUsed
GEN_id m_GenUsed
Definition: HadronOriginClassifier.h:108
DerivationFramework::HadronOriginClassifier::m_HadronPtMinCut
double m_HadronPtMinCut
Definition: HadronOriginClassifier.h:105
test_pyathena.parent
parent
Definition: test_pyathena.py:15
DerivationFramework::HadronOriginClassifier::isDirectlyFSRPythia6
bool isDirectlyFSRPythia6(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:635
DerivationFramework
THE reconstruction tool.
Definition: ParticleSortingAlg.h:24
DerivationFramework::HadronOriginClassifier::Pythia6
@ Pythia6
Definition: HadronOriginClassifier.h:50
DerivationFramework::HadronOriginClassifier::isDirectlyFromGluonQuark
static bool isDirectlyFromGluonQuark(const xAOD::TruthParticle *part, bool looping)
Definition: HadronOriginClassifier.cxx:613
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
DerivationFramework::HadronOriginClassifier::HadronOriginClassifier
HadronOriginClassifier(const std::string &t, const std::string &n, const IInterface *p)
Definition: HadronOriginClassifier.cxx:9
DerivationFramework::HadronOriginClassifier::isLooping
bool isLooping(const xAOD::TruthParticle *part, std::set< const xAOD::TruthParticle * > init_part=std::set< const xAOD::TruthParticle * >()) const
init_part needed to detect looping graphs (sherpa) and to switch on using barcode to resolve it witho...
Definition: HadronOriginClassifier.cxx:839
DerivationFramework::HadronOriginClassifier::isCHadronFromB
bool isCHadronFromB(const xAOD::TruthParticle *part) const
Definition: HadronOriginClassifier.cxx:435
DerivationFramework::HadronOriginClassifier::isDirectlyFromQuarkTopPythia8
bool isDirectlyFromQuarkTopPythia8(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:739
DerivationFramework::HadronOriginClassifier::isDirectlyFromQuarkTop
bool isDirectlyFromQuarkTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:676
xAOD::TruthVertex_v1
Class describing a truth vertex in the MC record.
Definition: TruthVertex_v1.h:41
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:544
DerivationFramework::HadronOriginClassifier::IsPythia6
bool IsPythia6() const
Definition: HadronOriginClassifier.h:100
python.PyAthena.v
v
Definition: PyAthena.py:157
DerivationFramework::HadronOriginClassifier::IsPythia8
bool IsPythia8() const
Definition: HadronOriginClassifier.h:99
DerivationFramework::HadronOriginClassifier::m_mcName
std::string m_mcName
Definition: HadronOriginClassifier.h:104
DerivationFramework::HadronOriginClassifier::isQuarkFromHadron
bool isQuarkFromHadron(const xAOD::TruthParticle *part) const
Definition: HadronOriginClassifier.cxx:419
isW
bool isW(const T &p)
Definition: AtlasPID.h:167
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
xAOD::TruthParticle_v1::status
int status() const
Status code.
DerivationFramework::HadronOriginClassifier::isDirectlyFromWTop
bool isDirectlyFromWTop(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:586
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
DerivationFramework::HadronOriginClassifier::passHadronSelection
bool passHadronSelection(const xAOD::TruthParticle *part) const
Definition: HadronOriginClassifier.cxx:513
DerivationFramework::HadronOriginClassifier::IsTtBb
bool IsTtBb() const
Definition: HadronOriginClassifier.h:102
DerivationFramework::HadronOriginClassifier::isFromQuarkTopPythia8
bool isFromQuarkTopPythia8(const xAOD::TruthParticle *part, bool looping) const
Definition: HadronOriginClassifier.cxx:779
xAOD::EgammaHelpers::isPhoton
bool isPhoton(const xAOD::Egamma *eg)
is the object a photon
Definition: EgammaxAODHelpers.cxx:21
xAOD::TruthParticle_v1::child
const TruthParticle_v1 * child(size_t i=0) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
Definition: TruthParticle_v1.cxx:149
isCharmHadron
bool isCharmHadron(const T &p)
Definition: AtlasPID.h:465
DerivationFramework::HadronOriginClassifier::m_DSID
int m_DSID
Definition: HadronOriginClassifier.h:107
DerivationFramework::HadronOriginClassifier::extrajet
@ extrajet
Definition: HadronOriginClassifier.h:43
AthAlgTool
Definition: AthAlgTool.h:26
HepMC::status
int status(const T &p)
Definition: MagicNumbers.h:130
DerivationFramework::HadronOriginClassifier::buildPartonsHadronsMaps
void buildPartonsHadronsMaps(std::map< const xAOD::TruthParticle *, int > &mainHadronMap, std::map< const xAOD::TruthParticle *, HF_id > &partonsOrigin) const
Definition: HadronOriginClassifier.cxx:273
HepMCHelpers.h
DerivationFramework::HadronOriginClassifier::b_from_top
@ b_from_top
Definition: HadronOriginClassifier.h:47
DerivationFramework::HadronOriginClassifier::Sherpa
@ Sherpa
Definition: HadronOriginClassifier.h:50
DerivationFramework::HadronOriginClassifier::initialize
virtual StatusCode initialize() override
Definition: HadronOriginClassifier.cxx:30