ATLAS Offline Software
TTbarWToLeptonFilter.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 TTbarWToLeptonFilter::TTbarWToLeptonFilter(const std::string& name, ISvcLocator* pSvcLocator)
8  : GenFilter(name,pSvcLocator)
9 {
10  declareProperty("Ptcut", m_Ptmin=200000.);
11  declareProperty("NumLeptons", m_numLeptons=-1); // Negative for >0, positive integers for the specific number
12  declareProperty("fourTopsFilter", m_fourTopsFilter=false);//four top filter or not
13  declareProperty("SSMLFilter", m_SSMLFilter=false);//Same sign multilepton filter or not
14 
15 }
16 
17 
19  int N_quark_t = 0;
20  int N_quark_tbar = 0;
21  int N_quark_t_all = 0;
22  int N_quark_tbar_all = 0;
23  int N_pt_above_cut = 0;
24  int N_pt_above_cut_plus = 0;
25  int N_pt_above_cut_minus = 0;
26 
27  int foundlepton[6] = {0, 0, 0, 0, 0, 0}; // e+, e-, mu+, mu-, tau+, tau-
28  int count_found_leptons = 1; // In ttbar each charged lepton flavour is counted at most once
29  if(m_fourTopsFilter) count_found_leptons = 2; // In four tops, one can have the same charged lepton flavour twice
30 
31  for (McEventCollection::const_iterator itr = events()->begin(); itr!=events()->end(); ++itr) {
32  const HepMC::GenEvent* genEvt = (*itr);
33 #ifdef HEPMC3
34  for (const auto& pitr: *genEvt) {
35  if (std::abs(pitr->pdg_id()) != 6) continue;
36  if ( pitr->pdg_id() == 6 ) N_quark_t_all++;
37  if ( pitr->pdg_id() == -6 ) N_quark_tbar_all++;
38  auto decayVtx = pitr->end_vertex();
39  // Verify if we got a valid pointer and retrieve the number of daughters
40  if (!decayVtx) continue;
41  // For this analysis we are not interested in t->t MC structures, only in decays
42  if (decayVtx->particles_out().size() < 2) continue;
43  for (const auto& child_mcpart: decayVtx->particles_out()) {
44  // Implicitly assume that tops always decay to W X
45  if (std::abs(child_mcpart->pdg_id()) != 24) continue;
46  if ( pitr->pdg_id() == 6 ) N_quark_t++;
47  if ( pitr->pdg_id() == -6 ) N_quark_tbar++;
48 
49  bool useNextVertex = false;
50  auto w_decayVtx = child_mcpart->end_vertex();
51  while (w_decayVtx) {
52  useNextVertex = false;
53  for (const auto& grandchild_mcpart: *w_decayVtx) {
54  int grandchild_pid = grandchild_mcpart->pdg_id();
55  ATH_MSG_DEBUG("W (t/tbar) has " << w_decayVtx->particles_out().size() << " children and the pdg_id of the next is " << grandchild_pid);
56  // Check if the W's child is W again. If yes, then move to its next decay vertex in a decay tree
57  if (std::abs(grandchild_pid) == 24) {
58  w_decayVtx = grandchild_mcpart->end_vertex();
59  // If something wrong comes from truth...
60  if (!w_decayVtx) {
61  ATH_MSG_ERROR("A stable W is found... ");
62  break;
63  }
64  useNextVertex = true;
65  break;
66  }
67 
68  // use brute force to use only leptons that have not been found already
69  if (grandchild_pid == -11 && foundlepton[0] < count_found_leptons) {
70  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
71  foundlepton[0]++;
72  N_pt_above_cut++;
73  N_pt_above_cut_minus++;
74  }
75  }
76  if (grandchild_pid == 11 && foundlepton[1] < count_found_leptons) {
77  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
78  foundlepton[1]++;
79  N_pt_above_cut++;
80  N_pt_above_cut_plus++;
81 
82  }
83  }
84  if (grandchild_pid == -13 && foundlepton[2] < count_found_leptons) {
85  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
86  foundlepton[2]++;
87  N_pt_above_cut++;
88  N_pt_above_cut_minus++;
89  }
90  }
91  if (grandchild_pid == 13 && foundlepton[3] < count_found_leptons) {
92  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
93  foundlepton[3]++;
94  N_pt_above_cut++;
95  N_pt_above_cut_plus++;
96  }
97  }
98  if (grandchild_pid == -15 && foundlepton[4] < count_found_leptons) {
99  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
100  foundlepton[4]++;
101  N_pt_above_cut++;
102  N_pt_above_cut_minus++;
103  }
104  }
105  if (grandchild_pid == 15 && foundlepton[5] < count_found_leptons) {
106  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
107  foundlepton[5]++;
108  N_pt_above_cut++;
109  N_pt_above_cut_plus++;
110  }
111  }
112  }
113  // If investigation of W's next decay vertex is not required then finish looking for leptons
114  if (!useNextVertex) break;
115  }
116  }
117  }
118 #else
119  for (HepMC::GenEvent::particle_const_iterator pitr = genEvt->particles_begin(); pitr != genEvt->particles_end(); ++pitr) {
120  if (std::abs((*pitr)->pdg_id()) == 6) {
121  if ( (*pitr)->pdg_id() == 6 ) N_quark_t_all++;
122  if ( (*pitr)->pdg_id() == -6 ) N_quark_tbar_all++;
123 
124  int n_daughters = 0;
125 
126  HepMC::GenParticle * mcpart = (*pitr);
127  const HepMC::GenVertex * decayVtx = mcpart->end_vertex();
128 
129  // Verify if we got a valid pointer and retrieve the number of daughters
130  if (decayVtx != 0) n_daughters = decayVtx->particles_out_size();
131 
132  // For this analysis we are not interested in t->t MC structures, only in decays
133  if (n_daughters >= 2) {
134  HepMC::GenVertex::particles_in_const_iterator child_mcpartItr = decayVtx->particles_out_const_begin();
135  HepMC::GenVertex::particles_in_const_iterator child_mcpartItrE = decayVtx->particles_out_const_end();
136  for (; child_mcpartItr != child_mcpartItrE; ++child_mcpartItr) {
137  HepMC::GenParticle * child_mcpart = (*child_mcpartItr);
138 
139  // Implicitly assume that tops always decay to W X
140  if (std::abs(child_mcpart->pdg_id()) == 24) {
141  if ( (*pitr)->pdg_id() == 6 ) N_quark_t++;
142  if ( (*pitr)->pdg_id() == -6 ) N_quark_tbar++;
143 
144  bool useNextVertex = false;
145  const HepMC::GenVertex * w_decayVtx = child_mcpart->end_vertex();
146 
147  while (w_decayVtx) {
148 
149  useNextVertex = false;
150  int mcpart_n_particles_out = w_decayVtx->particles_out_size();
151 
152  HepMC::GenVertex::particles_out_const_iterator grandchild_mcpartItr = w_decayVtx->particles_out_const_begin();
153  HepMC::GenVertex::particles_out_const_iterator grandchild_mcpartItrE = w_decayVtx->particles_out_const_end();
154 
155  for (; grandchild_mcpartItr != grandchild_mcpartItrE; ++grandchild_mcpartItr) {
156  HepMC::GenParticle * grandchild_mcpart = (*grandchild_mcpartItr);
157  int grandchild_pid = grandchild_mcpart->pdg_id();
158 
159  // cppcheck-suppress shiftNegative; false positive!
160  ATH_MSG_DEBUG("W (t/tbar) has " << mcpart_n_particles_out << " children and the pdg_id of the next is " << grandchild_pid);
161 
162  // Check if the W's child is W again. If yes, then move to its next decay vertex in a decay tree
163  if (std::abs(grandchild_pid) == 24) {
164  w_decayVtx = grandchild_mcpart->end_vertex();
165 
166  // If something wrong comes from truth...
167  if (!w_decayVtx) {
168  ATH_MSG_ERROR("A stable W is found... ");
169  break;
170  }
171 
172  useNextVertex = true;
173  break;
174  }
175 
176  // use brute force to use only leptons that have not been found already
177  if (grandchild_pid == -11 && foundlepton[0] < count_found_leptons) {
178  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
179  foundlepton[0]++;
180  N_pt_above_cut++;
181  N_pt_above_cut_minus++;
182  }
183  }
184  if (grandchild_pid == 11 && foundlepton[1] < count_found_leptons) {
185  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
186  foundlepton[1]++;
187  N_pt_above_cut++;
188  N_pt_above_cut_plus++;
189 
190  }
191  }
192  if (grandchild_pid == -13 && foundlepton[2] < count_found_leptons) {
193  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
194  foundlepton[2]++;
195  N_pt_above_cut++;
196  N_pt_above_cut_minus++;
197  }
198  }
199  if (grandchild_pid == 13 && foundlepton[3] < count_found_leptons) {
200  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
201  foundlepton[3]++;
202  N_pt_above_cut++;
203  N_pt_above_cut_plus++;
204  }
205  }
206  if (grandchild_pid == -15 && foundlepton[4] < count_found_leptons) {
207  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
208  foundlepton[4]++;
209  N_pt_above_cut++;
210  N_pt_above_cut_minus++;
211  }
212  }
213  if (grandchild_pid == 15 && foundlepton[5] < count_found_leptons) {
214  if (grandchild_mcpart->momentum().perp() >= m_Ptmin) {
215  foundlepton[5]++;
216  N_pt_above_cut++;
217  N_pt_above_cut_plus++;
218  }
219  }
220 
221  }
222 
223  // If investigation of W's next decay vertex is not required then finish looking for leptons
224  if (!useNextVertex) break;
225  }
226  }
227  }
228  }
229  }
230  }
231 #endif
232  }
233 
234  ATH_MSG_INFO("Found " << N_quark_t_all << " t quarks in event record");
235  ATH_MSG_INFO("Found " << N_quark_tbar_all << " tbar quarks in event record");
236  ATH_MSG_INFO("Found " << N_quark_t << " t -> W X decays");
237  ATH_MSG_INFO("Found " << N_quark_tbar << " tbar -> W X decays");
238  ATH_MSG_INFO("Num leptons from W decays from tops with lepton pt above " << m_Ptmin/1000.0 << " Gaudi::Units::GeV/c = " << N_pt_above_cut);
239 
240  int count_tops = 1;
241  if(m_fourTopsFilter) count_tops = 2;
242  if (N_quark_t_all < count_tops || N_quark_tbar_all < count_tops) {
243 
244  ATH_MSG_ERROR("No t or tbar quarks were found in a (presumably) ttbar event! Event is rejected.");
245  setFilterPassed(false);
246  return StatusCode::SUCCESS;
247  }
248 
249  if (N_quark_t < count_tops || N_quark_tbar < count_tops) {
250 
251  ATH_MSG_ERROR("No t or tbar quarks were found decaying to W in a (presumably) ttbar event! Event is rejected. Event dump follows.");
252  int event = 0;
253  for (McEventCollection::const_iterator itr = events()->begin(); itr!=events()->end(); ++itr) {
254  event++;
255  const HepMC::GenEvent* genEvt = (*itr);
256  int part=0 ;
257  for (const auto& mcpart: *genEvt) {
258  part++;
259  int pid = mcpart->pdg_id();
260  ATH_MSG_ERROR("In event (from MC collection) " << event << " particle number " << part << " has pdg_id = " << pid);
261  // retrieve decay vertex
262  auto decayVtx = mcpart->end_vertex();
263  // verify if we got a valid pointer
264  if ( !decayVtx ) continue;
265  int part_child=0;
266  for (const auto& child_mcpart: *decayVtx) {
267  part_child++;
268  int child_pid = child_mcpart->pdg_id();
269  ATH_MSG_ERROR(" child " << part_child << " with pdg_id = " << child_pid);
270  }
271  }
272  }
273  setFilterPassed(false);
274  return StatusCode::SUCCESS;
275  }
276 
277  // If NumLeptons is negative (default), accept if Nlep > 0, otherwise only accept an exact match
278  if (m_numLeptons < 0) {
279  if ( (N_quark_t >= 2 || N_quark_tbar >= 2) && !m_fourTopsFilter) {
280  ATH_MSG_WARNING("More than one t -> W X or tbar -> W X decays found. Event is accepted anyway.");
281  }
282  if ( (N_quark_t > 2 || N_quark_tbar > 2) && m_fourTopsFilter) {
283  ATH_MSG_WARNING("More than one t -> W X or tbar -> W X decays found. Event is accepted anyway.");
284  }
285  setFilterPassed(N_pt_above_cut > 0);
286  } else {
287  if(m_fourTopsFilter){
288  if(m_SSMLFilter) setFilterPassed( (N_pt_above_cut >= m_numLeptons) && (N_pt_above_cut_plus >= 2 || N_pt_above_cut_minus >= 2));
289  else setFilterPassed(N_pt_above_cut >= m_numLeptons);}
290  else setFilterPassed(N_pt_above_cut == m_numLeptons);
291  }
292 
293  return StatusCode::SUCCESS;
294 }
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
TTbarWToLeptonFilter::m_SSMLFilter
bool m_SSMLFilter
Definition: TTbarWToLeptonFilter.h:27
DataModel_detail::const_iterator
Const iterator class for DataVector/DataList.
Definition: DVLIterator.h:82
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
TTbarWToLeptonFilter::m_numLeptons
int m_numLeptons
Definition: TTbarWToLeptonFilter.h:25
TTbarWToLeptonFilter.h
AthCommonDataStore< AthCommonMsg< Algorithm > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
PlotCalibFromCool.begin
begin
Definition: PlotCalibFromCool.py:94
python.DataFormatRates.events
events
Definition: DataFormatRates.py:105
TTbarWToLeptonFilter::m_Ptmin
double m_Ptmin
Definition: TTbarWToLeptonFilter.h:24
GenFilter
Base class for event generator filtering modules.
Definition: GenFilter.h:30
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
event
POOL::TEvent event(POOL::TEvent::kClassAccess)
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
ParticleGun_EoverP_Config.pid
pid
Definition: ParticleGun_EoverP_Config.py:62
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
TTbarWToLeptonFilter::TTbarWToLeptonFilter
TTbarWToLeptonFilter(const std::string &name, ISvcLocator *pSvcLocator)
Definition: TTbarWToLeptonFilter.cxx:7
TTbarWToLeptonFilter::filterEvent
virtual StatusCode filterEvent()
Definition: TTbarWToLeptonFilter.cxx:18
TTbarWToLeptonFilter::m_fourTopsFilter
bool m_fourTopsFilter
Definition: TTbarWToLeptonFilter.h:26
GenParticle
@ GenParticle
Definition: TruthClasses.h:30