ATLAS Offline Software
Loading...
Searching...
No Matches
VGammaORTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
7
8VGammaORTool::VGammaORTool(const std::string& name)
9 : asg::AsgTool(name),
10 m_truthClassifier("MCTruthClassifier",this) {
11
12 declareProperty("n_leptons", m_n_leptons = -2);
13 declareProperty("lepton_pdgIds", m_lepton_pdgIds = {11, -11, 13, -13, 15, -15});
14 declareProperty("veto_lepton_origins", m_lepton_veto_origins = {3, 5, 6, 7, 8, 9, 23, 24, 25, 26, 27, 28, 29, 30, 31,
15 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42});
16 declareProperty("preferred_lepton_origins", m_preferred_lepton_origins = {1, 2, 4, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21});
17
18 declareProperty("veto_photon_origins", m_veto_photon_origins = {9, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 42});
19
20 declareProperty("photon_pT_cuts", m_photon_pT_cuts = {});
21 declareProperty("dR_lepton_photon_cut", m_dR_lepton_photon_cut = 0.1);
22 declareProperty("dR_lepton_photon_cuts", m_dR_lepton_photon_cuts = {0.0, 0.05, 0.075, 0.1, 0.125, 0.15, 0.2});
23
24 declareProperty("use_gamma_iso", m_use_gamma_iso = false);
25 declareProperty("frixione_dR", m_frixione_dR = 0.1);
26 declareProperty("frixione_exponent", m_frixione_exponent = 2);
27 declareProperty("frixione_epsilon", m_frixione_epsilon = 0.1);
28 declareProperty("abs_pdgids_excluded_from_iso", m_abs_pdgids_excluded_from_iso = {11, 12, 13, 14, 15, 16, 22});
29 declareProperty("min_considered_photon_pT", m_min_considered_photon_pT = 3.e3);
30
31 for (int origin : m_preferred_lepton_origins) {
32 if (std::find(m_lepton_veto_origins.begin(), m_lepton_veto_origins.end(), origin) != m_lepton_veto_origins.end()) {
33 ATH_MSG_ERROR(origin << " in both lepton origin and lepton veto origin, this is not correct.");
34 break;
35 }
36 }
37 // pT cuts are sorted in descending order
38 std::sort(m_photon_pT_cuts.begin(), m_photon_pT_cuts.end(), std::greater<float>());
39}
40
43
44
45//============================================================================
46// PUBLIC IN OVERLAP FUNCTION
47// See header for description
49 const std::vector<TLorentzVector>* leptons,
50 const std::vector<TLorentzVector>* photons,
51 const std::vector<int>* lepton_origins,
52 const std::vector<int>* photon_origins) const {
53 std::vector<float> photon_pts;
54 ANA_CHECK(photonPtsOutsideDr(photon_pts,leptons,photons,lepton_origins,photon_origins));
55 result = checkPhotonPts(photon_pts);
56 return StatusCode::SUCCESS;
57}
58
59//============================================================================
60// PUBLIC PTS OUTSIDE DR FUNCTION
61// See header for description
62StatusCode VGammaORTool::photonPtsOutsideDr(std::vector<float>& result,
63 const std::vector<TLorentzVector>* leptons,
64 const std::vector<TLorentzVector>* photons,
65 const std::vector<int>* lepton_origins,
66 const std::vector<int>* photon_origins) const {
67 std::map<float, std::vector<float> > photon_pt_map;
68 ANA_CHECK(photonPtsOutsideDrs(photon_pt_map,std::vector<float>(1, m_dR_lepton_photon_cut),leptons,photons,lepton_origins,photon_origins));
69 result = photon_pt_map[m_dR_lepton_photon_cut];
70 return StatusCode::SUCCESS;
71}
72
73//============================================================================
74// PUBLIC PTS OUTSIDE DR*S* FUNCTION
75// See header for description
76StatusCode VGammaORTool::photonPtsOutsideDrs(std::map<float, std::vector<float> >& result,
77 const std::vector<TLorentzVector>* leptons,
78 const std::vector<TLorentzVector>* photons,
79 const std::vector<int>* lepton_origins,
80 const std::vector<int>* photon_origins) const {
81 ANA_CHECK(photonPtsOutsideDrs(result,m_dR_lepton_photon_cuts,leptons,photons,lepton_origins,photon_origins));
82 return StatusCode::SUCCESS;
83}
84
85
86//============================================================================
87// PRIVATE PTS OUTSIDE DRS FUNCTION
88// This function exectutes the OR algorithm if one of the public funtions is called
89StatusCode VGammaORTool::photonPtsOutsideDrs(std::map<float, std::vector<float> >& result,
90 const std::vector<float>& drCuts,
91 const std::vector<TLorentzVector>* leptons,
92 const std::vector<TLorentzVector>* photons,
93 const std::vector<int>* lepton_origins,
94 const std::vector<int>* photon_origins) const {
95 std::vector<TLorentzVector> good_leptons;
96 std::vector<TLorentzVector> good_photons;
97 ANA_CHECK(setInput(good_leptons,good_photons,leptons,photons,lepton_origins,photon_origins));
98
99 // the actual OR algorithm is here, pts of photon outside dRs are determined first
100 for (const auto& drCut : drCuts) {
101 result[drCut] = std::vector<float>();
102 for (const auto& photon : good_photons) {
103 bool tooCloseToLepton = false;
104 for (uint i_lep = 0; i_lep < good_leptons.size() && (m_n_leptons<0 || int(i_lep) < m_n_leptons); i_lep++) {
105 const float dr = photon.DeltaR(good_leptons[i_lep]);
106 if (dr < drCut) {
107 tooCloseToLepton = true;
108 break;
109 }
110 }
111 if (!tooCloseToLepton) result[drCut].push_back(photon.Pt());
112 }
113 // photon pts are sorted and returned
114 std::sort(result[drCut].begin(), result[drCut].end(), std::greater<float>());
115 }
116
117 return StatusCode::SUCCESS;
118}
119
120//============================================================================
121// find the right leptons, get them either from user or the current event
122StatusCode VGammaORTool::setInput(std::vector<TLorentzVector>& leptons_out,
123 std::vector<TLorentzVector>& photons_out,
124 const std::vector<TLorentzVector>* lepton_p4s,
125 const std::vector<TLorentzVector>* photon_p4s,
126 const std::vector<int>* lepton_origins,
127 const std::vector<int>* photon_origins) const {
128
129 // truth particles are retrieved from event if not given by user
130 const xAOD::TruthParticleContainer* truthMuons(nullptr);
131 const xAOD::TruthParticleContainer* truthElectrons(nullptr);
132 const xAOD::TruthParticleContainer* truthPhotons(nullptr);
133 if(lepton_p4s==0 || photon_p4s==0){
134 ANA_CHECK(evtStore()->retrieve(truthMuons,"TruthMuons"));
135 ANA_CHECK(evtStore()->retrieve(truthElectrons,"TruthElectrons"));
136 ANA_CHECK(evtStore()->retrieve(truthPhotons, "TruthPhotons"));
137 }
138
139 // relevant photons and leptons identified
140 if(lepton_p4s==0){
141 std::vector<TLorentzVector> muonsOut=getLeptonP4s(*truthMuons);
142 std::vector<TLorentzVector> electronsOut=getLeptonP4s(*truthElectrons);
143 leptons_out.insert(leptons_out.end(),muonsOut.begin(),muonsOut.end());
144 leptons_out.insert(leptons_out.end(),electronsOut.begin(),electronsOut.end());
145 }
146 else{
147 if(lepton_origins!=0){
148 leptons_out = filterLeptonOrigins(*lepton_p4s,*lepton_origins);
149 }
150 else{
151 leptons_out = *lepton_p4s;
152 }
153 }
154 if(photon_p4s==0){
155 photons_out = getPhotonP4s(*truthPhotons);
156 }
157 else{
158 if(photon_origins!=0){
159 photons_out = filterPhotonOrigins(*photon_p4s,*photon_origins);
160 }
161 else{
162 photons_out = *photon_p4s;
163 }
164 }
165
166 ATH_MSG_DEBUG("VGammaORTool::setInput" << ": Found " << photons_out.size() << " photons.");
167 ATH_MSG_DEBUG("VGammaORTool::setInput" << ": Found " << leptons_out.size() << " leptons.");
168
169 if (m_n_leptons >=0 && int(leptons_out.size()) < m_n_leptons) {
171 "VGammaORTool::setInput" << ": Found " << leptons_out.size() << " leptons but expected " << m_n_leptons << ".");
172 }
173
174 return StatusCode::SUCCESS;
175}
176
177//============================================================================
178// Functions to filter out particles from wrong origins
179std::vector<TLorentzVector> VGammaORTool::filterPhotonOrigins(const std::vector<TLorentzVector>& photon_candidates,
180 const std::vector<int>& photon_origins) const {
181 // this should only happen if the user gives the wrong input
182 if (photon_candidates.size() != photon_origins.size()) {
184 "VGammaORTool::filterPhotonOrigins" << ": size of photon candidates (" << photon_candidates.size() << ") different from number of photon origins (" << photon_origins.size() <<
185 ").");
186 }
187 // filter out vetoed photons
188 std::vector<TLorentzVector> photon_p4s;
189 for (uint i = 0; i < photon_candidates.size(); i++) {
190 const TLorentzVector p4 = photon_candidates[i];
191 const int p_origin = photon_origins[i];
192 const bool vetoed =
193 std::find(m_veto_photon_origins.begin(), m_veto_photon_origins.end(), p_origin) != m_veto_photon_origins.end();
194 if (!vetoed) {
195 photon_p4s.push_back(p4);
196 }
197 }
198
199 return photon_p4s;
200}
201
202std::vector<TLorentzVector> VGammaORTool::filterLeptonOrigins(const std::vector<TLorentzVector>& lepton_candidates,
203 const std::vector<int>& lepton_origins) const {
204 // this should only happen if the user gives the wrong input
205 if (lepton_candidates.size() != lepton_origins.size()) {
207 "VGammaORTool::filterLeptonOrigins" << ": size of lepton candidates (" << lepton_candidates.size() << ") different from number of lepton origins (" << lepton_origins.size() <<
208 ").");
209 }
210 std::vector<TLorentzVector> lepton_p4s;
211 std::vector<TLorentzVector> leptons_not_vetoed_p4s;
212 // find both good photons and photons that are just not vetoed (lower quality, used as fall back)
213 for (uint i = 0; i < lepton_candidates.size(); i++) {
214 const TLorentzVector p4 = lepton_candidates[i];
215 const int p_origin = lepton_origins[i];
216 const bool use = std::find(m_preferred_lepton_origins.begin(), m_preferred_lepton_origins.end(), p_origin) != m_preferred_lepton_origins.end();
217 if (use) {
218 lepton_p4s.push_back(p4);
219 if (m_n_leptons>=0 && int(lepton_p4s.size()) >= m_n_leptons) {
220 // as soon as enough leptons are found, return them
221 // this is why the order of lepton candidates matters
222 // if this tool identifies the leptons, taus will be before mu/el and otherwise leptons are ordered by pT
223 // in most cases the origin should unambiguosly identify the lepton anyway
224 return lepton_p4s;
225 }
226 } else {
227 bool vetoed =
228 std::find(m_lepton_veto_origins.begin(), m_lepton_veto_origins.end(), p_origin) != m_lepton_veto_origins.end();
229 if (!vetoed) {
230 leptons_not_vetoed_p4s.push_back(p4);
231 }
232 }
233 }
234 // if not enough good leptons were found (or no expected number of leptons was set),
235 // the result is filled with leptons that were merely not vetoed
236 for (const auto& l : leptons_not_vetoed_p4s) {
237 lepton_p4s.push_back(l);
238 if (m_n_leptons>=0 && int(lepton_p4s.size()) >= m_n_leptons) break;
239 }
240 return lepton_p4s;
241}
242
243//============================================================================
244// Get the right leptons and photons from the event
245std::vector<TLorentzVector> VGammaORTool::getLeptonP4s(const xAOD::TruthParticleContainer& truthParticles) const {
246 std::vector<const xAOD::TruthParticle*> tau_candidates;
247 std::vector<const xAOD::TruthParticle*> elmu_candidates;
248 for (const auto *p : truthParticles) {
249 // ignore all particles created in Geant4
250 if (HepMC::is_simulation_particle(p)) continue;
251 // ignore all particles with the wrong pdgid
252 if (std::find(m_lepton_pdgIds.begin(), m_lepton_pdgIds.end(), p->pdgId()) == m_lepton_pdgIds.end()) continue;
253 // handle taus: use tau instances before decay into non-tau
254 if (MC::isTau(p)) {
255 bool childIsTau = false;
256 bool hasChildren = false;
257 // make sure tau has no tau children, i.e. is tau before decay
258 for (uint i = 0; i < p->nChildren(); i++) {
259 if (p->child(i) == nullptr) continue;
260 if (HepMC::is_same_particle(p->child(i),p)) continue;
261 hasChildren = true;
262 if (p->child(i)->pdgId() == p->pdgId()) {
263 childIsTau = true;
264 break;
265 }
266 }
267 if (hasChildren && !childIsTau) tau_candidates.push_back(p);
268 }
269 // electron and muons: use all status 1 not from tau
270 else if (MC::isStable(p) && !isFromTau(*p)) {
271 elmu_candidates.push_back(p);
272 }
273 }
274 // sort leptons by pT
275 sort(tau_candidates.begin(), tau_candidates.end(),
276 [](const xAOD::TruthParticle*& p1, const xAOD::TruthParticle*& p2) {
277 return p1->pt() > p2->pt();
278 });
279 sort(elmu_candidates.begin(), elmu_candidates.end(),
280 [](const xAOD::TruthParticle*& p1, const xAOD::TruthParticle*& p2) {
281 return p1->pt() > p2->pt();
282 });
283 // put taus before other leptons in a vector
284 std::vector<const xAOD::TruthParticle*> lepton_candidates(tau_candidates);
285 lepton_candidates.insert(lepton_candidates.end(), elmu_candidates.begin(), elmu_candidates.end());
286 // determine lepton origins
287 std::vector<TLorentzVector> lepton_p4s;
288 std::vector<int> lepton_origins;
289 static const SG::ConstAccessor<unsigned int> classifierParticleOriginAcc("classifierParticleOrigin");
290 for (const auto& p : lepton_candidates) {
291 const unsigned int origin = classifierParticleOriginAcc(*p);
292 lepton_origins.push_back(origin);
293 lepton_p4s.push_back(p->p4());
294 }
295 // filter out bad origins
296 return filterLeptonOrigins(lepton_p4s, lepton_origins);
297}
298
299std::vector<TLorentzVector> VGammaORTool::getPhotonP4s(const xAOD::TruthParticleContainer& truthParticles) const {
300 std::vector<TLorentzVector> photon_p4s;
301 std::vector<int> photon_origins;
302 for (const auto *p : truthParticles) {
303 // consider only final state photons, not from geant, above a lower pt cut
304 if (!MC::isStable(p) || HepMC::is_simulation_particle(p) || !MC::isPhoton(p) || p->pt() < m_min_considered_photon_pT) continue;
305 // require photons to be isolated if use_gamma_iso is true
307 // determine photon origin
308 static const SG::ConstAccessor<unsigned int> classifierParticleOriginAcc("classifierParticleOrigin");
309 const unsigned int origin = classifierParticleOriginAcc(*p);
310 photon_origins.push_back(origin);
311 photon_p4s.push_back(p->p4());
312 }
313 // filter out bad photons
314 return filterPhotonOrigins(photon_p4s, photon_origins);
315}
316
317bool VGammaORTool::isFromTau(const xAOD::TruthParticle& lepton, int nRecursions) const{
318 // avoid being stuck in some weird particle family tree
319 if(nRecursions>20){
320 return false;
321 }
322 for(uint i=0; i<lepton.nParents(); i++){
323 const xAOD::TruthParticle* parent=lepton.parent(i);
324 if (MC::isTau(parent)) return true;
325 if(parent->pdgId()==lepton.pdgId()){
326 return isFromTau(lepton, nRecursions+1);
327 }
328 }
329 return false;
330
331}
332
333bool VGammaORTool::checkPhotonPts(const std::vector<float>& photon_pts) const{
334 if(m_photon_pT_cuts.size()==0){
335 ATH_MSG_ERROR("photon_pT_cuts needs to be a non-empty list, when inOverlap is called, set as property or in constructor.");
336 return false;
337 }
338 if(m_photon_pT_cuts.size()>photon_pts.size()){
339 return false;
340 }
341 for(uint i=0; i<m_photon_pT_cuts.size();i++){
342 if(photon_pts[i]<m_photon_pT_cuts[i]){
343 return false;
344 }
345 }
346 return true;
347}
348//============================================================================
349// Functions related to photon isolation
351 const xAOD::TruthParticleContainer& truthParticles, float dR0, float exponent,
352 float epsilon) const {
353 // all photons are isolated if dR is negative
354 if (dR0 <= 0.) {
355 return true;
356 }
357 // create map between hadron-photon dr and hadron pt
358 std::map<float, float> dr_to_pt;
359 for (const auto *p : truthParticles) {
360 if (!MC::isStable(p) || HepMC::is_simulation_particle(p)) continue;
361 // ignore what typically is leptons and photons
363 std::abs(p->pdgId())) != m_abs_pdgids_excluded_from_iso.end()) {
364 continue;
365 }
366 const float dRgamma = photon.p4().DeltaR(p->p4());
367 // consider only photons withon isolation cone dR0
368 if (dRgamma < dR0) {
369 // should two hadrons have the same dr they are added up
370 if (dr_to_pt.count(dRgamma) > 0) {
371 dr_to_pt[dRgamma] += p->pt();
372 }
373 dr_to_pt[dRgamma] = p->pt();
374 }
375 }
376 // use map to determine whether photon is Frixione isolated
377 // map is sorted from low to high dr
378 float sumPt = 0.;
379 for (const auto& pair : dr_to_pt) {
380 sumPt += pair.second;
381 const float dRgamma = pair.first;
382 // if for any dRgamma the sum of pt of hadrons with a distrance of <=dRgamma to photon
383 // does not fulfill the Frixione condition, the photon is not isolated
384 if (sumPt > photon.pt() * frixioneFunc(dRgamma, dR0, exponent, epsilon)) {
385 return false;
386 }
387 }
388 // otherwise the photon is isolated
389 return true;
390}
391
392float VGammaORTool::frixioneFunc(float dR, float dR0, float exponent, float epsilon) const {
393 return epsilon * TMath::Power((1 - TMath::Cos(dR)) / (1 - TMath::Cos(dR0)), exponent);
394}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define ANA_CHECK(EXP)
check whether the given expression was successful
unsigned int uint
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
ServiceHandle< StoreGateSvc > & evtStore()
Helper class to provide constant type-safe access to aux data.
std::vector< int > m_lepton_pdgIds
std::vector< float > m_dR_lepton_photon_cuts
float m_frixione_epsilon
VGammaORTool(const std::string &name)
std::vector< TLorentzVector > getPhotonP4s(const xAOD::TruthParticleContainer &truthParticleContainer) const
Get final state photons from truthParticleContainer A minimum pT cut and isolation is applied accordi...
std::vector< TLorentzVector > filterLeptonOrigins(const std::vector< TLorentzVector > &, const std::vector< int > &) const
std::vector< int > m_lepton_veto_origins
virtual ~VGammaORTool() override
StatusCode setInput(std::vector< TLorentzVector > &leptons_out, std::vector< TLorentzVector > &photons_out, const std::vector< TLorentzVector > *lepton_p4s, const std::vector< TLorentzVector > *photon_p4s, const std::vector< int > *lepton_origins, const std::vector< int > *photon_origins) const
std::vector< TLorentzVector > getLeptonP4s(const xAOD::TruthParticleContainer &truthParticleContainer) const
Get final state leptons from truthParticleContainer Filter function is applied, only leptons from rel...
std::vector< float > m_photon_pT_cuts
bool isFromTau(const xAOD::TruthParticle &lepton, int nRecursions=0) const
std::vector< int > m_preferred_lepton_origins
virtual StatusCode photonPtsOutsideDr(std::vector< float > &result, const std::vector< TLorentzVector > *leptons=0, const std::vector< TLorentzVector > *photons=0, const std::vector< int > *lepton_origins=0, const std::vector< int > *photon_origins=0) const override
Determine the pTs of photons outside the dR cut that is configured in tool initialization (dR_lepton_...
float frixioneFunc(float dR, float dR0, float exponent, float epsilon) const
asg::AnaToolHandle< MCTruthClassifier > m_truthClassifier
float m_dR_lepton_photon_cut
virtual StatusCode photonPtsOutsideDrs(std::map< float, std::vector< float > > &result, const std::vector< TLorentzVector > *leptons=0, const std::vector< TLorentzVector > *photons=0, const std::vector< int > *lepton_origins=0, const std::vector< int > *photon_origins=0) const override
Determine the pTs of photons outside of several dR cuts that are configured in tool initialization (d...
float m_frixione_exponent
virtual bool frixioneIsolated(const xAOD::TruthParticle &photon, const xAOD::TruthParticleContainer &truthParticles, float dR0, float exponent, float epsilon) const override
Function determining whether a photon is frixione isolated from truthParticles Parameters as defined ...
std::vector< int > m_veto_photon_origins
std::vector< TLorentzVector > filterPhotonOrigins(const std::vector< TLorentzVector > &, const std::vector< int > &) const
virtual StatusCode inOverlap(bool &result, const std::vector< TLorentzVector > *leptons=0, const std::vector< TLorentzVector > *photons=0, const std::vector< int > *lepton_origins=0, const std::vector< int > *photon_origins=0) const override
Determine whether current event is in overlap region (set via reference).
float m_frixione_dR
bool checkPhotonPts(const std::vector< float > &photon_pts) const
std::vector< int > m_abs_pdgids_excluded_from_iso
float m_min_considered_photon_pT
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
STL class.
int pdgId() const
PDG ID code.
const TruthParticle_v1 * parent(size_t i) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
size_t nParents() const
Number of parents of this particle.
bool is_same_particle(const T1 &p1, const T2 &p2)
Method to establish if two particles in the GenEvent actually represent the same 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...
bool isPhoton(const T &p)
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
bool isTau(const T &p)
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TruthParticle_v1 TruthParticle
Typedef to implementation.
TruthParticleContainer_v1 TruthParticleContainer
Declare the latest version of the truth particle container.