ATLAS Offline Software
xAODTTbarWToLeptonFilter.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 xAODTTbarWToLeptonFilter::xAODTTbarWToLeptonFilter(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 
17 {
18 
19 // Retrieve TruthGen container from xAOD Gen slimmer, contains all particles witout barcode_zero and
20 // duplicated barcode ones
21  const xAOD::TruthParticleContainer* xTruthParticleContainer;
22  if (evtStore()->retrieve(xTruthParticleContainer, "TruthGen").isFailure()) {
23  ATH_MSG_ERROR("No TruthParticle collection with name " << "TruthGen" << " found in StoreGate!");
24  return StatusCode::FAILURE;
25  }
26 
27  int N_quark_t = 0;
28  int N_quark_tbar = 0;
29  int N_quark_t_all = 0;
30  int N_quark_tbar_all = 0;
31  int N_pt_above_cut = 0;
32  int N_pt_above_cut_plus = 0;
33  int N_pt_above_cut_minus = 0;
34 
35  int foundlepton[6] = {0, 0, 0, 0, 0, 0}; // e+, e-, mu+, mu-, tau+, tau-
36  int count_found_leptons = 1; // In ttbar each charged lepton flavour is counted at most once
37  if (m_fourTopsFilter)
38  count_found_leptons = 2; // In four tops, one can have the same charged lepton flavour twice
39 
40  // Loop over all particles in the event
41  unsigned int nPart = xTruthParticleContainer->size();
42  for (unsigned int iPart = 0; iPart < nPart; ++iPart) {
43  const xAOD::TruthParticle* pitr = (*xTruthParticleContainer)[iPart];
44  if (std::abs(pitr->pdgId()) != 6)
45  continue;
46  if (pitr->pdgId() == 6)
47  N_quark_t_all++;
48  if (pitr->pdgId() == -6)
49  N_quark_tbar_all++;
50  auto decayVtx = pitr->decayVtx();
51  // Verify if we got a valid pointer and retrieve the number of daughters
52  if (!decayVtx)
53  continue;
54  // For this analysis we are not interested in t->t MC structures, only in decays
55  if (decayVtx->nOutgoingParticles() < 2)
56  continue;
57 
58  for (size_t thisChild_id = 0; thisChild_id < pitr->decayVtx()->nOutgoingParticles(); thisChild_id++)
59  {
60  auto child_mcpart = pitr->decayVtx()->outgoingParticle(thisChild_id);
61  // Implicitly assume that tops always decay to W X
62  if (std::abs(child_mcpart->pdgId()) != 24)
63  continue;
64  if (pitr->pdgId() == 6)
65  N_quark_t++;
66  if (pitr->pdgId() == -6)
67  N_quark_tbar++;
68 
69  bool useNextVertex = false;
70  auto w_decayVtx = child_mcpart->decayVtx();
71  while (w_decayVtx)
72  {
73  useNextVertex = false;
74  for (size_t w_thisChild_id = 0; w_thisChild_id < w_decayVtx->nOutgoingParticles(); w_thisChild_id++)
75  {
76  auto grandchild_mcpart = w_decayVtx->outgoingParticle(w_thisChild_id);
77 
78  int grandchild_pid = grandchild_mcpart->pdgId();
79  ATH_MSG_DEBUG("W (t/tbar) has " << w_decayVtx->nOutgoingParticles() << " children and the pdgId of the next is " << grandchild_pid);
80  // Check if the W's child is W again. If yes, then move to its next decay vertex in a decay tree
81  if (std::abs(grandchild_pid) == 24)
82  {
83  w_decayVtx = grandchild_mcpart->decayVtx();
84  // If something wrong comes from truth...
85  if (!w_decayVtx)
86  {
87  ATH_MSG_ERROR("A stable W is found... ");
88  break;
89  }
90  useNextVertex = true;
91  break;
92  }
93 
94  // use brute force to use only leptons that have not been found already
95  if (grandchild_pid == -11 && foundlepton[0] < count_found_leptons)
96  {
97  if (grandchild_mcpart->pt() >= m_Ptmin)
98  {
99  foundlepton[0]++;
100  N_pt_above_cut++;
101  N_pt_above_cut_minus++;
102  }
103  }
104  if (grandchild_pid == 11 && foundlepton[1] < count_found_leptons)
105  {
106  if (grandchild_mcpart->pt() >= m_Ptmin)
107  {
108  foundlepton[1]++;
109  N_pt_above_cut++;
110  N_pt_above_cut_plus++;
111  }
112  }
113  if (grandchild_pid == -13 && foundlepton[2] < count_found_leptons)
114  {
115  if (grandchild_mcpart->pt() >= m_Ptmin)
116  {
117  foundlepton[2]++;
118  N_pt_above_cut++;
119  N_pt_above_cut_minus++;
120  }
121  }
122  if (grandchild_pid == 13 && foundlepton[3] < count_found_leptons)
123  {
124  if (grandchild_mcpart->pt() >= m_Ptmin)
125  {
126  foundlepton[3]++;
127  N_pt_above_cut++;
128  N_pt_above_cut_plus++;
129  }
130  }
131  if (grandchild_pid == -15 && foundlepton[4] < count_found_leptons)
132  {
133  if (grandchild_mcpart->pt() >= m_Ptmin)
134  {
135  foundlepton[4]++;
136  N_pt_above_cut++;
137  N_pt_above_cut_minus++;
138  }
139  }
140  if (grandchild_pid == 15 && foundlepton[5] < count_found_leptons)
141  {
142  if (grandchild_mcpart->pt() >= m_Ptmin)
143  {
144  foundlepton[5]++;
145  N_pt_above_cut++;
146  N_pt_above_cut_plus++;
147  }
148  }
149  }
150  // If investigation of W's next decay vertex is not required then finish looking for leptons
151  if (!useNextVertex)
152  break;
153  }
154  }
155  } //loop over TruthParticles
156 
157 
158  ATH_MSG_INFO("Found " << N_quark_t_all << " t quarks in event record");
159  ATH_MSG_INFO("Found " << N_quark_tbar_all << " tbar quarks in event record");
160  ATH_MSG_INFO("Found " << N_quark_t << " t -> W X decays");
161  ATH_MSG_INFO("Found " << N_quark_tbar << " tbar -> W X decays");
162  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);
163 
164  int count_tops = 1;
165  if (m_fourTopsFilter)
166  count_tops = 2;
167  if (N_quark_t_all < count_tops || N_quark_tbar_all < count_tops)
168  {
169 
170  ATH_MSG_ERROR("No t or tbar quarks were found in a (presumably) ttbar event! Event is rejected.");
171  setFilterPassed(false);
172  return StatusCode::SUCCESS;
173  }
174 
175  if (N_quark_t < count_tops || N_quark_tbar < count_tops)
176  {
177 
178  ATH_MSG_ERROR("No t or tbar quarks were found decaying to W in a (presumably) ttbar event! Event is rejected. Event dump follows.");
179  int part = 0;
180  // Loop over all particles in the event and build up the grid
181  unsigned int nPart = xTruthParticleContainer->size();
182  for (unsigned int iPart = 0; iPart < nPart; ++iPart) {
183  const xAOD::TruthParticle *mcpart = (*xTruthParticleContainer)[iPart];
184  part++;
185  int pid = mcpart->pdgId();
186  ATH_MSG_ERROR("Particle number " << part << " has pdgId = " << pid);
187  // retrieve decay vertex
188  auto decayVtx = mcpart->decayVtx();
189  // verify if we got a valid pointer
190  if (!decayVtx)
191  continue;
192  int part_child = 0;
193  for (size_t thisChild_id = 0; thisChild_id < mcpart->decayVtx()->nOutgoingParticles(); thisChild_id++)
194  {
195  auto child_mcpart = mcpart->decayVtx()->outgoingParticle(thisChild_id);
196  part_child++;
197  int child_pid = child_mcpart->pdgId();
198  ATH_MSG_ERROR(" child " << part_child << " with pdgId = " << child_pid);
199  }
200  } // loop over TruthParticles
201 
202  setFilterPassed(false);
203  return StatusCode::SUCCESS;
204  }
205 
206  // If NumLeptons is negative (default), accept if Nlep > 0, otherwise only accept an exact match
207  if (m_numLeptons < 0)
208  {
209  if ((N_quark_t >= 2 || N_quark_tbar >= 2) && !m_fourTopsFilter)
210  {
211  ATH_MSG_WARNING("More than one t -> W X or tbar -> W X decays found. Event is accepted anyway.");
212  }
213  if ((N_quark_t > 2 || N_quark_tbar > 2) && m_fourTopsFilter)
214  {
215  ATH_MSG_WARNING("More than one t -> W X or tbar -> W X decays found. Event is accepted anyway.");
216  }
217  setFilterPassed(N_pt_above_cut > 0);
218  }
219  else
220  {
221  if (m_fourTopsFilter)
222  {
223  if (m_SSMLFilter)
224  setFilterPassed((N_pt_above_cut >= m_numLeptons) && (N_pt_above_cut_plus >= 2 || N_pt_above_cut_minus >= 2));
225  else
226  setFilterPassed(N_pt_above_cut >= m_numLeptons);
227  }
228  else
229  setFilterPassed(N_pt_above_cut == m_numLeptons);
230  }
231 
232  return StatusCode::SUCCESS;
233 }
LArG4FSStartPointFilter.part
part
Definition: LArG4FSStartPointFilter.py:21
python.PyKernel.retrieve
def retrieve(aClass, aKey=None)
Definition: PyKernel.py:110
xAODTTbarWToLeptonFilter::m_Ptmin
double m_Ptmin
Definition: xAODTTbarWToLeptonFilter.h:28
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
xAODTTbarWToLeptonFilter::filterEvent
virtual StatusCode filterEvent()
Definition: xAODTTbarWToLeptonFilter.cxx:16
AthCommonDataStore< AthCommonMsg< Algorithm > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
xAODTTbarWToLeptonFilter::m_fourTopsFilter
bool m_fourTopsFilter
Definition: xAODTTbarWToLeptonFilter.h:30
AthCommonDataStore< AthCommonMsg< Algorithm > >::evtStore
ServiceHandle< StoreGateSvc > & evtStore()
The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
Definition: AthCommonDataStore.h:85
GenFilter
Base class for event generator filtering modules.
Definition: GenFilter.h:30
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
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
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:41
xAODTTbarWToLeptonFilter::m_SSMLFilter
bool m_SSMLFilter
Definition: xAODTTbarWToLeptonFilter.h:31
ParticleGun_EoverP_Config.pid
pid
Definition: ParticleGun_EoverP_Config.py:62
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
xAOD::TruthParticle_v1::decayVtx
const TruthVertex_v1 * decayVtx() const
The decay vertex of this particle.
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
xAODTTbarWToLeptonFilter.h
xAODTTbarWToLeptonFilter::xAODTTbarWToLeptonFilter
xAODTTbarWToLeptonFilter(const std::string &name, ISvcLocator *pSvcLocator)
Definition: xAODTTbarWToLeptonFilter.cxx:7
xAOD::TruthParticle_v1::pdgId
int pdgId() const
PDG ID code.
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
xAOD::TruthVertex_v1::outgoingParticle
const TruthParticle_v1 * outgoingParticle(size_t index) const
Get one of the outgoing particles.
Definition: TruthVertex_v1.cxx:121
xAODTTbarWToLeptonFilter::m_numLeptons
int m_numLeptons
Definition: xAODTTbarWToLeptonFilter.h:29