ATLAS Offline Software
Loading...
Searching...
No Matches
IsolationCloseByCorrectionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
4
12#include <xAODBase/ObjectType.h>
17
18#include "xAODEgamma/Egamma.h"
21
22#include <cmath>
23
24namespace CP {
25 using namespace xAOD::Iso;
28 static const caloDecorNames names =
29 {"IsoCloseByCorr_assocClustEta", "IsoCloseByCorr_assocClustPhi", "IsoCloseByCorr_assocClustEnergy",
30 "IsoCloseByCorr_assocClustDecor"};
31 return names;
32 }
34 static const caloDecorNames names =
35 {"IsoCloseByCorr_assocPflowEta", "IsoCloseByCorr_assocPflowPhi", "IsoCloseByCorr_assocPflowEnergy",
36 "IsoCloseByCorr_assocPflowDecor"};
37 return names;
38 }
39 constexpr float MinClusterEnergy = 100.;
40 constexpr float MeVtoGeV = 1.e-3;
41
43
46 ATH_CHECK(m_selectorTool.retrieve());
50
54 if (!m_isoDecSuffix.empty()) ATH_MSG_INFO("IsoDecSuffix set to " << m_isoDecSuffix);
55 if (!m_quality_name.empty()) ATH_MSG_INFO("SelectionDecorator set to " << m_quality_name);
56
57
58#ifndef XAOD_ANALYSIS
63 ATH_CHECK(m_isoVarKeys.initialize());
64 ATH_CHECK(m_isoWriteDecVarKeys.initialize());
65 if (!m_caloExtTool.empty()) ATH_CHECK(m_caloExtTool.retrieve());
66 else {
67 ATH_MSG_WARNING("The ParticleCaloExtensionTool was not configured. Pleease include it!!!");
68 }
69#endif
70
71 ATH_CHECK(m_VtxKey.initialize());
74
75 // set default properties of track selection tool, if the user hasn't configured it
76 if (m_trkselTool.empty()) {
77 asg::AsgToolConfig config{"InDet::InDetTrackSelectionTool/TrackParticleSelectionTool"};
78 ATH_MSG_INFO("No TrackSelectionTool provided, so I will create and configure my own, called: " << config.name());
79 // The z0 cut is checked in any case either by the
80 // track to vertex association tool or by the tracking tool
81 ATH_CHECK(config.setProperty("maxZ0SinTheta", 3.));
82 // The minimum Pt requirement is lowered to 500 MeV because
83 // the Loose ttva cone variables accept very low-pt tracks
84 // https://gitlab.cern.ch/atlas/athena/blob/21.2/Reconstruction/RecoAlgs/IsolationAlgs/python/IsoUpdatedTrackCones.py#L21
85 ATH_CHECK(config.setProperty("minPt", 500.));
86 ATH_CHECK(config.setProperty("CutLevel", "Loose"));
87 ATH_CHECK(config.makePrivateTool(m_trkselTool));
88 }
90 if (m_ttvaTool.empty()) {
91 asg::AsgToolConfig config{"CP::TrackVertexAssociationTool/ttva_selection_tool"};
92 ATH_CHECK(config.setProperty("WorkingPoint", "Nonprompt_All_MaxWeight"));
93 ATH_CHECK(config.makePrivateTool(m_ttvaTool));
94 }
95 ATH_CHECK(m_trkselTool.retrieve());
96 ATH_CHECK(m_ttvaTool.retrieve());
97
98 if (!m_quality_name.empty()) m_acc_quality = std::make_unique<CharAccessor>(m_quality_name);
99 if (!m_passOR_name.empty()) m_acc_passOR = std::make_unique<CharAccessor>(m_passOR_name);
100 if (!m_isoSelection_name.empty()) m_dec_isoselection = std::make_unique<CharDecorator>(m_isoSelection_name);
101 m_isInitialised = true;
102 return StatusCode::SUCCESS;
103 }
104 void IsolationCloseByCorrectionTool::isoTypesFromWP(const std::vector<std::unique_ptr<IsolationWP>>& WPs, IsoVector& types) {
105 types.clear();
106 for (const std::unique_ptr<IsolationWP>& W : WPs) {
107 for (const std::unique_ptr<IsolationCondition>& C : W->conditions()) {
108 for (unsigned int t = 0; t < C->num_types(); ++t) {
109 const IsoType iso_type = C->type(t);
110 if (std::find(types.begin(), types.end(), iso_type) == types.end()) types.emplace_back(iso_type);
111 if (m_isohelpers.find(iso_type) == m_isohelpers.end()) {
112 m_isohelpers.insert(std::make_pair(iso_type, std::make_unique<IsoVariableHelper>(iso_type, m_backup_prefix, m_isoDecSuffix)));
113 }
114 }
115 }
116 }
117 m_has_nonTTVA |= std::find_if(types.begin(), types.end(),
118 [](const IsolationType& t) { return isTrackIso(t) && !isTrackIsoTTVA(t); }) != types.end();
119 m_hasPflowIso |= std::find_if(types.begin(), types.end(),
120 [](const IsolationType& t) { return isPFlowIso(t); }) != types.end();
121 m_hasEtConeIso |= std::find_if(types.begin(), types.end(),
122 [](const IsolationType& t) { return isTopoEtIso(t); }) != types.end();
123 }
124#ifndef XAOD_ANALYSIS
125 void IsolationCloseByCorrectionTool::declareDependency(const std::vector<std::string>& containers, const IsoVector& types) {
126 for (const std::string& cont : containers) {
127 for (const IsoType iso : types) {
128 // define read accessor iso variable keys
129 m_isoVarKeys.emplace_back(cont + "." + std::string(toString(iso)));
130 // define write decorator iso variable keys - needed for MT, but we do not use handles for writing the decorators in isoHelpers
131 m_isoWriteDecVarKeys.emplace_back(cont + "." + std::string(toString(iso) + (m_isoDecSuffix.empty() ? "" : "_") + m_isoDecSuffix));
132 }
135 for (const std::string& decor : pflowDecors()) m_isoVarKeys.emplace_back(cont + "." + decor);
136 }
138 for (const std::string& decor : caloDecors()) m_isoVarKeys.emplace_back(cont + "." + decor + m_caloDecSuffix);
139 }
140 }
141 }
142#endif
144 if (!container) return;
145 for (const xAOD::IParticle* particle : *container) {
146 if (m_dec_isoselection) (*m_dec_isoselection)(*particle) = true && m_selectorTool->accept(*particle);
147 const IsoVector& iso_types = getIsolationTypes(particle);
148 if (iso_types.empty()) { ATH_MSG_DEBUG("No isolation types have been defined for particle type " << particleName(particle)); }
149 for (const IsoType type : iso_types) {
150 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
151 IsoHelperMap::const_iterator Itr = m_isohelpers.find(type);
152 if (Itr == m_isohelpers.end() || Itr->second->backupIsolation(particle) == CorrectionCode::Error) {
153 ATH_MSG_WARNING("Failed to properly access the vanilla isolation variable "
154 << toString(type) << "for particle " << particleName(particle) << " with pT: "
155 << particle->pt() * MeVtoGeV << " GeV, eta: " << particle->eta() << ", phi: " << particle->phi());
156 }
157 }
158 // Save all particles to be sure to output the new iso decorated values
159 // They either pass or not the selection.
160 // The selected ones participate in the CloseBy and may have their isolation corrected.
161 if (!passSelectionQuality(particle)) {
162 cache.not_sel_parts.insert(particle);
163 }
164 else {
165 cache.prim_parts.insert(particle);
166 }
167 }
168 }
169 void IsolationCloseByCorrectionTool::loadAssociatedObjects(const EventContext& ctx, ObjectCache& cache) const {
170
171 // Use isLRT decoration for LLP particles to avoid looking for tracks from the primary vertex
172 static const CharAccessor isLRT("isLRT");
173
174 cache.prim_vtx = retrieveIDBestPrimaryVertex(ctx);
175 for (const xAOD::IParticle* prim : cache.prim_parts) {
176 // skip LRT leptons
177 if (!isLRT.isAvailable(*prim) || !isLRT(*prim) ) {
178 const TrackSet tracks = getAssociatedTracks(prim, cache.prim_vtx);
179 cache.tracks.insert(tracks.begin(), tracks.end());
180 }
181 const ClusterSet clusters = getAssociatedClusters(ctx, prim, cache);
182 cache.clusters.insert(clusters.begin(), clusters.end());
183 }
184 getAssocFlowElements(ctx, cache);
185 }
186 PflowSet IsolationCloseByCorrectionTool::getAssocFlowElements(const EventContext& ctx, const xAOD::IParticle* particle) const {
187 ObjectCache cache{};
188 cache.prim_parts = {particle};
189 loadAssociatedObjects(ctx, cache);
190 return cache.flows;
191 }
192
193 void IsolationCloseByCorrectionTool::getAssocFlowElements(const EventContext& ctx, ObjectCache& cache) const {
194 if (m_PflowKey.empty()) return;
196 if (!readHandle.isValid()) return;
197 std::set<const xAOD::IParticle*> tombola{};
198 for (const xAOD::IParticle* p : cache.prim_parts) tombola.insert(p);
199 for (const TrackPtr& p : cache.tracks) tombola.insert(p);
200 for (const CaloClusterPtr& p : cache.clusters) tombola.insert(p);
201
202 for (const xAOD::FlowElement* flow : *readHandle) {
203 if (!flow) continue;
204 for (size_t ch = 0; ch < flow->nChargedObjects(); ++ch) {
205 const xAOD::IParticle* obj = flow->chargedObject(ch);
206 if (tombola.count(obj)) {
207 const std::vector<float>& weights = flow->chargedObjectWeights();
208 cache.flows.emplace(flow, ch < weights.size() ? weights[ch] : 1.f);
209 }
210 }
211 for (size_t ne = 0; ne < flow->nOtherObjects(); ++ne) {
212 const xAOD::IParticle* obj = flow->otherObject(ne);
213 if (tombola.count(obj)) {
214 const std::vector<float>& weights = flow->otherObjectWeights();
215 cache.flows.emplace(flow, ne < weights.size() ? weights[ne] : 1.f);
216 ATH_MSG_VERBOSE("getAssocFlowElements: neflow " << ne << ", " << obj->type() << ", " << obj->pt() << ", " << obj->eta() << ", " << obj->phi() << ", " << flow->pt() << ", " << flow->eta() << ", " << flow->phi());
217 }
218 }
219 }
220 }
221
222 #ifndef XAOD_ANALYSIS
223 bool IsolationCloseByCorrectionTool::getExtrapEtaPhi(const EventContext& ctx, const xAOD::TrackParticle* tp, float& eta, float& phi) const {
225 ATH_MSG_DEBUG("Geting calo extension caloExtension tool.");
226 // If we have an extension cache then it owns the extension, otherwise we own it
227 // Therefore we have to prepare both an owning and a non-owning pointer
228 std::unique_ptr<Trk::CaloExtension> caloExtension;
229 caloExtension = m_caloExtTool->caloExtension(ctx, *tp);
230 if(!caloExtension){
231 ATH_MSG_WARNING("Can not get caloExtension.");
232 return false;
233 };
234
235 const std::vector<Trk::CurvilinearParameters>& intersections = caloExtension->caloLayerIntersections();
236 if(!intersections.empty()){
237 Amg::Vector3D avePoint(0,0,0);
238 for (unsigned int i = 0; i < intersections.size(); ++i){
239 const Amg::Vector3D& point = intersections[i].position();
240 avePoint += point;
241 }
242 avePoint = (1./intersections.size())*avePoint;
243 eta = avePoint.eta();
244 phi = avePoint.phi();
245 return true;
246 } else {
247 ATH_MSG_WARNING("Muon Calo extension got no intersection!!!");
248 }
250 ATH_MSG_WARNING("Calo extension can not be obtained!!!");
251 return false;
252 }
253 #endif // xAOD
254
256 const EventContext& ctx,
257 const xAOD::ElectronContainer* electrons,
258 const xAOD::MuonContainer* muons,
259 const xAOD::PhotonContainer* photons) const {
260 if (!m_isInitialised) {
261 ATH_MSG_ERROR("The IsolationCloseByCorrectionTool was not initialised!!!");
263 }
264 ObjectCache cache{};
266 loadPrimaryParticles(electrons, cache);
267 loadPrimaryParticles(muons, cache);
268 loadPrimaryParticles(photons, cache);
269
270 loadAssociatedObjects(ctx, cache);
275 return ret;
276 }
278 if (cache.prim_vtx) {
279 // require a primary vertex for isolation correction - expect that if there is not primary vertex, then we only need to assure that the cache.not_sel_parts are treated correctly below
280 for (const xAOD::IParticle* particle : cache.prim_parts) {
281 ATH_MSG_DEBUG("Correct the isolation of particle "<<particleName(particle)<< " with pt: " << particle->pt() * MeVtoGeV << " GeV"
282 << " eta: " << particle->eta()
283 << " phi: " << particle->phi());
284
285 if (subtractCloseByContribution(ctx, particle, cache) == CorrectionCode::Error) {
286 ATH_MSG_ERROR("Failed to correct the isolation of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
287 << " eta: " << particle->eta()
288 << " phi: " << particle->phi());
290 }
291 if (m_dec_isoselection) (*m_dec_isoselection)(*particle) = bool(m_selectorTool->accept(*particle));
292 ATH_MSG_DEBUG("Corrected the isolation of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
293 << " eta: " << particle->eta()
294 << " phi: " << particle->phi());
295
296 }
297 }
298 else {
299 // Missing primary vertex - need to copy the uncorrected iso values
300 for (const xAOD::IParticle* particle : cache.prim_parts) {
301 ATH_MSG_DEBUG("Copy isolation values of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
302 << " eta: " << particle->eta()
303 << " phi: " << particle->phi());
305 ATH_MSG_ERROR("Failed to copy the isolation of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
306 << " eta: " << particle->eta()
307 << " phi: " << particle->phi());
309 }
310 }
311 }
312 // Only need to copy the uncorrected iso values
313 for (const xAOD::IParticle* particle : cache.not_sel_parts) {
314 ATH_MSG_DEBUG("Copy isolation values of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
315 << " eta: " << particle->eta()
316 << " phi: " << particle->phi());
318 ATH_MSG_ERROR("Failed to copy the isolation of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
319 << " eta: " << particle->eta()
320 << " phi: " << particle->phi());
322 }
323 }
324 return CorrectionCode::Ok;
325 }
327 const IsoVector& isoTypes) const {
328 if (!parts) return;
329
332 const CharDecorator dec_isDecor{caloDecors()[3] + m_caloDecSuffix};
333
334 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
335
336 if (parts->ownPolicy() == SG::VIEW_ELEMENTS) {
338 for (const xAOD::IParticle* part : *parts) {
339 const SG::AuxVectorData* c = part->container();
340 if (conts.insert(c).second) {
341 for (const IsoType t : isoTypes) {
342 auto it = m_isohelpers.find (t);
343 if (it != m_isohelpers.end())
344 it->second->lockDecorations(*part->container());
345 }
347 const_cast<SG::AuxVectorData*> (c);
348 c_nc->lockDecoration (dec_assocEta.auxid());
349 c_nc->lockDecoration (dec_assocPhi.auxid());
350 c_nc->lockDecoration (dec_isDecor.auxid());
351 }
352 }
353 }
354
355 else {
356 for (const IsoType t : isoTypes) {
357 auto it = m_isohelpers.find (t);
358 if (it != m_isohelpers.end())
359 it->second->lockDecorations(*parts);
360 }
362 const_cast<xAOD::IParticleContainer*> (parts);
363 c_nc->lockDecoration (dec_assocEta.auxid());
364 c_nc->lockDecoration (dec_assocPhi.auxid());
365 c_nc->lockDecoration (dec_isDecor.auxid());
366 }
367 }
369 static const IsoVector dummy{};
370 if (!particle) return dummy;
371 if (particle->type() == xAOD::Type::ObjectType::Electron)
372 return m_electron_isoTypes;
373 else if (particle->type() == xAOD::Type::ObjectType::Muon)
374 return m_muon_isoTypes;
375 else if (particle->type() == xAOD::Type::ObjectType::Photon)
376 return m_photon_isoTypes;
377 return dummy;
378 }
379
381 const xAOD::IParticle* par,
382 ObjectCache& cache) const {
383 const IsoVector& types = getIsolationTypes(par);
384 if (types.empty()) {
385 ATH_MSG_WARNING("No isolation types are defiend for " << particleName(par));
387 }
388 for (const IsolationType iso_type : types) {
389 float iso_variable{0.f};
390 if (isTrackIso(iso_type)) {
391 if (getCloseByCorrectionTrackIso(par, iso_type, cache, iso_variable) == CorrectionCode::Error) {
392 ATH_MSG_ERROR("Failed to apply track correction");
394 }
395 } else if (isTopoEtIso(iso_type)) {
396 if (getCloseByCorrectionTopoIso(ctx, par, iso_type, cache, iso_variable) == CorrectionCode::Error) {
397 ATH_MSG_ERROR("Failed to apply topo cluster correction");
399 }
400 } else if (isPFlowIso(iso_type)) {
401 if (getCloseByCorrectionPflowIso(ctx, par, iso_type, cache, iso_variable) == CorrectionCode::Error) {
402 ATH_MSG_ERROR("Failed to apply pflow correction");
404 }
405 }
406 ATH_MSG_DEBUG("subtractCloseByContribution: Set pt, eta, phi " << par->pt() << ", " << par->eta() << ", " << par->phi() << " for " << toString(iso_type) << " to " << iso_variable);
407 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
408 if (m_isohelpers.at(iso_type)->setIsolation(par, iso_variable) == CorrectionCode::Error) {
409 ATH_MSG_ERROR("Cannot set " << toString(iso_type) << " to " << iso_variable);
410 return CorrectionCode::Error;
411 }
412 }
413 return CorrectionCode::Ok;
414 }
415
417 const IsoVector& types = getIsolationTypes(part);
418
419 ATH_MSG_DEBUG("copyIsoValuesForPartsNotSelected " << part->type() << " " << part->pt() * MeVtoGeV << " GeV" << " eta: " << part->eta() << " phi: " << part->phi());
420
421 if (types.empty()) {
422 ATH_MSG_WARNING("No isolation types are defiend for " << particleName(part));
424 }
425 for (const IsolationType iso_type : types) {
426 float iso_variable{0.f};
427 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
428 if (m_isohelpers.at(iso_type)->getIsolation(part, iso_variable) == CorrectionCode::Error) {
429 ATH_MSG_ERROR("Cannot get value for " << toString(iso_type));
430 return CorrectionCode::Error;
431 }
432 ATH_MSG_DEBUG("copyIsoValuesForPartsNotSelected: Set pt, eta " << part->pt() << ", " << part->eta() << ", " << part->phi() << " for " << toString(iso_type) << " to " << iso_variable);
433 if (!std::isfinite(iso_variable)) {
434 ATH_MSG_WARNING("Copying non-finite " << toString(iso_type) << " = " << iso_variable << " of particle with pt: " << part->pt() * MeVtoGeV << " GeV eta: " << part->eta() << " phi: " << part->phi());
435 }
436 if (m_isohelpers.at(iso_type)->setIsolation(part, iso_variable, true) == CorrectionCode::Error) {
437 ATH_MSG_ERROR("Cannot set " << toString(iso_type) << " to " << iso_variable);
438 return CorrectionCode::Error;
439 }
440 }
441 return CorrectionCode::Ok;
442 }
443
444
446 const std::vector<IsolationType>& types,
447 const xAOD::IParticleContainer& closePar) const {
448
449 if (!m_isInitialised) {
450 ATH_MSG_ERROR("The IsolationCloseByCorrectionTool was not initialised!!!");
452 }
454 {
455 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
456 for (const IsolationType& t : types) {
457 IsoHelperMap::const_iterator Itr = m_isohelpers.find(t);
458 if (Itr != m_isohelpers.end()) { continue; }
459 Itr = m_isohelpers.insert(std::make_pair(t, std::make_unique<IsoVariableHelper>(t, m_backup_prefix, m_isoDecSuffix))).first;
460 }
461 }
462 corrections.assign(types.size(), 0);
463 ObjectCache cache{};
464 loadPrimaryParticles(&closePar, cache);
465 const EventContext& ctx = Gaudi::Hive::currentContext();
466 loadAssociatedObjects(ctx, cache);
467 std::vector<float>::iterator Cone = corrections.begin();
468 for (const IsolationType& iso_type : types) {
469 {
470 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
471 IsoHelperMap::const_iterator Itr = m_isohelpers.find(iso_type);
472 if (Itr->second->backupIsolation(&par) == CP::CorrectionCode::Error) {
473 ATH_MSG_ERROR("Failed to backup isolation");
475 }
476 }
477 if (isTrackIso(iso_type)) {
478 if (getCloseByCorrectionTrackIso(&par, iso_type, cache, (*Cone)) == CorrectionCode::Error) {
479 ATH_MSG_ERROR("Failed to apply track correction");
481
482 }
483 }
484 else if (isTopoEtIso(iso_type)) {
485 if (getCloseByCorrectionTopoIso(ctx, &par, iso_type, cache, (*Cone)) == CorrectionCode::Error) {
486 ATH_MSG_ERROR("Failed to apply topo cluster correction");
488 }
489 }
490 else if (isPFlowIso(iso_type)) {
491 if (getCloseByCorrectionPflowIso(ctx, &par, iso_type, cache, (*Cone)) == CorrectionCode::Error) {
492 ATH_MSG_ERROR("Failed to apply pflow correction");
494 }
495 }
496 ++Cone;
497 }
498 return CorrectionCode::Ok;
499 }
500 // check for non-zero primary vtx - single particle samples don't have one
502 return trk && vtx && m_trkselTool->accept(*trk, vtx) && (!m_has_nonTTVA || m_ttvaTool->isCompatible(*trk, *vtx));
503 }
505 TrackSet to_return{};
506 if (P->type() == xAOD::Type::Muon) {
507 const xAOD::Muon* mu = static_cast<const xAOD::Muon*>(P);
508 if (mu->muonType() != xAOD::Muon::MuonType::SiliconAssociatedForwardMuon)
509 to_return.emplace(mu->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle));
510 } else if (P->type() == xAOD::Type::TrackParticle) {
511 const xAOD::TrackParticle* trk = static_cast<const xAOD::TrackParticle*>(P);
512 to_return.emplace(trk);
513 } else if (isEgamma(P)) {
514 const xAOD::Egamma* EG = static_cast<const xAOD::Egamma*>(P);
515 std::set<const xAOD::TrackParticle*> trk_vec = xAOD::EgammaHelpers::getTrackParticles(EG, true, true);
516 for (const xAOD::TrackParticle* trk : trk_vec) {
517 ATH_MSG_VERBOSE("Adding egamma track with "
518 << trk->pt() * MeVtoGeV << " GeV, eta: " << trk->eta() << ", phi: " << trk->phi());
519 to_return.emplace(trk);
520 }
521 }
522 return to_return;
523 }
525 const TrackSet assoc_tracks = getAssociatedTracks(P);
526 TrackSet to_ret{};
527 for (const TrackPtr trk : assoc_tracks) {
528 if (passFirstStage(trk, vtx)) to_ret.insert(trk);
529 }
530 return to_ret;
531 }
532 TrackSet IsolationCloseByCorrectionTool::getTrackCandidates(const EventContext& ctx, const xAOD::IParticle* particle) const {
534 }
538
539 // Collect topoclusters for electron, photon and muons
540 // - for electrons and photons, collect the associated clusters
541 // - for muons, use associated cluster, if it exists, to get topocluster, otherwise, extrapolate the InDet trackParticle to calo
542 // and look for topoclusters matching in dR the core muon cone
544 ObjectCache& cache) const {
545 // Remember topoclusters which are associated to an egamma object, electron or photon
546 // This will be used to avoid associating the same object to a muon
547 ClusterSet clusters;
548 if (isEgamma(P)) {
549 const xAOD::Egamma* egamm = static_cast<const xAOD::Egamma*>(P);
550 for (size_t calo = 0; calo < egamm->nCaloClusters(); ++calo) {
551 const xAOD::CaloCluster* clust = egamm->caloCluster(calo);
552 if (!clust) continue;
553 std::vector<const xAOD::CaloCluster*> constituents = xAOD::EgammaHelpers::getAssociatedTopoClusters(clust);
554 for (const xAOD::CaloCluster* cluster : constituents) {
555 if (cluster && std::abs(cluster->eta()) < 7. && cluster->e() > MinClusterEnergy) {
556 clusters.emplace(cluster);
557 cache.eg_associated_clusters.insert(cluster); // set flag that this cluster is associated to an electron or photon
558 ATH_MSG_VERBOSE("getAssociatedClusters: " << P->type() << " has topo cluster with pt: " << cluster->pt() * MeVtoGeV << " GeV, eta: "
559 << cluster->eta() << ", phi: " << cluster->phi());
560 }
561 }
562 }
563 if (clusters.size()) return clusters;
564 }
565 if (m_CaloClusterKey.empty()) return clusters;
567 if (!topoClusters.isValid()) return clusters;
568
569 if (P->type() == xAOD::Type::ObjectType::Muon) {
570 const xAOD::Muon* mu = static_cast<const xAOD::Muon*>(P);
571 const xAOD::CaloCluster* cl = mu->cluster();
572 bool foundMuonTopo = false;
573 if (cl) {
574 ATH_MSG_VERBOSE("getAssociatedClusters: muon has cluster with pt: " << cl->pt() * MeVtoGeV << " GeV, eta: "
575 << cl->eta() << ", phi: " << cl->phi());
576 std::vector<const xAOD::CaloCluster*> constituents = xAOD::EgammaHelpers::getAssociatedTopoClusters(cl);
577 for (const xAOD::CaloCluster* cluster : constituents) {
578 if (cluster && std::abs(cluster->eta()) < 7. && cluster->e() > MinClusterEnergy) {
579 // skip association if this cluster is already associated with an electron or photon - priority is given to egamma reco
580 if (!cache.eg_associated_clusters.contains(cluster)) {
581 clusters.emplace(cluster);
582 foundMuonTopo = true;
583 ATH_MSG_VERBOSE("getAssociatedClusters: muon has topo cluster with pt: " << cluster->pt() * MeVtoGeV << " GeV, eta: "
584 << cluster->eta() << ", phi: " << cluster->phi());
585 }
586 else {
587 ATH_MSG_VERBOSE("getAssociatedClusters: muon topo cluster already associated with an EG objet - cluster with pt: "
588 << cluster->pt() * MeVtoGeV << " GeV, eta: " << cluster->eta() << ", phi: " << cluster->phi());
589 }
590 }
591 }
592 }
593 if (!foundMuonTopo) {
594#ifndef XAOD_ANALYSIS
595 // extraploate muon to calo and look for matching topo cluster
596 const xAOD::TrackParticle* tp = mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
597 if (tp) {
598 ATH_MSG_VERBOSE("getAssociatedClusters: found mu tp " << " with pt: " << tp->pt() * MeVtoGeV << " GeV, eta: " << tp->eta() << ", phi: " << tp->phi());
599 float tpEtaAtCalo;
600 float tpPhiAtCalo;
601 if (getExtrapEtaPhi(ctx, tp, tpEtaAtCalo, tpPhiAtCalo)) {
602 ATH_MSG_VERBOSE("getAssociatedClusters: tp extrapolated - tpEtaAtCalo " << tpEtaAtCalo << ", tpPhiAtCalo " << tpPhiAtCalo);
603 for (const xAOD::CaloCluster* cluster : *topoClusters) {
604 if (cluster && std::abs(cluster->eta()) < 7. && cluster->e() > MinClusterEnergy &&
605 xAOD::P4Helpers::deltaR(tpEtaAtCalo, tpPhiAtCalo, cluster->eta(), cluster->phi()) < m_coreConeMu) {
606 clusters.emplace(cluster);
607 ATH_MSG_VERBOSE("getAssociatedClusters: for mu trkPart save clus " << " with pt: " << cluster->pt() * MeVtoGeV << " GeV, eta: " << cluster->eta() << ", phi: " << cluster->phi() << ", tpEtaAtCalo " << tpEtaAtCalo << ", tpPhiAtCalo " << tpPhiAtCalo);
608 }
609 }
610 }
611 }
612#endif
613 }
614 }
615
616 return clusters;
617 }
619 if (!P) return false;
620 if (m_acc_quality && (!m_acc_quality->isAvailable(*P) || !(*m_acc_quality)(*P))) return false;
621 if (m_acc_passOR && (!m_acc_passOR->isAvailable(*P) || !(*m_acc_passOR)(*P))) return false;
622 return true;
623 }
625 const ObjectCache& cache, float& isoValue) const {
626 if (!isTrackIso(type)) {
627 ATH_MSG_ERROR("Invalid isolation type " << toString(type));
629 }
630 {
631 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
632 IsoHelperMap::const_iterator Itr = m_isohelpers.find(type);
633 if (Itr == m_isohelpers.end() || Itr->second->getOriginalIsolation(par, isoValue) == CorrectionCode::Error) {
634 ATH_MSG_WARNING(__func__<<"() -- "<<__LINE__<<" Could not retrieve the isolation variable " << toString(type));
636 } else if (cache.tracks.empty())
637 return CorrectionCode::Ok;
638 }
639
640 float MaxDR = coneSize(par, type);
641 const TrackSet ToExclude = getAssociatedTracks(par);
642
643 const xAOD::IParticle* Ref = isoRefParticle(par);
644 ATH_MSG_VERBOSE(toString(type) << " of " << particleName(par) << " with pt: " << par->pt() * MeVtoGeV << " GeV, eta: " << par->eta()
645 << ", phi: " << par->phi() << " before correction: " << isoValue * MeVtoGeV << " GeV. "
646 << ToExclude.size() << " tracks will be excluded.");
647
648 for (const TrackPtr& poluting_trk : cache.tracks) {
649 // Checks for the Pile-up robust isolation WP's
650 if (poluting_trk->pt() < trackPtCut(type)) continue;
652 if (isTrackIsoTTVA(type) && m_has_nonTTVA && !m_ttvaTool->isCompatible(*poluting_trk, *cache.prim_vtx)) continue;
653
654 if (overlap(Ref, poluting_trk, MaxDR) && !ToExclude.count(poluting_trk)) {
655 ATH_MSG_VERBOSE("Subtract track with "
656 << poluting_trk->pt() * MeVtoGeV << " GeV, eta: " << poluting_trk->eta() << ", phi: " << poluting_trk->phi()
657 << " with dR: " << std::sqrt(deltaR2(Ref, poluting_trk)) << " from the isolation cone " << toString(type)
658 << " " << (isoValue * MeVtoGeV) << " GeV.");
659 isoValue -= poluting_trk->pt();
660 }
661 }
662 isoValue = std::max(0.f, isoValue);
663 ATH_MSG_VERBOSE(toString(type) << " of " << particleName(par) << " with pt: " << par->pt() * MeVtoGeV << " GeV, eta: " << par->eta()
664 << ", phi: " << par->phi() << " after correction: " << isoValue * MeVtoGeV << " GeV");
665 return CorrectionCode::Ok;
666 }
668 const IsoType type, const ObjectCache& cache,
669 float& isoValue) const {
670 if (!isPFlowIso(type)) {
671 ATH_MSG_ERROR("getCloseByCorrectionPflowIso() -- The isolation type is not a Pflow variable " << toString(type));
673 }
674 if (m_isohelpers.at(type)->getOriginalIsolation(primary, isoValue) == CorrectionCode::Error) {
675 ATH_MSG_ERROR("getCloseByCorrectionPflowIso() -- Could not retrieve the isolation variable.");
677 }
679 if (isoValue <= 0.) {
680 ATH_MSG_DEBUG("Pflow varible is already sufficiently isolated ");
681 return CorrectionCode::Ok;
682 }
683 const float coneDR = coneSize(primary, type);
684 float ref_eta{0.f}, ref_phi{0.f};
685 getExtrapEtaPhi(primary, ref_eta, ref_phi);
688 ATH_MSG_VERBOSE("getCloseByCorrectionPflowIso: " << toString(type) << " of " << particleName(primary) << " with pt: "
689 << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
690 << ", phi: " << primary->phi() << " before correction: " << isoValue * MeVtoGeV << " GeV. ");
691 PflowSet assoc_coll = getAssocFlowElements(ctx, primary);
692 for (const FlowElementPtr& flow : cache.flows) {
693 ATH_MSG_VERBOSE("Loop over pflow element: " << flow->pt() << " GeV, eta: " << flow->eta() << " phi: " << flow->phi());
694
695 const float dR = xAOD::P4Helpers::deltaR(ref_eta,ref_phi, flow->eta(),flow->phi());
696 if(dR < (primary->type() == xAOD::Type::ObjectType::Muon ? m_coreConeMu : m_coreConeEl)) {
697 ATH_MSG_VERBOSE("Flow element is in core cone");
698 continue;
699 }
700 if (assoc_coll.count(flow)) {
701 ATH_MSG_VERBOSE("Flow element is directly associated with the object");
702 continue;
703 }
704 if (dR < coneDR) {
705 ATH_MSG_VERBOSE("Found overlapping pflow element: " << flow->pt() << " GeV, eta: " << flow->eta()
706 << " phi: " << flow->phi() << " dR: " << dR);
707 isoValue -= flow->pt() * flow.weight;
708 }
709 }
710 ATH_MSG_VERBOSE("getCloseByCorrectionPflowIso: " << toString(type) << " of " << particleName(primary) << " with pt: "
711 << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
712 << ", phi: " << primary->phi() << " after correction: " << isoValue * MeVtoGeV << " GeV. ");
714 static const FloatAccessor acc_eta{pflowDecors()[0]};
715 static const FloatAccessor acc_phi{pflowDecors()[1]};
716 static const FloatAccessor acc_ene{pflowDecors()[2]};
717 static const CharAccessor acc_isDecor{pflowDecors()[3]};
718 for (const xAOD::IParticle* others : cache.prim_parts) {
719 if (others == primary) continue;
720 if (!acc_isDecor.isAvailable(*others) || !acc_isDecor(*others)) {
721 ATH_MSG_ERROR("The variable energy averaged pflow decorations are not available for "<<particleName(others)<<". Please check");
723 }
724 const float other_eta = acc_eta(*others);
725 const float other_phi = acc_phi(*others);
726 const float dR = xAOD::P4Helpers::deltaR(ref_eta,ref_phi,other_eta,other_phi);
727 if (dR > coneDR) continue;
728 if (dR< (primary->type() == xAOD::Type::ObjectType::Muon ? m_coreConeMu : m_coreConeEl)) continue;
729 isoValue -= acc_ene(*others);
730 }
731 } else {
732 ATH_MSG_ERROR("Unknown calo correction model "<<m_caloModel);
734 }
735 isoValue = std::max(0.f, isoValue);
736 return CorrectionCode::Ok;
737 }
738
740 const IsoType type, ObjectCache& cache,
741 float& isoValue) const {
742 // check if the isolation can be loaded
743 if (!isTopoEtIso(type)) {
744 ATH_MSG_ERROR("getCloseByCorrectionTopoIso() -- The isolation type is not an et cone variable " << toString(type));
746 }
747 {
748 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
749 if (m_isohelpers.at(type)->getOriginalIsolation(primary, isoValue) == CorrectionCode::Error) {
750 ATH_MSG_WARNING("Could not retrieve the isolation variable.");
752 }
753 }
755 if (isoValue <= 0.) {
756 ATH_MSG_DEBUG("Topo et cone variable is already sufficiently isolated");
757 return CorrectionCode::Ok;
758 }
759 float ref_eta{0.f}, ref_phi{0.f};
760 getExtrapEtaPhi(primary, ref_eta, ref_phi);
761 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: " << toString(type) << " of " << particleName(primary) << " with ref eta: " << ref_eta << ", ref phi " << ref_phi);
762
763 float MaxDR = coneSize(primary, type) * (primary->type() != xAOD::Type::ObjectType::Muon ? 1. : m_ConeSizeVariation.value());
765 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: " << toString(type) << " of " << particleName(primary) << " with pt: "
766 << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
767 << ", phi: " << primary->phi() << " before correction: " << isoValue * MeVtoGeV << " GeV. ");
768 ClusterSet assoc = getAssociatedClusters(ctx, primary, cache);
769 for (const CaloClusterPtr& calo : cache.clusters) {
770 const float dR = xAOD::P4Helpers::deltaR(ref_eta, ref_phi, calo->eta(), calo->phi());
771 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: Loop over cluster: " << calo->pt() * MeVtoGeV << " GeV, eta: " << calo->eta() << " phi: " << calo->phi() << " dR: " << dR);
772 if (dR > MaxDR) continue;
773 // REMOVED CORE CUT SINCE TOPOCLUSTERS SHOULD BE ASSOCIATED TO THE ELECTRONS AND MUONS AND WILL BE CUT BY ASSOC CUT BELOW
774 if (assoc.count(calo)) {
775 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: skip due to assoc " << assoc.count(calo));
776 continue;
777 }
778 float Polution = clusterEtMinusTile(calo) / (isoValue != 0 ? isoValue : 1.);
779 if (Polution < 0. || Polution > m_maxTopoPolution) {
780 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: skip due to polution " << Polution << ", clus noTile " << clusterEtMinusTile(calo) * MeVtoGeV << " GeV");
781 continue;
782 }
783 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: Found overlapping topocluster: " << calo->pt() * MeVtoGeV << " GeV, lessTile " << clusterEtMinusTile(calo) * MeVtoGeV << " GeV, eta: " << calo->eta()
784 << " phi: " << calo->phi() << " dR: " << dR);
785 isoValue -= clusterEtMinusTile(calo);
786 }
787 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: " << toString(type) << " of " << particleName(primary) << " with pt: "
788 << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
789 << ", phi: " << primary->phi() << " after correction: " << isoValue * MeVtoGeV << " GeV. ");
791 const FloatAccessor acc_eta{caloDecors()[0] + m_caloDecSuffix};
792 const FloatAccessor acc_phi{caloDecors()[1] + m_caloDecSuffix};
793 const FloatAccessor acc_ene{caloDecors()[2] + m_caloDecSuffix};
794 const CharAccessor acc_isDecor{caloDecors()[3] + m_caloDecSuffix};
795 for (const xAOD::IParticle* others : cache.prim_parts) {
796 if (others == primary) continue;
797 if (!acc_isDecor.isAvailable(*others) || !acc_isDecor(*others)) {
798 ATH_MSG_ERROR("The averaged calo cluster decorations are not available for "<<particleName(others)<<". Please check");
800 }
801 const float other_eta = acc_eta(*others);
802 const float other_phi = acc_phi(*others);
803 const float dR = xAOD::P4Helpers::deltaR(ref_eta,ref_phi,other_eta,other_phi);
804 if (dR > MaxDR) continue;
805 if (dR< (primary->type() == xAOD::Type::ObjectType::Muon ? m_coreConeMu : m_coreConeEl)) continue;
806 isoValue -= acc_ene(*others);
807 }
808 }
809 isoValue = std::max(0.f, isoValue);
810 return CorrectionCode::Ok;
811 }
815 const CharAccessor acc_isDecor{caloDecors()[3] + m_caloDecSuffix};
816 if (par->type() != xAOD::Type::ObjectType::Muon) {
817 const xAOD::Egamma* egam = dynamic_cast<const xAOD::Egamma*>(par);
818 if( egam ) {
819 eta = egam->caloCluster()->eta();
820 phi = egam->caloCluster()->phi();
821 }
822 else {
823 eta = par->eta();
824 phi = par->phi();
825 }
826 } else if (acc_isDecor.isAvailable(*par) && acc_isDecor(*par)) {
827 eta = acc_assocEta(*par);
828 phi = acc_assocPhi(*par);
829 } else {
830 float assoc_ene{0.f};
833 const CharDecorator dec_isDecor{caloDecors()[3] + m_caloDecSuffix};
834 associateCluster(par,eta, phi, assoc_ene);
835 dec_assocEta(*par) = eta;
836 dec_assocPhi(*par) = phi;
837 dec_isDecor(*par) = true;
838 }
839 }
840 void IsolationCloseByCorrectionTool::associateFlowElement(const EventContext& ctx, const xAOD::IParticle* particle, float& eta,
841 float& phi, float& energy) const {
842 phi = eta = energy = 0.;
843 PflowSet flowCollection = getAssocFlowElements(ctx, particle);
844 if (flowCollection.empty()) {
845 phi = particle->phi();
846 eta = particle->eta();
847 return;
848 }
849 for (const FlowElementPtr& ele : flowCollection) {
850 const float flow_energy = ele->e() * ele.weight;
851 if (flow_energy < MinClusterEnergy) continue;
852 phi += ele->phi() * flow_energy;
853 eta += ele->eta() * flow_energy;
854 energy += flow_energy;
855 }
856 if (energy < MinClusterEnergy) {
857 phi = particle->phi();
858 eta = particle->eta();
859 return;
860 }
861 phi = xAOD::P4Helpers::deltaPhi(phi / energy, 0.);
862 eta /= energy;
863 }
864 void IsolationCloseByCorrectionTool::associateCluster(const xAOD::IParticle* particle, float& eta, float& phi, float& energy) const {
865 phi = particle->phi();
866 eta = particle->eta();
867 energy = -1.;
868 if (particle->type() == xAOD::Type::ObjectType::Muon) {
869 const xAOD::Muon* mu = static_cast<const xAOD::Muon*>(particle);
870 const xAOD::CaloCluster* cluster = mu->cluster();
871 if (!cluster) return;
872 energy = cluster->e();
873 // At the moment no cluster associated with muons is in the derivations
874 int nSample{0};
875 float etaT{0.f}, phiT{0.f}, dphiT{0.f};
876
877 for (unsigned int i = 0; i < CaloSampling::Unknown; ++i) {
879 if (cluster->hasSampling(s)) {
880 ATH_MSG_VERBOSE("Sampling: " << i << "eta-phi (" << cluster->etaSample(s) << ", " << cluster->phiSample(s) << ")");
881 etaT += cluster->etaSample(s);
882 if (!nSample)
883 phiT = cluster->phiSample(s);
884 else
885 dphiT += xAOD::P4Helpers::deltaPhi(cluster->phiSample(s), phiT);
886 ++nSample;
887 }
888 }
889 if (!nSample) return;
890 ATH_MSG_DEBUG("Eta, phi before sampling: " << eta << ", " << phi << " and after sampling: " << etaT / nSample << ", "
891 << phiT / nSample);
892 phi = xAOD::P4Helpers::deltaPhi(phiT + dphiT / nSample, 0);
893 eta = etaT / nSample;
894 ATH_MSG_VERBOSE("associateCluster: mu with pt: " << mu->pt() * MeVtoGeV << " GeV, eta: "
895 << mu->eta() << ", phi: " << mu->phi() << " energy, eta, phi " << energy << ", " << eta << ", " << phi
896 << ", et " << energy * mu->pt() / mu->e());
897 }
898 if (!isEgamma(particle)) return;
899 const xAOD::Egamma* egamm = static_cast<const xAOD::Egamma*>(particle);
900 eta = phi = energy = 0.;
901 for (unsigned int cl = 0; cl < egamm->nCaloClusters(); ++cl) {
902 const xAOD::CaloCluster* prim_cluster = egamm->caloCluster(cl);
903 if (!prim_cluster) {
904 ATH_MSG_DEBUG("Cluster " << cl << " is not defined " << egamm);
905 continue;
906 }
907 std::vector<const xAOD::CaloCluster*> constituents = xAOD::EgammaHelpers::getAssociatedTopoClusters(prim_cluster);
908 for (const xAOD::CaloCluster* cluster : constituents) {
909 if (!cluster) continue;
910 const float clus_e = clusterEtMinusTile(cluster);
912 if (clus_e < MinClusterEnergy) continue;
913 eta += cluster->eta() * clus_e;
914 phi += cluster->phi() * clus_e;
915 energy += clus_e;
916 ATH_MSG_VERBOSE("associateCluster: eg add in clus with e: " << clus_e * MeVtoGeV << " clus et " << cluster->pt() * MeVtoGeV << " GeV, eta: "
917 << cluster->eta() << ", phi: " << cluster->phi());
918 }
919 }
920 if (energy >= MinClusterEnergy) {
921 phi = xAOD::P4Helpers::deltaPhi(phi / energy, 0.);
922 eta /= energy;
923 ATH_MSG_VERBOSE("associateCluster: eg with pt: " << egamm->pt() * MeVtoGeV << " GeV, eta: "
924 << egamm->eta() << ", phi: " << egamm->phi() << " energy, eta, phi " << energy << ", " << eta << ", " << phi );
925 } else {
926 ATH_MSG_DEBUG("Average energy from the clusters is too low " << energy << " copy particle properties");
927 eta = egamm->eta();
928 phi = egamm->phi();
929 energy = egamm->e();
930 }
931 }
933 const xAOD::IParticleContainer& closePar) const {
934 if (!m_isInitialised) { ATH_MSG_WARNING("The IsolationCloseByCorrectionTool was not initialised!!!"); }
935 assert(!m_selectorTool.empty());
936 const IsoVector& iso_types = getIsolationTypes(&x);
937 if (iso_types.empty()) {
938 // TODO: figure out if this is actually a valid situation
939 // or if we should just fail at this point.
940 ATH_MSG_WARNING("Could not cast particle for acceptCorrected. Will return false.");
941 static const asg::AcceptInfo dummyAcceptInfo = []() {
942 asg::AcceptInfo info;
943 info.addCut("castCut", "whether we managed to cast to a known type");
944 return info;
945 }();
946 if (m_dec_isoselection) (*m_dec_isoselection)(x) = false;
947 return asg::AcceptData(&dummyAcceptInfo);
948 }
949
950 if (closePar.empty()) return m_selectorTool->accept(x);
951 strObj strPar;
952 strPar.isolationValues.resize(numIsolationTypes);
953 strPar.pt = x.pt();
954 strPar.eta = x.eta();
955 strPar.type = x.type();
956 std::vector<float> corrections;
957 if (getCloseByCorrection(corrections, x, iso_types, closePar) == CorrectionCode::Error) {
958 ATH_MSG_WARNING("Could not calculate the corrections. acceptCorrected(x) is done without the corrections.");
959 if (m_dec_isoselection) (*m_dec_isoselection)(x) = bool(m_selectorTool->accept(x));
960 return m_selectorTool->accept(x);
961 }
962 for (unsigned int i = 0; i < iso_types.size(); ++i) {
963 strPar.isolationValues.at(iso_types[i]) = corrections.at(i);
965 if (acc)[[likely]]{
966 float old = (*acc)(x);
967 ATH_MSG_DEBUG("Correcting " << toString(iso_types[i]) << " from " << old << " to " << corrections[i]);
968 }
969 }
970 auto accept = m_selectorTool->accept(strPar);
971 if (m_dec_isoselection) (*m_dec_isoselection)(x) = bool(accept);
972 return accept;
973 }
976 if (!Verticies.isValid() || !Verticies->size()) {
977 ATH_MSG_WARNING("Failed to load vertex collection " << m_VtxKey.key());
978 return nullptr;
979 }
980 for (const xAOD::Vertex* V : *Verticies) {
981 if (V->vertexType() == xAOD::VxType::VertexType::PriVtx) {
982 ATH_MSG_VERBOSE("retrieveIDBestPrimaryVertex: vertex found ");
983 return V;
984 }
985 }
986 ATH_MSG_VERBOSE("retrieveIDBestPrimaryVertex: no vertex found ");
987 return nullptr;
988 }
989
992 float ConeDR = coneSize(Cone);
994 const xAOD::IParticle* Reference = isoRefParticle(P);
995 float MiniIso = m_ptvarconeRadius / unCalibPt(Reference);
996 if (MiniIso < ConeDR) return MiniIso;
997 }
998 return ConeDR;
999 }
1001 if (!P) {
1002 ATH_MSG_WARNING("No partcile given. Return stupidly big number. ");
1003 return 1.e25;
1004 }
1006 if (!OR) {
1007 ATH_MSG_VERBOSE("No reference from the shallow copy container of " << particleName(P) << " could be found");
1008 return P->pt();
1009 }
1010 return OR->pt();
1011 }
1012
1014 if (!P) {
1015 ATH_MSG_ERROR("Nullptr given");
1016 return nullptr;
1017 }
1018 // Use for muons the associated ID track. Else the particle itself
1019 if (P->type() == xAOD::Type::ObjectType::Muon) {
1020 const xAOD::Muon* muon = static_cast<const xAOD::Muon*>(P);
1021 const xAOD::TrackParticle* idTrk = muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
1022 return idTrk ? idTrk : muon->trackParticle(xAOD::Muon::TrackParticleType::Primary);
1023 }
1024 return P;
1025 }
1027 if (!P || !P1) {
1028 ATH_MSG_WARNING("Nullptr were given");
1029 return true;
1030 }
1031 return (P == P1);
1032 }
1033
1034 float IsolationCloseByCorrectionTool::deltaR2(const xAOD::IParticle* P, const xAOD::IParticle* P1, bool AvgCalo) const {
1035 if (isSame(P, P1)) return 0.;
1036 // Check if one of the objects is a CaloCluster or the Averaging over the clusters is requested.
1037 if (AvgCalo || (P->type() != P1->type() &&
1039 float phi1{0.f}, eta1{0.f}, eta2{0.f}, phi2{0.f};
1040 getExtrapEtaPhi(P, eta1, phi1);
1041 getExtrapEtaPhi(P1, eta2, phi2);
1042 return xAOD::P4Helpers::deltaR2(eta1, phi1, eta2, phi2);
1043 }
1044 float dPhi = xAOD::P4Helpers::deltaPhi(P, P1);
1045 float dEta = P->eta() - P1->eta();
1046 return dEta * dEta + dPhi * dPhi;
1047 }
1049 return (!isSame(P, P1) && deltaR2(P, P1) < (dR * dR));
1050 }
1052 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
1053 IsoHelperMap::const_iterator itr = m_isohelpers.find(isoVariable);
1054 float isovalue = 0;
1055 if (itr == m_isohelpers.end() || itr->second->getOriginalIsolation(particle, isovalue) == CorrectionCode::Error) {
1056 ATH_MSG_ERROR("Failed to retrieve the original isolation cone ");
1057 isovalue = FLT_MAX;
1058 }
1059 return isovalue;
1060 }
1065 float Et{0.f};
1066 if (cluster) {
1067 try {
1068 Et = cluster->p4(xAOD::CaloCluster::State::UNCALIBRATED).Et();
1069 Et = Et - cluster->eSample(xAOD::CaloCluster::CaloSample::TileGap3) /
1070 std::cosh(cluster->p4(xAOD::CaloCluster::State::UNCALIBRATED).Eta());
1071 } catch (...) { Et = cluster->p4().Et(); }
1072 }
1073 return std::max(Et, 0.f);
1074 }
1077 if (T == xAOD::Type::ObjectType::Electron) return "Electron";
1078 if (T == xAOD::Type::ObjectType::Photon) return "Photon";
1079 if (T == xAOD::Type::ObjectType::Muon) return "Muon";
1080 if (T == xAOD::Type::ObjectType::TrackParticle) return "Track";
1081 if (T == xAOD::Type::ObjectType::CaloCluster) return "Cluster";
1082 return "Unknown";
1083 }
1108 ATH_MSG_INFO("The following isolation cones are considered for " << particleName(T));
1109 for (const IsoType& cone : types) { ATH_MSG_INFO(" --- " << toString(cone)); }
1110 }
1122} // namespace CP
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
Handle class for reading from StoreGate.
static Double_t P(Double_t *tt, Double_t *par)
#define x
Define macros for attributes used to control the static checker.
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ OutOfValidityRange
Input object is out of validity range.
@ Ok
The correction was done successfully.
bool m_has_nonTTVA
Switch whether a pile-up non robust TTVA working point is defined.
CorrectionCode getCloseByCorrectionTopoIso(const EventContext &ctx, const xAOD::IParticle *primary, const IsoType type, ObjectCache &cache, float &isoValue) const
bool overlap(const xAOD::IParticle *particle, const xAOD::IParticle *particle1, float dR) const
const xAOD::IParticle * isoRefParticle(const xAOD::IParticle *particle) const override
Retrieve the reference particle to define the cone axis in which the track particles contributing to ...
IsoVector m_electron_isoTypes
Isolation variables used by the electron working point.
IsoVector m_muon_isoTypes
Isolation variables used by the muon working point.
bool passFirstStage(const xAOD::TrackParticle *trk, const xAOD::Vertex *vtx) const
The Track particle has to pass the Track selection tool and the TTVA selection.
CorrectionCode getCloseByCorrectionTrackIso(const xAOD::IParticle *primary, const IsoType type, const ObjectCache &cache, float &isoValue) const
ToolHandle< CP::ITrackVertexAssociationTool > m_ttvaTool
float deltaR2(const xAOD::IParticle *particle, const xAOD::IParticle *particle1, bool AvgCalo=false) const
bool m_hasPflowIso
Switch whether a pflow isolation working point is defined.
void lockDecorations(const xAOD::IParticleContainer *parts, const IsoVector &isoTypes) const
float unCalibPt(const xAOD::IParticle *particle) const
void declareDependency(const std::vector< std::string > &containers, const IsoVector &types)
Helper function to declare the data dependencies.
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
bool getExtrapEtaPhi(const EventContext &ctx, const xAOD::TrackParticle *tp, float &eta, float &phi) const
helper to get eta,phi of muon extrap
bool passSelectionQuality(const xAOD::IParticle *particle) const
void getAssocFlowElements(const EventContext &ctx, ObjectCache &cache) const
Retrieve all Flow elements associated with the particles in the cache.
ToolHandle< CP::IIsolationSelectionTool > m_selectorTool
Gaudi::Property< std::vector< std::string > > m_elecKeys
Declare the data dependencies of the Input containers.
static bool isTrackIso(xAOD::Iso::IsolationType type)
static bool isFixedTrackIso(xAOD::Iso::IsolationType type)
static bool isEgamma(const xAOD::IParticle *particle)
void associateFlowElement(const EventContext &ctx, const xAOD::IParticle *particle, float &eta, float &phi, float &energy) const override
ClusterSet getAssociatedClusters(const EventContext &ctx, const xAOD::IParticle *particle, ObjectCache &cache) const
Loads the topo clusters associated with the primary IParticle.
static bool isVarTrackIso(xAOD::Iso::IsolationType type)
void loadAssociatedObjects(const EventContext &ctx, ObjectCache &cache) const
Load all associated tracks / clusters / flow elements into the cache.
Gaudi::Property< std::vector< std::string > > m_photKeys
static float trackPtCut(xAOD::Iso::IsolationType type)
SG::ReadHandleKey< xAOD::CaloClusterContainer > m_CaloClusterKey
static bool isFixedTrackIsoTTVA(xAOD::Iso::IsolationType type)
IsoVector m_photon_isoTypes
Isolation variables used by the photon working point.
bool m_hasEtConeIso
Switch whether a topoetcone isolation working point is defined.
bool isSame(const xAOD::IParticle *particle, const xAOD::IParticle *particle1) const
void isoTypesFromWP(const std::vector< std::unique_ptr< IsolationWP > > &WP, IsoVector &types)
Helper function to load all Isolation types from the iso working points.
virtual CorrectionCode getCloseByIsoCorrection(const EventContext &ctx, const xAOD::ElectronContainer *Electrons, const xAOD::MuonContainer *Muons, const xAOD::PhotonContainer *Photons) const override
TrackSet getAssociatedTracks(const xAOD::IParticle *P) const
Retrieve all Inner detector tracks associated with the primary particle.
static const caloDecorNames & caloDecors()
Returns an array with the calo cluster decoration names [0]-> eta, [1]->phi, [2]->energy....
void printIsolationCones(const IsoVector &types, xAOD::Type::ObjectType T) const
CorrectionCode subtractCloseByContribution(const EventContext &ctx, const xAOD::IParticle *P, ObjectCache &cache) const
static float clusterEtMinusTile(const xAOD::CaloCluster *C)
virtual float getOriginalIsolation(const xAOD::IParticle &P, IsoType type) const override
SG::ReadDecorHandleKeyArray< xAOD::IParticleContainer > m_isoVarKeys
SG::WriteDecorHandleKeyArray< xAOD::IParticleContainer > m_isoWriteDecVarKeys
void loadPrimaryParticles(const xAOD::IParticleContainer *container, ObjectCache &cache) const
Filter all electrons/muons/photons from the collection which pass the selection decoration.
Gaudi::Property< std::string > m_isoSelection_name
SG::ReadHandleKey< xAOD::FlowElementContainer > m_PflowKey
CorrectionCode getCloseByCorrectionPflowIso(const EventContext &ctx, const xAOD::IParticle *primary, const IsoType type, const ObjectCache &cache, float &isoValue) const
static bool isTopoEtIso(xAOD::Iso::IsolationType type)
virtual asg::AcceptData acceptCorrected(const xAOD::IParticle &x, const xAOD::IParticleContainer &closePar) const override
Gaudi::Property< std::vector< std::string > > m_muonKeys
static std::string particleName(const xAOD::IParticle *C)
void associateCluster(const xAOD::IParticle *particle, float &eta, float &phi, float &energy) const override
Retrieve the associated clusters from the Particle and calculate the average eta/phi/energy.
const IsoVector & getIsolationTypes(const xAOD::IParticle *particle) const
ToolHandle< Trk::IParticleCaloExtensionTool > m_caloExtTool
calo extension tool for muon track particle extrapolation to calo
virtual CorrectionCode getCloseByCorrection(std::vector< float > &corrections, const xAOD::IParticle &par, const std::vector< xAOD::Iso::IsolationType > &types, const xAOD::IParticleContainer &closePar) const override
TrackSet getTrackCandidates(const EventContext &ctx, const xAOD::IParticle *particle) const override
Load all TrackParticles associated with the particles in the Container. The particles have to pass th...
SG::ReadHandleKey< xAOD::VertexContainer > m_VtxKey
static bool isVarTrackIsoTTVA(xAOD::Iso::IsolationType Iso)
ToolHandle< InDet::IInDetTrackSelectionTool > m_trkselTool
float coneSize(const xAOD::IParticle *particle, IsoType Cone) const
const xAOD::Vertex * retrieveIDBestPrimaryVertex(const EventContext &ctx) const
CorrectionCode copyIsoValuesForPartsNotSelected(const xAOD::IParticle *part) const
CorrectionCode performCloseByCorrection(const EventContext &ctx, ObjectCache &cache) const
static bool isPFlowIso(xAOD::Iso::IsolationType type)
Gaudi::Property< int > m_caloModel
EXPERT PROPERTIES.
static bool isTrackIsoTTVA(xAOD::Iso::IsolationType type)
bool empty() const noexcept
Returns true if the collection is empty.
Helper class to provide type-safe access to aux data.
Manage lookup of vectors of auxiliary data.
void lockDecoration(SG::auxid_t auxid)
Explicitly lock a decoration.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
an object that can create a AsgTool
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
virtual double pt() const
The transverse momentum ( ) of the particle (negative for negative-energy clusters).
float phiSample(const CaloSample sampling) const
Retrieve barycenter in a given sample.
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double e() const
The total energy of the particle.
float eSample(const CaloSample sampling) const
virtual double phi() const
The azimuthal angle ( ) of the particle.
float etaSample(const CaloSample sampling) const
Retrieve barycenter in a given sample.
virtual FourMom_t p4() const
The full 4-momentum of the particle.
bool hasSampling(const CaloSample s) const
Checks if certain smapling contributes to cluster.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition Egamma_v1.cxx:66
virtual double e() const override
The total energy of the particle.
Definition Egamma_v1.cxx:86
size_t nCaloClusters() const
Return the number of xAOD::CaloClusters that define the electron candidate.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
Definition Egamma_v1.cxx:71
virtual double phi() const override final
The azimuthal angle ( ) of the particle.
Definition Egamma_v1.cxx:76
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
Class providing the definition of the 4-vector interface.
virtual double eta() const =0
The pseudorapidity ( ) of the particle.
virtual Type::ObjectType type() const =0
The type of the object as a simple enumeration.
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .).
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
struct color C
Eigen::Matrix< double, 3, 1 > Vector3D
Select isolated Photons, Electrons and Muons.
constexpr float MeVtoGeV
@ W
FillWPartonHistory.
constexpr float MinClusterEnergy
IsolationCloseByCorrectionTool::caloDecorNames caloDecorNames
std::unordered_set< const SG::AuxVectorData * > UnorderedContainerSet
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
ObjectType
Type of objects that have a representation in the xAOD EDM.
Definition ObjectType.h:32
@ TrackParticle
The object is a charged track particle.
Definition ObjectType.h:43
@ Photon
The object is a photon.
Definition ObjectType.h:47
@ CaloCluster
The object is a calorimeter cluster.
Definition ObjectType.h:39
@ Muon
The object is a muon.
Definition ObjectType.h:48
@ Electron
The object is an electron.
Definition ObjectType.h:46
std::set< const xAOD::TrackParticle * > getTrackParticles(const xAOD::Egamma *eg, bool useBremAssoc=true, bool allParticles=true)
Return a list of all or only the best TrackParticle associated to the object.
std::vector< const xAOD::CaloCluster * > getAssociatedTopoClusters(const xAOD::CaloCluster *cluster)
Return a vector of all the topo clusters associated with the egamma cluster.
Namespace holding the IsolationType enumeration.
IsolationFlavour isolationFlavour(IsolationType type)
convert Isolation Type into Isolation Flavour
IsolationType
Overall enumeration for isolation types in xAOD files.
IsolationFlavour
Enumeration for different ways of calculating isolation in xAOD files.
@ topoetcone
Topo-cluster ET-sum.
@ ptvarcone_Nonprompt_All_MaxWeightTTVALooseCone_pt1000
@ ptcone_Nonprompt_All_MaxWeightTTVALooseCone_pt1000
@ ptvarcone_Nonprompt_All_MaxWeightTTVA_pt500
ptvarcone for high mu
@ neflowisol
neutral eflow
@ ptcone
Track isolation.
@ ptvarcone
mini isolation
@ ptvarcone_Nonprompt_All_MaxWeightTTVALooseCone_pt500
@ ptcone_Nonprompt_All_MaxWeightTTVA_pt1000
@ ptcone_Nonprompt_All_MaxWeightTTVALooseCone_pt500
ptcone for high mu
@ ptvarcone_Nonprompt_All_MaxWeightTTVA_pt1000
@ ptcone_Nonprompt_All_MaxWeightTTVA_pt500
ptcone for high mu
float coneSize(IsolationConeSize type)
convert Isolation Size into cone size
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
double deltaR(double rapidity1, double phi1, double rapidity2, double phi2)
from bare bare rapidity,phi
double deltaR2(double rapidity1, double phi1, double rapidity2, double phi2)
from bare rapidity,phi
@ PriVtx
Primary vertex.
PhotonContainer_v1 PhotonContainer
Definition of the current "photon container version".
const SG::Accessor< float > * getIsolationAccessor(Iso::IsolationType type)
Get the Accessor object for a given isolation type.
ElectronContainer_v1 ElectronContainer
Definition of the current "electron container version".
setEt setPhi setE277 setWeta2 eta1
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
FlowElement_v1 FlowElement
Definition of the current "pfo version".
Definition FlowElement.h:16
TrackParticle_v1 TrackParticle
Reference the current persistent version:
const IParticle * getOriginalObject(const IParticle &copy)
This function can be used to conveniently get a pointer back to the original object from which a copy...
static const SG::Accessor< std::vector< std::string > > names("thrNames")
Accessor for the names of the passed thresholds.
Vertex_v1 Vertex
Define the latest version of the vertex class.
Egamma_v1 Egamma
Definition of the current "egamma version".
Definition Egamma.h:17
static const EventInfo_v1::Accessor< std::vector< std::string > > types("streamTagTypes")
Muon_v1 Muon
Reference the current persistent version:
Definition Muon.h:13
setBGCode setTAP setLVL2ErrorBits bool
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
std::string toString(const SG::AuxElement &obj)
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.
static const SG::Accessor< ElementLink< IParticleContainer > > acc("originalObjectLink")
Object used for setting/getting the dynamic decoration in question.
#define likely(x)
For the flow elements we need a special derivate which also contains the weights.
std::vector< float > isolationValues
xAOD::Type::ObjectType type