ATLAS Offline Software
ClassifyAndCalculateHFTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // //
7 // ClassifyAndCalculateHFTool.cxx //
8 // Implementation file for class ClassifyAndCalculateHFTool //
9 // Author: Adrian Berrocal Guardia <adrian.berrocal.guardia@cern.ch> //
10 // //
12 
15 
16 namespace DerivationFramework {
17 
18  /*
19  ---------------------------------------------------------------------------------------------------------------------------------------
20  ------------------------------------------------------- Constructor/Destructor --------------------------------------------------------
21  ---------------------------------------------------------------------------------------------------------------------------------------
22  */
23 
24  ClassifyAndCalculateHFTool::ClassifyAndCalculateHFTool(const std::string& t, const std::string& n, const IInterface* p) : AthAlgTool(t,n,p){
25  declareInterface<DerivationFramework::ClassifyAndCalculateHFTool>(this);
26  }
27 
29  }
30 
31  /*
32  ---------------------------------------------------------------------------------------------------------------------------------------
33  --------------------------------------------------------- Initialize/Finalize ---------------------------------------------------------
34  ---------------------------------------------------------------------------------------------------------------------------------------
35  */
36 
38 
39  ATH_MSG_INFO("Initialize");
40 
41  // Print the string variables.
42 
43  ATH_MSG_INFO("Cut on the pt of the jets: " << m_jetPtCut);
44  ATH_MSG_INFO("Cut on the eta of the jets: " << m_jetEtaCut);
45  ATH_MSG_INFO("Cut on the pt of the leading hadron: " << m_leadingHadronPtCut);
46  ATH_MSG_INFO("Cut on the ratio between the pt of the leading hadron and the pt of its associated jet: " << m_leadingHadronPtRatioCut);
47 
48  return StatusCode::SUCCESS;
49  }
50 
52  return StatusCode::SUCCESS;
53  }
54 
55  /*
56  ---------------------------------------------------------------------------------------------------------------------------------------
57  ------------------------------------------------------------- Hadron Type -------------------------------------------------------------
58  ---------------------------------------------------------------------------------------------------------------------------------------
59  */
60 
61  // Define the function isBHadron that determines if an hadron is a B-type.
62 
64 
65  // Check if the pdgId is too large to protect against some ions that could pass the test below.
66 
67  if(pdgId>1e9) return false;
68 
69  // Determine if the pdgId corresponds to a B-hadron.
70  // The PDG Id of quark composite states has 7-digits.
71  // The 3rd and 4th digits of the PDG Id starting from the end correspond to the largest PDG Id of the quarks.
72 
73  int rest1(std::abs(pdgId)%1000); // Three last digits of the PDG Id.
74  int rest2(std::abs(pdgId)%10000); // Four last digits of the PDF Id.
75 
76  // If the 3rd digit or 4th one is 5, then the hadron has a b-quark.
77 
78  if((rest2 >= 5000 && rest2 < 6000) || (rest1 >= 500 && rest1 < 600)) return true;
79 
80  return false;
81 
82  }
83 
84  // Define the function isCHadron that determines if an hadron is a C-type.
85 
87 
88  // Check if the pdgId is too large to protect against some ions that could pass the test below
89 
90  if(pdgId>1e9) return false;
91 
92  // Determine if the pdgId corresponds to a C-hadron.
93  // The PDG Id of quark composite states has 7-digits.
94  // The 3rd and 4th digits of the PDG Id starting from the end correspond to the largest PDG Id of the quarks.
95 
96  int rest1(std::abs(pdgId)%1000); // Three last digits of the PDG Id.
97  int rest2(std::abs(pdgId)%10000); // Four last digits of the PDF Id.
98 
99  // If the 3rd digit or 4th one is 4, then the hadron has a c-quark.
100  // The function does not consider if the case where the hadron has also a b-quark.
101  // Hence, the function isCHadron should only be called if the function isBHadron returns a false.
102 
103  if((rest2 >= 4000 && rest2 < 5000) || (rest1 >= 400 && rest1 < 500)) return true;
104 
105  return false;
106  }
107 
108  /*
109  ---------------------------------------------------------------------------------------------------------------------------------------
110  -------------------------------------------------------------- Flag Jets --------------------------------------------------------------
111  ---------------------------------------------------------------------------------------------------------------------------------------
112  */
113 
115  const std::map<const xAOD::Jet*, std::vector<xAOD::TruthParticleContainer::const_iterator>>& particleMatch,
116  const std::map<const xAOD::TruthParticle*, DerivationFramework::HadronOriginClassifier::HF_id>& hadronMap,
117  const std::string& hfDecorationName) const{
118 
119  SG::Decorator< int > decorator_flav(hfDecorationName + "_flav");
120  SG::Decorator< int > decorator_id(hfDecorationName + "_id");
121  SG::Decorator< int > decorator_count(hfDecorationName + "_count");
122 
123  for(const xAOD::Jet* jet : *jets){
124 
125  // Check if the jet passes the cuts and if it does not, then skip it.
126 
127  if(jet->p4().Pt() < m_jetPtCut || std::abs(jet->p4().Eta()) > m_jetEtaCut) {
128  decorator_flav(*jet) = -999;
129  decorator_id(*jet) = -999;
130  decorator_count(*jet) = -999;
131  continue;
132  }
133 
134  // Create a set of integer variables to save the necessary variables for the HF classifier:
135  // -flav: Flavour of the jet.
136  // -id: Origin of the most initial hadron of the jet.
137  // -count: Number of associated hadrons of the jet that have the same flavour as the jet.
138 
139  int flav=0;
140  int id=0;
141  int count=0;
142 
143  // Create a set of integer variables to save information that is required to compute the necessary variables for the HF classifier.:
144  // -bcount: It contains the number of B-hadrons.
145  // -ccount: It contains the number of C-hadrons.
146  // -bcountcut: It contains the number of B-hadron that pass the cuts.
147  // -ccountcut: It contains the number of C-hadron that pass the cuts.
148  // -bid: The greatest value of the variable "TopHadronOriginFlag" for B-hadrons (most initial B-hadron).
149  // -cid: The greatest value of the variable "TopHadronOriginFlag" for C-hadrons (most initial B-hadron).
150 
151  int bcount=0;
152  int ccount=0;
153  int bcountcut=0;
154  int ccountcut=0;
155 
156  int bid=0;
157  int cid=0;
158 
159  // Get the hadrons associated with the jet that is being considered.
160 
161  auto it = particleMatch.find (jet);
162  if (it != particleMatch.end()) {
163 
165 
166  // Create two integer variables:
167  // -hforigin: It will contain the origin of the hadron if it is a HF hadron. Otherwise, it will be 6.
168  // -pdgId: It will contain the value of the variable "pdgId" of the hadron.
169 
170  int hforigin = 6;
171  int pdgId = (*hf)->pdgId();
172 
173  // Extract the origin of the hadron.
174 
175  auto h_it = hadronMap.find(*hf);
176  if(h_it!=hadronMap.end()){
177  hforigin= static_cast<int>(h_it->second);
178  }
179 
180  // Check if hforigin is 6 and if it is the case, then hadron is not HF and it is skipped.
181 
182  if(6==hforigin) continue;
183 
184  // Compute the ratio between the pt of the hadron and the pt of its associated jet.
185 
186  float ptratio = (*hf)->p4().Pt()/jet->p4().Pt();
187 
188  // Determine if the hadron is a B-hadron or a C-hadron.
189 
190  int hftype = 0;
191 
192  if(ClassifyAndCalculateHFTool::isCHadron(pdgId)) hftype=4; // B-hadron
193  if(ClassifyAndCalculateHFTool::isBHadron(pdgId)) hftype=5; // C-hadron.
194 
195  // Check if hftype is 4 or 5.
196 
197  if(5==hftype){
198 
199  // In this case, hftype is 5 so the hadron is a B-hadron.
200  // Save hforigin in bid if it is greater than the current bid.
201 
202  if(bid<hforigin)bid=hforigin;
203 
204  // Add one to bcount and to bcountcut if hadron passes the cuts.
205 
206  ++bcount;
207 
208  if((*hf)->p4().Pt()>m_leadingHadronPtCut && ptratio>m_leadingHadronPtRatioCut){
209  ++bcountcut;
210  }
211  }
212  else if(4==hftype){
213 
214  // In this case, hftype is 4 so the hadron is a C-hadron.
215  // Save hforigin in cid if it is greater than the current cid.
216 
217  if(cid>hforigin)cid=hforigin;
218 
219  // Add one to ccount and to ccountcut if hadron passes the cuts.
220 
221  ++ccount;
222 
223  if((*hf)->p4().Pt()>m_leadingHadronPtCut && ptratio>m_leadingHadronPtRatioCut){
224  ++ccountcut;
225  }
226 
227  }
228  else{
229 
230  // In this case, hftype is not 4 neither 5 so print an error.
231 
232  ATH_MSG_WARNING("Hadron type '" << hftype << "' is not 4 or 5");
233 
234  }
235 
236  }
237  }
238 
239  // Check if there is at least one B-hadron or a C-hadron that passes the cuts.
240 
241  if(bcountcut){
242 
243  // In this case, at least one B-hadron passes the cuts.
244  // The "flavour" of the jet (flav) is set to 5.
245  // As a id of the jet, the greatest value of the variable "TopHadronOriginFlag" for B-hadrons is used (origin of the most initial hadron).
246  // The number of B-hadrons is saved in count.
247 
248  flav=5;
249  id=bid;
250  count=bcount;
251  }
252  else if(ccountcut){
253 
254  // In this case, no B-hadron passes the cuts, but at least one C-hadron does.
255  // The "flavour" of the jet (flav) is set to 4.
256  // As a id of the jet, the greatest value of the variable "TopHadronOriginFlag" for C-hadrons is used (origin of the most initial hadron).
257  // The number of C-hadrons is saved in count.
258 
259  flav=4;
260  id=cid;
261  count=ccount;
262  }
263 
264  // Dectorate the jet with the flav, id and count.
265  decorator_flav(*jet) = flav;
266  decorator_id(*jet) = id;
267  decorator_count(*jet) = count;
268  }
269 
270  }
271 
272  /*
273  ---------------------------------------------------------------------------------------------------------------------------------------
274  ---------------------------------------------------------- HF Classification ----------------------------------------------------------
275  ---------------------------------------------------------------------------------------------------------------------------------------
276  */
277 
278  int ClassifyAndCalculateHFTool::computeHFClassification(const xAOD::JetContainer* jets, const std::string& hfDecorationName) const{
279 
280  // Create a set of integer variables to save information that is required to compute the HF classifier.:
281  // -b: Number of jets that has just one B-hadron that passes the cuts.
282  // -B: Number of jets that has more than one B-hadron and at least one of them passes the cuts.
283  // -c: Number of jets that has just one C-hadron that passes the cuts (and no B-hadron)
284  // -C: Number of jets that has more than one C-hadron and at least one of them passes the cuts (and no B-hadron).
285  // -b_prompt: Number of jets that has just one prompt B-hadron that passes the cuts.
286  // -B_prompt: Number of jets that has more than one prompt B-hadron and at least one of them passes the cuts.
287  // -c_prompt: Number of jets that has just one prompt C-hadron that passes the cuts (and no B-hadron).
288  // -C_prompt: Number of jets that has more than one prompt C-hadron and at least one of them passes the cuts (and no B-hadron).
289  // -mpifsr_code: HF classifier for events with no prompt additional hadrons, just Multi-Parton Interaction (MPI) and/or Final State Radiation (FSR) hadrons.
290  // Note: prompt hadrons in this context are hadrons that do not come from the direct decay of top, W or Higgs but they are not from MPI or FSR.
291 
292  int b=0, B=0, c=0, C=0;
293  int b_prompt=0, B_prompt=0, c_prompt=0, C_prompt=0;
294 
295  int mpifsr_code=0;
296 
297  for(const xAOD::Jet* jet : *jets){
298 
299  // Check if the jet passes the cuts and if it does not, then skip it.
300 
301  if(jet->p4().Pt() < m_jetPtCut) continue;
302  if(std::abs(jet->p4().Eta()) > m_jetEtaCut) continue;
303 
304  // Get the flavour, the id and the number of hadrons of the considered jet.
305 
306  int flav = 0;
307  int id = 0;
308  int count = 0;
309 
310  SG::ConstAccessor<int> hfflavAcc(hfDecorationName + "_flav");
311  if(hfflavAcc.isAvailable(*jet)){
312  flav=hfflavAcc(*jet);
313  }else{
314  ATH_MSG_WARNING("variable '" + hfDecorationName + "_flav' not found.");
315  continue;
316  }
317 
318  SG::ConstAccessor<int> hfidAcc(hfDecorationName + "_id");
319  if(hfidAcc.isAvailable(*jet)){
320  id=hfidAcc(*jet);
321  }else{
322  ATH_MSG_WARNING("variable '" + hfDecorationName + "_id' not found.");
323  continue;
324  }
325 
326  SG::ConstAccessor<int> hfcountAcc(hfDecorationName + "_count");
327  if(hfcountAcc.isAvailable(*jet)){
328  count=hfcountAcc(*jet);
329  }else{
330  ATH_MSG_WARNING("variable '" + hfDecorationName + "_count' not found.");
331  continue;
332  }
333 
334  // Check the flavour and the id of the jet.
335 
336  if(flav==5 && id < 3){
337 
338  // In this case, the flavour is 5 and id is less than 3.
339  // This means that the jet has at least one B-hadron that is not from direct decay of top, W or Higgs.
340  // Hence, the jet is an additional one.
341 
342  // Check the number of B-hadrons.
343 
344  if(count > 1){
345 
346  // In this case, there is more than one B-hadron, so add 1 to B.
347 
348  B++;
349 
350  }
351  else{
352 
353  // In this case, there is just one B-hadron, so add 1 to b.
354 
355  b++;
356 
357  }
358  }
359  if(flav==4 && (id==0 || id==-1 || id==-2)){
360 
361  // In this case, the flavour is 4 and id is 0, -1 or -2.
362  // This means that the jet has no B-hadron and at least one C-hadron that is not from direct decay of top, W or Higgs.
363  // Hence, the jet is an additional one.
364 
365  // Check the number of C-hadrons.
366 
367  if(count > 1){
368 
369  // In this case, there is more than one C-hadron, so add 1 to C.
370 
371  C++;
372  }
373  else{
374 
375  // In this case, there is just one C-hadron, so add 1 to c.
376 
377  c++;
378  }
379  }
380 
381  // Check the flavour and the id of the jet but considering only prompt particles (id=0).
382 
383  if(flav==5 && id==0){
384 
385  // In this case, the flavour is 5 and id is 0.
386  // This means that the jet has at least one B-hadron that is not from direct decay of top, W or Higgs neither from MPI or FSR.
387 
388  // Check the number of B-hadrons.
389 
390  if(count > 1){
391 
392  // In this case, there is more than one B-hadron, so add 1 to B_prompt.
393 
394  B_prompt++;
395 
396  }
397  else{
398 
399  // In this case, there is jut one B-hadron, so add 1 to b_prompt.
400 
401  b_prompt++;
402 
403  }
404  }
405  if(flav==4 && id==0){
406 
407  // In this case, the flavour is 4 and id is 0.
408  // This means that the jet has no B-hadron and at least one C-hadron that is not from direct decay of top, W or Higgs neither from MPI or FSR.
409 
410  // Check the number of C-hadrons.
411 
412  if(count > 1){
413 
414  // In this case, there is more than one C-hadron, so add 1 to C_prompt.
415 
416  C_prompt++;
417  }
418  else{
419 
420  // In this case, there is just one C-hadron, so add 1 to C_prompt.
421 
422  c_prompt++;
423 
424  }
425  }
426 
427  // In the case when there is no prompt hadrons, then the HF classifier is computed with non-promt hadrons.
428  // This hadrons come from Multi-Parton Interactions (MPI) and the Final State Radiation (FSR).
429  // Compute mpifsr_code which will contain the HF classifier when there is no prompt hadrons.
430  // Each jet adds a different quantity to mpifsr_code depending on its flavour and its id.
431 
432  if(id==1 && flav==5){ // b MPI
433  mpifsr_code -= 1000;
434  }
435  else if(id==2 && flav==5){ // b FSR
436  mpifsr_code -= 100;
437  }
438  else if(id==-1 && flav==4){ // c MPI
439  mpifsr_code -= 10;
440  }
441  else if(id==-2 && flav==4) { // c FSR
442  mpifsr_code -= 1;
443  }
444  }
445 
446  // Compute the ext_code using the number of additional jets with HF hadrons.
447  // Compute the prompt_code using the number of additional jets with propmt HF hadrons.
448 
449  int ext_code = 1000*b+100*B+10*c+1*C;
450  int prompt_code = 1000*b_prompt+100*B_prompt+10*c_prompt+1*C_prompt;
451 
452  // Check if there are prompt hadrons and non-prompt hadrons using ext_code and prompt_code.
453 
454  if(prompt_code==0 && ext_code!=0){
455 
456  // In this case, there is no prompt hadrons but there are MPI and FSR hadrons.
457  // Hence, return mpifsr_code as a HF classifier, which is equal to ext_code but in negative sign.
458 
459  return mpifsr_code;
460 
461  }
462 
463  // In this case, there are prompt hadrons, so return ext_code as HF classifier.
464 
465  return ext_code;
466 
467  }
468 
470 
471  // Check the value of the HF classifier (hfclassif) which is computed with the function computeHFClassification.
472 
473  if(std::abs(hfclassif)>=100){
474 
475  // If the absolute value of hfclassif is greater than 100, then there is at least one jet with a B-hadron.
476  // In this case, return 1.
477 
478  return 1;
479 
480 
481  }
482  else if(hfclassif==0){
483 
484  // If hfclassif is 0, then there is no jet with a B-hadron or a C-hadron.
485  // In this case, return 0.
486 
487  return 0;
488  }
489 
490  // If the absolute value of hfclassif is lower than 100 and non-zero, then there is no jet with a B-hadron but at least one with a C-hadron.
491  // In this case, return -1.
492 
493  return -1;
494  }
495 }
DerivationFramework::ClassifyAndCalculateHFTool::flagJets
void flagJets(const xAOD::JetContainer *jets, const std::map< const xAOD::Jet *, std::vector< xAOD::TruthParticleContainer::const_iterator >> &particleMatch, const std::map< const xAOD::TruthParticle *, DerivationFramework::HadronOriginClassifier::HF_id > &hadronMap, const std::string &hfDecorationName) const
Definition: ClassifyAndCalculateHFTool.cxx:114
DerivationFramework::ClassifyAndCalculateHFTool::isCHadron
bool isCHadron(int pdgId) const
Definition: ClassifyAndCalculateHFTool.cxx:86
DataModel_detail::const_iterator
Const iterator class for DataVector/DataList.
Definition: DVLIterator.h:82
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
skel.it
it
Definition: skel.GENtoEVGEN.py:423
DerivationFramework::ClassifyAndCalculateHFTool::m_leadingHadronPtCut
Gaudi::Property< float > m_leadingHadronPtCut
Definition: ClassifyAndCalculateHFTool.h:106
SG::ConstAccessor< int >
DerivationFramework::ClassifyAndCalculateHFTool::~ClassifyAndCalculateHFTool
virtual ~ClassifyAndCalculateHFTool()
Definition: ClassifyAndCalculateHFTool.cxx:28
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
DerivationFramework::ClassifyAndCalculateHFTool::initialize
virtual StatusCode initialize() override
Definition: ClassifyAndCalculateHFTool.cxx:37
PowhegPy8EG_H2a.pdgId
dictionary pdgId
Definition: PowhegPy8EG_H2a.py:128
XMLtoHeader.count
count
Definition: XMLtoHeader.py:85
DerivationFramework::ClassifyAndCalculateHFTool::computeHFClassification
int computeHFClassification(const xAOD::JetContainer *jets, const std::string &hfDecorationName) const
Definition: ClassifyAndCalculateHFTool.cxx:278
jet
Definition: JetCalibTools_PlotJESFactors.cxx:23
DerivationFramework::ClassifyAndCalculateHFTool::m_jetPtCut
Gaudi::Property< float > m_jetPtCut
Definition: ClassifyAndCalculateHFTool.h:104
DerivationFramework::ClassifyAndCalculateHFTool::finalize
virtual StatusCode finalize() override
Definition: ClassifyAndCalculateHFTool.cxx:51
SG::Decorator< int >
DerivationFramework::ClassifyAndCalculateHFTool::m_leadingHadronPtRatioCut
Gaudi::Property< float > m_leadingHadronPtRatioCut
Definition: ClassifyAndCalculateHFTool.h:107
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
THE reconstruction tool.
Definition: ParticleSortingAlg.h:24
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
id
SG::auxid_t id
Definition: Control/AthContainers/Root/debug.cxx:191
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
DerivationFramework::ClassifyAndCalculateHFTool::m_jetEtaCut
Gaudi::Property< float > m_jetEtaCut
Definition: ClassifyAndCalculateHFTool.h:105
xAOD::Jet_v1
Class describing a jet.
Definition: Jet_v1.h:57
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
DerivationFramework::ClassifyAndCalculateHFTool::getSimpleClassification
int getSimpleClassification(int hfclassif) const
Definition: ClassifyAndCalculateHFTool.cxx:469
SG::ConstAccessor::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
defineDB.jets
list jets
Definition: JetTagCalibration/share/defineDB.py:24
DerivationFramework::ClassifyAndCalculateHFTool::ClassifyAndCalculateHFTool
ClassifyAndCalculateHFTool(const std::string &t, const std::string &n, const IInterface *p)
Definition: ClassifyAndCalculateHFTool.cxx:24
ClassifyAndCalculateHFTool.h
ConstAccessor.h
Helper class to provide constant type-safe access to aux data.
AthAlgTool
Definition: AthAlgTool.h:26
python.compressB64.c
def c
Definition: compressB64.py:93
DerivationFramework::ClassifyAndCalculateHFTool::isBHadron
bool isBHadron(int pdgId) const
Definition: ClassifyAndCalculateHFTool.cxx:63