ATLAS Offline Software
CalcTopPartonHistory.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3  */
4 
5 // $Id: CalcTopPartonHistory.cxx 800464 2017-03-13 18:06:24Z tpelzer $
11 #include "xAODTruth/TruthVertex.h"
13 
14 namespace top {
16  asg::AsgTool(name),
17  m_config(nullptr) {
18  declareProperty("config", m_config);
19  }
20 
21  StatusCode CalcTopPartonHistory::buildContainerFromMultipleCollections(const std::vector<std::string> &collections, const std::string& out_contName)
22  {
24 
25  for(const std::string& collection : collections)
26  {
27  const xAOD::TruthParticleContainer* cont=nullptr;
28  ATH_CHECK(evtStore()->retrieve(cont,collection));
29  for(const xAOD::TruthParticle* p : *cont) out_cont->push_back(p);
30  }
31 
32  //we give control of the container to the store, because in this way we are able to retrieve it as a const data vector, see https://twiki.cern.ch/twiki/bin/view/AtlasComputing/DataVector#ConstDataVector
33  StatusCode save = evtStore()->tds()->record(out_cont,out_contName);
34  if (!save) return StatusCode::FAILURE;
35 
36  return StatusCode::SUCCESS;
37  }
38 
40  {
41  return decorateCollectionWithLinksToAnotherCollection("TruthBoson","TruthBosonsWithDecayParticles","AT_linkToTruthBosonsWithDecayParticles");
42  }
43 
44  StatusCode CalcTopPartonHistory::decorateCollectionWithLinksToAnotherCollection(const std::string &collectionToDecorate, const std::string &collectionToLink, const std::string &nameOfDecoration)
45  {
46  const xAOD::TruthParticleContainer* cont1(nullptr);
47  const xAOD::TruthParticleContainer* cont2(nullptr);
48  ATH_CHECK(evtStore()->retrieve(cont1,collectionToDecorate));
49  ATH_CHECK(evtStore()->retrieve(cont2,collectionToLink));
50 
51  for(const xAOD::TruthParticle *p : *cont1)
52  {
53 
54  const xAOD::TruthParticle* link =0;
55  for(const xAOD::TruthParticle *p2 : *cont2)
56  {
57  if(p->pdgId()==p2->pdgId() && HepMC::uniqueID(p) == HepMC::uniqueID(p2))
58  {
59  link=p2;
60  break;
61  }
62  }
63  p->auxdecor<const xAOD::TruthParticle*>(nameOfDecoration)=link;
64 
65  }
66  return StatusCode::SUCCESS;
67  }
68 
70  {
71  if(!part->isAvailable<const xAOD::TruthParticle*>(decorationName)) return part;
72 
73  const xAOD::TruthParticle* link=part->auxdecor<const xAOD::TruthParticle*>(decorationName);
74  if(link) return link;
75 
76  return part;
77  }
78 
82  // https://svnweb.cern.ch/trac/atlasphys-top/browser/Physics/Top/Software/MCvalidation/Rivet/Rivet2.X/trunk/routines/ATLAS_2014_I1304289/ATLAS_2014_I1304289.cc
84  TLorentzVector& top_afterFSR_SC_p4) {
86  // Vectors to hold any status=3 (anti-)top quarks (Pythia 6)
87  std::vector<const xAOD::TruthParticle*> v_status3_top;
88  // Vectors to hold any status=155 (anti-)top quarks (Herwig 6)
89  std::vector<const xAOD::TruthParticle*> v_status155_top;
90  // Vectors to hold any status=11 (anti-)top quarks for Herwig++
91  std::vector<const xAOD::TruthParticle*> v_status11_top;
92  // Vectors to hold any status=22 (anti-)top quarks
93  std::vector<const xAOD::TruthParticle*> v_statusOther_top;
94 
96  for (const xAOD::TruthParticle* particle : *truthParticles) {
97  if (particle->pdgId() != start) continue; // only keep particles of a given pdgID (e.g. 6 or -6)
98 
99  if (particle->status() == 3) {
100  v_status3_top.push_back(particle);
101  } else if (particle->status() == 155) {
102  v_status155_top.push_back(particle);
103  } else if (particle->status() == 11) {// for Herwig++: take only the tops that decay into Wb!!!
104  if (!particle->hasDecayVtx()) continue;
105  const xAOD::TruthVertex* vertex = particle->decayVtx();
106  if (vertex == nullptr) continue;
107  if (vertex->nOutgoingParticles() == 2) v_status11_top.push_back(particle);
108  } else {
109  v_statusOther_top.push_back(particle);
110  }
111  }
112 
114  // If there are more than 1 status 3 tops or anti-tops, only keep the last one put into the vector
115  if (v_status3_top.size() > 1) {
116  v_status3_top = std::vector<const xAOD::TruthParticle*>(v_status3_top.end() - 1, v_status3_top.end());
117  }
118  // If there are more than 1 status 11 tops or anti-tops, only keep the last one put into the vector
119  if (v_status11_top.size() > 1) {
120  v_status11_top = std::vector<const xAOD::TruthParticle*>(v_status11_top.end() - 1, v_status11_top.end());
121  }
122  // Rach: check for Pythia 8 as well
123  // If there are more than 1 status 3 tops or anti-tops, only keep the last one put into the vector
124  if (v_statusOther_top.size() > 1) {
125  v_statusOther_top = std::vector<const xAOD::TruthParticle*>(v_statusOther_top.end() - 1, v_statusOther_top.end());
126  }
127 
129  const xAOD::TruthParticle* top = nullptr;
130  // If there are status 3 tops and no status 155 tops this is probably a Pythia event, so used the status 3s.
131  if (v_status3_top.size() == 1 && v_status155_top.size() == 0) {
132  top = v_status3_top[0];
133  }
134  // If there are status 155 tops this must be a Herwig event, so use the status 155s.
135  if (v_status155_top.size() == 1 && v_status3_top.size() == 0) {
136  top = v_status155_top[0];
137  }
138  // If there are tops with other status this must be a Pythia8 event, so use them.
139  if (v_statusOther_top.size() == 1 && v_status155_top.size() == 0 && v_status3_top.size() == 0) {
140  top = v_statusOther_top[0];
141  }
142  // If there are status 155 tops this must be a Herwig event, so use the status 155s.
143  if (v_status11_top.size() == 1 && v_status3_top.size() == 0) {
144  top = v_status11_top[0];
145  }
146 
148  if (top != nullptr) {
149  top_afterFSR_SC_p4 = top->p4();
150  return true;
151  }
152  return false;
153  }
154 
155  // for b coming from W'->tb
157  TLorentzVector& b_beforeFSR, TLorentzVector& b_afterFSR) {
158  for (const xAOD::TruthParticle* particle : *truthParticles) {
159  if (abs(particle->pdgId()) != 5) continue;
160 
161  bool skipit(false);
162  for (size_t i = 0; i < particle->nParents(); i++) {
163  const xAOD::TruthParticle* parent = particle->parent(i);
164  if (parent && (parent->isTop() || abs(parent->pdgId()) == 5)) {
165  skipit = true;
166  break;
167  }//if
168  }//for
169 
170  if (skipit) continue;
171 
172  b_beforeFSR = particle->p4();
174 
175  return true;
176  }
177 
178 
179  return false;
180  }
181 
183  int start, TLorentzVector& t_beforeFSR_p4, TLorentzVector& t_afterFSR_p4,
184  TLorentzVector& W_p4,
185  TLorentzVector& b_p4, TLorentzVector& Wdecay1_p4,
186  int& Wdecay1_pdgId, TLorentzVector& Wdecay2_p4, int& Wdecay2_pdgId) {
187  bool hasT = false;
188  bool hasW = false;
189  bool hasB = false;
190  bool hasWdecayProd1 = false;
191  bool hasWdecayProd2 = false;
192 
193  for (const xAOD::TruthParticle* particle : *truthParticles) {
194  if (particle->pdgId() != start) continue;
195 
196  if (PartonHistoryUtils::hasParticleIdenticalParent(particle)) continue; // kepping only top before FSR
197 
198  t_beforeFSR_p4 = particle->p4(); // top before FSR
199  hasT = true;
200 
201  // demanding the last tops after FSR
203  t_afterFSR_p4 = particle->p4(); // top after FSR
204 
205  for (size_t k = 0; k < particle->nChildren(); k++) {
206  const xAOD::TruthParticle* topChildren = particle->child(k);
207 
208  if (abs(topChildren->pdgId()) == 24) {
209  W_p4 = topChildren->p4(); // W boson after FSR
210  hasW = true;
211 
212  // demanding the last W after FSR
213  topChildren = PartonHistoryUtils::findAfterFSR(topChildren);
214 
215  //for DAOD_PHYS we have to use a special procedure to associate W bosons linked from the top to those in the TruthBosonsWithDecayParticles collection, which have the correct links for their decay products
216  //this is better explained in the head; this will work only if the class calling this function has called linkBosonCollections() before
217  if(m_config->getDerivationStream() == "PHYS") topChildren=getTruthParticleLinkedFromDecoration(topChildren,"AT_linkToTruthBosonsWithDecayParticles");
218 
219  for (size_t q = 0; q < topChildren->nChildren(); ++q) {
220  const xAOD::TruthParticle* WChildren = topChildren->child(q);
221  if (abs(WChildren->pdgId()) < 17) {
222  if (WChildren->pdgId() > 0) {
223  Wdecay1_p4 = WChildren->p4();
224  Wdecay1_pdgId = WChildren->pdgId();
225  hasWdecayProd1 = true;
226  } else {
227  Wdecay2_p4 = WChildren->p4();
228  Wdecay2_pdgId = WChildren->pdgId();
229  hasWdecayProd2 = true;
230  }//else
231  }//if
232  }//for
233  } else if (abs(topChildren->pdgId()) == 5) {
234  b_p4 = topChildren->p4();
235  hasB = true;
236  } //else if
237  } //for (size_t k=0; k < particle->nChildren(); k++)
238 
239  if (hasT && hasW && hasB && hasWdecayProd1 && hasWdecayProd2) return true;
240 
241  } //for (const xAOD::TruthParticle* particle : *truthParticles)
242 
243  return false;
244  }
245 
247  int start, TLorentzVector& t_beforeFSR_p4, TLorentzVector& t_afterFSR_p4,
248  TLorentzVector& W_p4,
249  TLorentzVector& q_p4, int& q_pdgId, TLorentzVector& Wdecay1_p4,
250  int& Wdecay1_pdgId, TLorentzVector& Wdecay2_p4, int& Wdecay2_pdgId) {
251  bool hasT = false;
252  bool hasW = false;
253  bool hasQ = false;
254  bool hasWdecayProd1 = false;
255  bool hasWdecayProd2 = false;
256 
257  for (const xAOD::TruthParticle* particle : *truthParticles) {
258  if (particle->pdgId() != start) continue;
259 
260  if (PartonHistoryUtils::hasParticleIdenticalParent(particle)) continue; // kepping only top before FSR
261 
262  t_beforeFSR_p4 = particle->p4(); // top before FSR
263  hasT = true;
264 
265  // demanding the last tops after FSR
267  t_afterFSR_p4 = particle->p4(); // top after FSR
268 
269  for (size_t k = 0; k < particle->nChildren(); k++) {
270  const xAOD::TruthParticle* topChildren = particle->child(k);
271 
272  if (abs(topChildren->pdgId()) == 24) {
273  W_p4 = topChildren->p4(); // W boson after FSR
274  hasW = true;
275 
276  // demanding the last W after FSR
277  topChildren = PartonHistoryUtils::findAfterFSR(topChildren);
278 
279  for (size_t q = 0; q < topChildren->nChildren(); ++q) {
280  const xAOD::TruthParticle* WChildren = topChildren->child(q);
281  if (abs(WChildren->pdgId()) < 17) {
282  if (WChildren->pdgId() > 0) {
283  Wdecay1_p4 = WChildren->p4();
284  Wdecay1_pdgId = WChildren->pdgId();
285  hasWdecayProd1 = true;
286  } else {
287  Wdecay2_p4 = WChildren->p4();
288  Wdecay2_pdgId = WChildren->pdgId();
289  hasWdecayProd2 = true;
290  }//else
291  }//if
292  }//for
293  } else if (abs(topChildren->pdgId()) == 5 || abs(topChildren->pdgId()) == 3 || abs(topChildren->pdgId()) == 1) {
294  q_p4 = topChildren->p4();
295  q_pdgId = topChildren->pdgId();
296  hasQ = true;
297  } //else if
298  } //for (size_t k=0; k < particle->nChildren(); k++)
299  if (hasT && hasW && hasQ && hasWdecayProd1 && hasWdecayProd2) return true;
300  } //for (const xAOD::TruthParticle* particle : *truthParticles)
301 
302  return false;
303  }
304 
306  TLorentzVector& W_p4,
307  TLorentzVector& Wdecay1_p4, int& Wdecay1_pdgId,
308  TLorentzVector& Wdecay2_p4, int& Wdecay2_pdgId) {
309  bool hasW = false;
310  bool hasWdecayProd1 = false;
311  bool hasWdecayProd2 = false;
312 
313  for (const xAOD::TruthParticle* particle : *truthParticles) {
314  if (abs(particle->pdgId()) != 24) continue;
315  //std::cout << "PDGID: " << particle->pdgId() << std::endl;
316 
317  // demanding the last W after FSR
319  W_p4 = particle->p4(); // W boson after FSR
320  hasW = true;
321 
322  for (size_t k = 0; k < particle->nChildren(); k++) {
323  const xAOD::TruthParticle* WChildren = particle->child(k);
324  if (abs(WChildren->pdgId()) < 17) {
325  if (WChildren->pdgId() % 2 == 1) { // charged lepton in the Wlv case
326  Wdecay1_p4 = WChildren->p4();
327  Wdecay1_pdgId = WChildren->pdgId();
328  hasWdecayProd1 = true;
329  } else {// neutral lepton in the Wlv case
330  Wdecay2_p4 = WChildren->p4();
331  Wdecay2_pdgId = WChildren->pdgId();
332  hasWdecayProd2 = true;
333  }//else
334  }//if
335  } //for (size_t k=0; k < particle->nChildren(); k++)
336 
337  if (hasW && hasWdecayProd1 && hasWdecayProd2) return true;
338  } //for (const xAOD::TruthParticle* particle : *truthParticles)
339 
340 
341  return false;
342  }
343 
344  // for Wt ST events, find W that is not from top
346  TLorentzVector& W_p4, int& W_pdgId, TLorentzVector& Wdecay1_p4,
347  int& Wdecay1_pdgId, TLorentzVector& Wdecay2_p4, int& Wdecay2_pdgId) {
348  bool hasW = false;
349  bool hasWdecayProd1 = false;
350  bool hasWdecayProd2 = false;
351 
352  for (const xAOD::TruthParticle* particle : *truthParticles) {
353  if (particle == nullptr) continue;
354  if (abs(particle->pdgId()) != 24) continue; // W boson
355 
356  // need to check if the W is from top
357  // identify the first in chain and check
358  // if that particle has top as parent
359  if (PartonHistoryUtils::hasParticleIdenticalParent(particle)) continue; // kepping only W before FSR
360 
361  bool isFromTop = false;
362  // now we should have only the first W in chain
363  for (size_t iparent = 0; iparent < particle->nParents(); ++iparent) {
364  if (particle->parent(iparent) == nullptr) continue;
365  if (abs(particle->parent(iparent)->pdgId()) == 6) { // has top as parent
366  isFromTop = true;
367  break;
368  }
369  }
370 
371  if (isFromTop) continue;
372  else {
374  W_p4 = particle->p4();
375  W_pdgId = particle->pdgId();
376  hasW = true;
377  }
378 
379  // check the decay products of the W
380  for (size_t q = 0; q < particle->nChildren(); ++q) {
381  const xAOD::TruthParticle* WChildren = particle->child(q);
382  if (WChildren == nullptr) continue;
383  if (abs(WChildren->pdgId()) < 17) {
384  if (WChildren->pdgId() > 0) {
385  Wdecay1_p4 = WChildren->p4();
386  Wdecay1_pdgId = WChildren->pdgId();
387  hasWdecayProd1 = true;
388  } else {
389  Wdecay2_p4 = WChildren->p4();
390  Wdecay2_pdgId = WChildren->pdgId();
391  hasWdecayProd2 = true;
392  }//else
393  }//if
394  }//for
395 
396  if (hasW && hasWdecayProd1 && hasWdecayProd2) return true;
397  } // loop over truth particles
398 
399  return false;
400  }
401 
402  // for Wt ST events, find b that is not from top
404  TLorentzVector& b_beforeFSR, TLorentzVector& b_afterFSR,
405  int& b_pdgId) {
406  bool hasB = false;
407 
408  // identify "other" b quark that is not from radiation but from ME (Wtb)
409  // logic is simple: search for b quark that doesn't have top, proton, or
410  // nullptr as parent
411 
412  for (const xAOD::TruthParticle* particle : *truthParticles) {
413  if (particle == nullptr) continue;
414  if (abs(particle->pdgId()) != 5) continue;
415 
416  for (size_t iparent = 0; iparent < particle->nParents(); ++iparent) {
417  if (particle->parent(iparent) == nullptr) continue;
418 
419  // we dont want b-quarks that have b as parent
420  if (abs(particle->parent(iparent)->pdgId()) == 5) continue;
421 
422  // we dont want b-quarks that come from top
423  if (abs(particle->parent(iparent)->pdgId()) == 6) continue;
424 
425  // we dont want b-quarks that come from W
426  if (abs(particle->parent(iparent)->pdgId()) == 24) continue;
427 
428  // we dont want b-quarks that come from proton
429  if (abs(particle->parent(iparent)->pdgId()) == 2212) continue;
430 
431  hasB = true;
432  b_beforeFSR = particle->p4();
433  b_pdgId = particle->pdgId();
434 
435  // find after FSR
437  b_afterFSR = particle->p4();
438  }
439  }
440 
441 
442  if (hasB) return true;
443 
444  return false;
445  }
446 
447  // for ttbar + photon events
448  bool CalcTopPartonHistory::topPhWb(const xAOD::TruthParticleContainer* truthParticles, int topId,
449  TLorentzVector& t_beforeFSR_p4, TLorentzVector& t_afterFSR_p4,
450  TLorentzVector& Ph_p4, TLorentzVector& W_p4, TLorentzVector& b_p4,
451  TLorentzVector& Wdecay1_p4, int& Wdecay1_pdgId, TLorentzVector& Wdecay2_p4,
452  int& Wdecay2_pdgId, bool& has_ph, int& BranchType, int& IniPartonType,
453  bool& missingTop) {
454  bool hasT = false;
455  bool hasW = false;
456  bool hasAbsentW = false;
457  bool hasB = false;
458 
459  has_ph = false;
460  bool ph_W = false;
461  bool ph_Top = false;
462  bool ph_ISR = false;
463  bool ph_b = false;
464  bool hasWdecayProd1 = false;
465  bool hasWdecayProd2 = false;
466  missingTop = false;
467 
468  for (const xAOD::TruthParticle* particle : *truthParticles) {
469  if (particle->pdgId() != topId) continue;
470 
471  if (PartonHistoryUtils::hasParticleIdenticalParent(particle)) continue; // kepping only top before FSR
472  BranchType = -1;// 10(50): leptonic(hadronic), 12(52):topRad, 14(54):Wrad, 15(55):ISR, 18(58):b
473  IniPartonType = -1;
474 
475  // finding siblings
476  for (size_t iparent = 0; iparent < particle->nParents(); iparent++) {
477  if (abs(particle->parent(iparent)->pdgId()) == 21) {
478  IniPartonType = 1;
479  } // gg fusion
480  else if (abs(particle->parent(iparent)->pdgId()) < 6) {
481  IniPartonType = 2;
482  } //qq annihilation
483 
484  for (size_t ichild = 0; ichild < particle->parent(iparent)->nChildren(); ichild++) {
485  if (particle->parent(iparent)->child(ichild)->pdgId() == 22) {
486  const xAOD::TruthParticle* photon = PartonHistoryUtils::findAfterFSR(particle->parent(iparent)->child(ichild));
487  Ph_p4 = photon->p4();
488  has_ph = true;
489  ph_ISR = true;
490  }
491  if (!missingTop &&
492  (abs(particle->parent(iparent)->child(ichild)->pdgId()) == 5 ||
493  abs(particle->parent(iparent)->child(ichild)->pdgId()) == 24)) {
494  missingTop = true;
495  }
496  }
497  }
498 
499  t_beforeFSR_p4 = particle->p4(); // top before FSR
500  hasT = true;
501  // demanding the last tops after FSR
503  t_afterFSR_p4 = particle->p4(); // top after FSR
504 
505  for (size_t k = 0; k < particle->nChildren(); k++) {// top children
506  const xAOD::TruthParticle* topChildren = particle->child(k);
507 
508  if (abs(topChildren->pdgId()) == 24) {
509  W_p4 = topChildren->p4(); // W boson before FSR
510  hasW = true;
511 
512  // demanding the last W after FSR
513  topChildren = PartonHistoryUtils::findAfterFSR(topChildren);
514 
515  for (size_t q = 0; q < topChildren->nChildren(); q++) {// W children
516  const xAOD::TruthParticle* WChildren = topChildren->child(q);
517  if (abs(WChildren->pdgId()) > 0 && abs(WChildren->pdgId()) < 17) {
518  if (abs(WChildren->pdgId()) < 7) {
519  BranchType = 50;
520  }// hadronic
521  else if (abs(WChildren->pdgId()) > 10 && abs(WChildren->pdgId()) < 17) {
522  BranchType = 10;
523  }// leptonic
524  if (WChildren->pdgId() > 0) {
525  WChildren = PartonHistoryUtils::findAfterFSR(WChildren);
526  Wdecay1_p4 = WChildren->p4();
527  Wdecay1_pdgId = WChildren->pdgId();
528  hasWdecayProd1 = true;
529  } else {
530  WChildren = PartonHistoryUtils::findAfterFSR(WChildren);
531  Wdecay2_p4 = WChildren->p4();
532  Wdecay2_pdgId = WChildren->pdgId();
533  hasWdecayProd2 = true;
534  }//else
535  } else if (abs(WChildren->pdgId()) == 22) {// photon
536  // JUST FOR EXTRA SAFETY (not necessary)
537  // check if there exists a photon already
538  // if it does, check the photon's Pt
539  // if found harder then consider, else do nothing
540  if (has_ph) {
541  if (WChildren->p4().Pt() > Ph_p4.Pt()) {
542  ph_W = true;
543  ph_ISR = false;
544  ph_Top = false;
545  ph_b = false;
546  WChildren = PartonHistoryUtils::findAfterFSR(WChildren);
547  Ph_p4 = WChildren->p4();
548  }
549  } else {
550  has_ph = true;
551  ph_W = true;
552  WChildren = PartonHistoryUtils::findAfterFSR(WChildren);
553  Ph_p4 = WChildren->p4();
554  }
555  }
556  }// W children
557  } else if (abs(topChildren->pdgId()) == 5) { // b
558  hasB = true;
559  topChildren = PartonHistoryUtils::findAfterFSR(topChildren);// b After FSR
560  b_p4 = topChildren->p4();
561  // In MG5 generation of ttgamma it is not expected to have any b radiation 'recorded'
562  for (size_t b = 0; b < topChildren->nChildren(); b++) {// b Children
563  const xAOD::TruthParticle* bChildren = topChildren->child(b);
564  if (bChildren && MC::isPhoton(bChildren)) {
565  // JUST FOR EXTRA SAFETY (not necessary)
566  if (has_ph) {
567  if (bChildren->p4().Pt() > Ph_p4.Pt()) {
568  ph_b = true;
569  ph_ISR = false;
570  ph_Top = false;
571  ph_W = false;
572  bChildren = PartonHistoryUtils::findAfterFSR(bChildren);
573  Ph_p4 = bChildren->p4();
574  }
575  } else {
576  has_ph = true;
577  ph_b = true;
578  bChildren = PartonHistoryUtils::findAfterFSR(bChildren);
579  Ph_p4 = bChildren->p4();
580  }
581  }
582  }
583  } else if (MC::isPhoton(topChildren)) {
584  // JUST FOR EXTRA SAFETY (not necessary)
585  if (has_ph) {
586  if (topChildren->p4().Pt() > Ph_p4.Pt()) {
587  topChildren = PartonHistoryUtils::findAfterFSR(topChildren);
588  Ph_p4 = topChildren->p4();
589  ph_Top = true;
590  }
591  } else {
592  topChildren = PartonHistoryUtils::findAfterFSR(topChildren);
593  Ph_p4 = topChildren->p4();
594  has_ph = true;
595  ph_Top = true;
596  ph_W = false;
597  ph_ISR = false;
598  ph_b = false;
599  }
600  }
601  // sometimes the W is not recorded and the W products are recorded as top products
602  else if (abs(topChildren->pdgId()) <= 4 || (abs(topChildren->pdgId()) > 10 && abs(topChildren->pdgId()) < 17)) {
603  hasW = true;
604  hasAbsentW = true;
605  if (abs(topChildren->pdgId()) < 7) {
606  BranchType = 50;
607  }// hadronic
608  else if (abs(topChildren->pdgId()) > 10 && abs(topChildren->pdgId()) < 17) {
609  BranchType = 10;
610  }// leptonic
611  if (topChildren->pdgId() > 0) {
612  topChildren = PartonHistoryUtils::findAfterFSR(topChildren);
613  Wdecay1_p4 = topChildren->p4();
614  Wdecay1_pdgId = topChildren->pdgId();
615  hasWdecayProd1 = true;
616  } else {
617  topChildren = PartonHistoryUtils::findAfterFSR(topChildren);
618  Wdecay2_p4 = topChildren->p4();
619  Wdecay2_pdgId = topChildren->pdgId();
620  hasWdecayProd2 = true;
621  }//else
622  W_p4 = W_p4 + topChildren->p4();
623  }// if top children
624  } // for top children
625 
626  // BranchType Determination if there is a photon
627  if (hasAbsentW && (ph_Top || ph_W)) {
628  BranchType = -1;
629  }// if the W is not recorded and still the photon is from the top, the source of the photon is then ambiguous
630  // among top and W. BranchType would be +1. Category would be 0.
631  if (has_ph && ph_Top) {
632  BranchType = BranchType + 2;
633  }
634  if (has_ph && ph_W) {
635  BranchType = BranchType + 4;
636  }
637  if (has_ph && ph_ISR) {
638  BranchType = BranchType + 5;
639  }
640  if (has_ph && ph_b) {
641  BranchType = BranchType + 8;
642  }
643 
644  if (hasT && hasW && hasB && hasWdecayProd1 && hasWdecayProd2 && BranchType != -1) return true;
645  }// particle
646 
647  return false;
648  }
649 
651  // Get the Truth Particles
652  const xAOD::TruthParticleContainer* truthParticles(nullptr);
653 
654  if(m_config->getDerivationStream() == "PHYS") //in DAOD_PHYS we don't have the truth particles container
655  {
656  // To tops, we need the collections for it
657  std::vector<std::string> collections = {"TruthTop"};
658  ATH_CHECK(buildContainerFromMultipleCollections(collections,"AT_TOPPartonHistory_TruthParticles"));
659  ATH_CHECK(evtStore()->retrieve(truthParticles, "AT_TOPPartonHistory_TruthParticles"));
660 
661  //we need to be able to navigate from the Ws to their decayProducts, see CalcTopPartonHistory.h for details
663  }
664  else //otherwise we retrieve the container as usual
665  {
666  ATH_CHECK(evtStore()->retrieve(truthParticles, m_config->sgKeyMCParticle()));
667  }
668 
669  // Create the partonHistory xAOD object
670  //cppcheck-suppress uninitvar
672  //cppcheck-suppress uninitvar
674  partonCont->setStore(partonAuxCont);
675  //cppcheck-suppress uninitvar
676  xAOD::PartonHistory* partonHistory = new xAOD::PartonHistory {};
677  partonCont->push_back(partonHistory);
678 
679  // Save to StoreGate / TStore
680  std::string outputSGKey = m_config->sgKeyTopPartonHistory();
681  std::string outputSGKeyAux = outputSGKey + "Aux.";
682 
683  StatusCode save = evtStore()->tds()->record(partonCont, outputSGKey);
684  StatusCode saveAux = evtStore()->tds()->record(partonAuxCont, outputSGKeyAux);
685  if (!save || !saveAux) {
686  return StatusCode::FAILURE;
687  }
688 
689  return StatusCode::SUCCESS;
690  }
691 
692  void CalcTopPartonHistory::fillEtaBranch(xAOD::PartonHistory* partonHistory, std::string branchName,
693  TLorentzVector& tlv) {
694  if (tlv.CosTheta() == 1.) partonHistory->auxdecor< float >(branchName) = 1000.;
695  else if (tlv.CosTheta() == -1.) partonHistory->auxdecor< float >(branchName) = 1000.;
696  else partonHistory->auxdecor< float >(branchName) = tlv.Eta();
697  return;
698  }
699 }
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
xAOD::PartonHistory
Interface class.
Definition: PartonHistory.h:48
top::CalcTopPartonHistory::buildContainerFromMultipleCollections
StatusCode buildContainerFromMultipleCollections(const std::vector< std::string > &collections, const std::string &out_contName)
used to build container from multiple collections in DAOD_PHYS we don't have the TruthParticles colle...
Definition: CalcTopPartonHistory.cxx:21
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
top::CalcTopPartonHistory::topPhWb
bool topPhWb(const xAOD::TruthParticleContainer *truthParticles, int topId, TLorentzVector &t_beforeFSR_p4, TLorentzVector &t_afterFSR_p4, TLorentzVector &Ph_p4, TLorentzVector &W_p4, TLorentzVector &b_p4, TLorentzVector &Wdecay1_p4, int &Wdecay1_pdgId, TLorentzVector &Wdecay2_p4, int &Wdecay2_pdgId, bool &has_ph, int &BranchType, int &IniPartonType, bool &missingTop)
Store the four-momentum of photon coming from virtual top in ttgamma events.
Definition: CalcTopPartonHistory.cxx:448
top
TopConfig A simple configuration that is NOT a singleton.
Definition: AnalysisTrackingHelper.cxx:58
top::CalcTopPartonHistory::linkBosonCollections
StatusCode linkBosonCollections()
currently in DAOD_PHYS TruthTop have links to Ws from the TruthBoson collection, which have no link t...
Definition: CalcTopPartonHistory.cxx:39
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
SG::VIEW_ELEMENTS
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
Definition: OwnershipPolicy.h:18
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
mergePhysValFiles.start
start
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:14
top::CalcTopPartonHistory::getTruthParticleLinkedFromDecoration
const xAOD::TruthParticle * getTruthParticleLinkedFromDecoration(const xAOD::TruthParticle *part, const std::string &decorationName)
helper method to handle retriveing the truth particle linked in the decoration of another particle
Definition: CalcTopPartonHistory.cxx:69
asg
Definition: DataHandleTestTool.h:28
top::CalcTopPartonHistory::Wt_b
bool Wt_b(const xAOD::TruthParticleContainer *truthParticles, TLorentzVector &b_beforeFSR, TLorentzVector &b_afterFSR, int &b_pdgId)
Store the four-momentum of b quark that is NOT from top in Wt(b) ST events.
Definition: CalcTopPartonHistory.cxx:403
SG::AuxElement::auxdecor
Decorator< T, ALLOC >::reference_type auxdecor(const std::string &name) const
Fetch an aux decoration, as a non-const reference.
top::CalcTopPartonHistory::m_config
std::shared_ptr< top::TopConfig > m_config
Definition: CalcTopPartonHistory.h:87
top::CalcTopPartonHistory::Wt_W
bool Wt_W(const xAOD::TruthParticleContainer *truthParticles, TLorentzVector &W_p4, int &W_pdgId, TLorentzVector &Wdecay1_p4, int &Wdecay1_pdgId, TLorentzVector &Wdecay2_p4, int &Wdecay2_pdgId)
Store the four-momentum of several particles in W decay chain for W that is NOT from top in Wt ST eve...
Definition: CalcTopPartonHistory.cxx:345
AthCommonDataStore< AthCommonMsg< AlgTool > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
checkTP.save
def save(self, fileName="./columbo.out")
Definition: checkTP.py:178
top::CalcTopPartonHistory::b
bool b(const xAOD::TruthParticleContainer *truthParticles, TLorentzVector &b_beforeFSR, TLorentzVector &b_afterFSR)
Store the four-momentum of b (not from tops_ before and after FSR.
Definition: CalcTopPartonHistory.cxx:156
top::PartonHistoryUtils::findAfterFSR
const xAOD::TruthParticle * findAfterFSR(const xAOD::TruthParticle *particle)
Return particle after FSR (before the decay vertex)
Definition: PartonHistoryUtils.cxx:8
PartonHistory.h
lumiFormat.i
int i
Definition: lumiFormat.py:92
top::CalcTopPartonHistory::execute
virtual StatusCode execute()
Definition: CalcTopPartonHistory.cxx:650
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:41
PartonHistoryUtils.h
HepMC::uniqueID
int uniqueID(const T &p)
Definition: MagicNumbers.h:113
test_pyathena.parent
parent
Definition: test_pyathena.py:15
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
top::CalcTopPartonHistory::topAfterFSR_SC
bool topAfterFSR_SC(const xAOD::TruthParticleContainer *truthParticles, int start, TLorentzVector &top_afterFSR_SC_p4)
Store the four-momentum of the post-FSR top or anti-top found using statusCodes This would only work ...
Definition: CalcTopPartonHistory.cxx:83
top::CalcTopPartonHistory::topWq
bool topWq(const xAOD::TruthParticleContainer *truthParticles, int start, TLorentzVector &t_beforeFSR_p4, TLorentzVector &t_afterFSR_p4, TLorentzVector &W_p4, TLorentzVector &q_p4, int &q_pdgId, TLorentzVector &Wdecay1_p4, int &Wdecay1_pdgId, TLorentzVector &Wdecay2_p4, int &Wdecay2_pdgId)
Definition: CalcTopPartonHistory.cxx:246
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
TruthVertex.h
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
top::CalcTopPartonHistory::Wlv
bool Wlv(const xAOD::TruthParticleContainer *truthParticles, TLorentzVector &W_p4, TLorentzVector &Wdecay1_p4, int &Wdecay1_pdgId, TLorentzVector &Wdecay2_p4, int &Wdecay2_pdgId)
Store the four-momentum of several particles in the W decay chain.
Definition: CalcTopPartonHistory.cxx:305
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
ConstDataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
TopConfig.h
top::CalcTopPartonHistory::CalcTopPartonHistory
CalcTopPartonHistory(const std::string &name)
Definition: CalcTopPartonHistory.cxx:15
Trk::vertex
@ vertex
Definition: MeasurementType.h:21
CalcTtbarPartonHistory.h
xAOD::photon
@ photon
Definition: TrackingPrimitives.h:199
xAOD::PartonHistoryAuxContainer
Aux Container.
Definition: PartonHistory.h:41
ConstDataVector
DataVector adapter that acts like it holds const pointers.
Definition: ConstDataVector.h:76
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
top::CalcTopPartonHistory::decorateCollectionWithLinksToAnotherCollection
StatusCode decorateCollectionWithLinksToAnotherCollection(const std::string &collectionToDecorate, const std::string &collectionToLink, const std::string &nameOfDecoration)
helper method currently used in DAOD_PHYS to link particles from a given collection to the same parti...
Definition: CalcTopPartonHistory.cxx:44
extractSporadic.q
list q
Definition: extractSporadic.py:98
top::CalcTopPartonHistory::topWb
bool topWb(const xAOD::TruthParticleContainer *truthParticles, int start, TLorentzVector &t_beforeFSR_p4, TLorentzVector &t_afterFSR_p4, TLorentzVector &W_p4, TLorentzVector &b_p4, TLorentzVector &Wdecay1_p4, int &Wdecay1_pdgId, TLorentzVector &Wdecay2_p4, int &Wdecay2_pdgId)
Store the four-momentum of several particles in the top decay chain.
Definition: CalcTopPartonHistory.cxx:182
CalcTopPartonHistory.h
xAOD::TruthParticle_v1::p4
virtual FourMom_t p4() const override final
The full 4-momentum of the particle.
Definition: TruthParticle_v1.cxx:196
top::CalcTopPartonHistory::fillEtaBranch
void fillEtaBranch(xAOD::PartonHistory *partonHistory, std::string branchName, TLorentzVector &tlv)
Definition: CalcTopPartonHistory.cxx:692
xAOD::TruthParticle_v1::pdgId
int pdgId() const
PDG ID code.
top::PartonHistoryUtils::hasParticleIdenticalParent
bool hasParticleIdenticalParent(const xAOD::TruthParticle *particle)
Return true when particle is a top before FSR.
Definition: PartonHistoryUtils.cxx:28
HepMCHelpers.h
fitman.k
k
Definition: fitman.py:528