ATLAS Offline Software
Loading...
Searching...
No Matches
IsolationCloseByCorrectionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4
12#include <xAODBase/ObjectType.h>
17
18#include "xAODEgamma/Egamma.h"
21
22namespace CP {
23 using namespace xAOD::Iso;
26 static const caloDecorNames names =
27 {"IsoCloseByCorr_assocClustEta", "IsoCloseByCorr_assocClustPhi", "IsoCloseByCorr_assocClustEnergy",
28 "IsoCloseByCorr_assocClustDecor"};
29 return names;
30 }
32 static const caloDecorNames names =
33 {"IsoCloseByCorr_assocPflowEta", "IsoCloseByCorr_assocPflowPhi", "IsoCloseByCorr_assocPflowEnergy",
34 "IsoCloseByCorr_assocPflowDecor"};
35 return names;
36 }
37 constexpr float MinClusterEnergy = 100.;
38 constexpr float MeVtoGeV = 1.e-3;
39
41
44 ATH_CHECK(m_selectorTool.retrieve());
48
52 if (!m_isoDecSuffix.empty()) ATH_MSG_INFO("IsoDecSuffix set to " << m_isoDecSuffix);
53 if (!m_quality_name.empty()) ATH_MSG_INFO("SelectionDecorator set to " << m_quality_name);
54
55
56#ifndef XAOD_ANALYSIS
61 ATH_CHECK(m_isoVarKeys.initialize());
62 ATH_CHECK(m_isoWriteDecVarKeys.initialize());
63 if (!m_caloExtTool.empty()) ATH_CHECK(m_caloExtTool.retrieve());
64 else {
65 ATH_MSG_WARNING("The ParticleCaloExtensionTool was not configured. Pleease include it!!!");
66 }
67#endif
68
69 ATH_CHECK(m_VtxKey.initialize());
72
73 // set default properties of track selection tool, if the user hasn't configured it
74 if (m_trkselTool.empty()) {
75 asg::AsgToolConfig config{"InDet::InDetTrackSelectionTool/TrackParticleSelectionTool"};
76 ATH_MSG_INFO("No TrackSelectionTool provided, so I will create and configure my own, called: " << config.name());
77 // The z0 cut is checked in any case either by the
78 // track to vertex association tool or by the tracking tool
79 ATH_CHECK(config.setProperty("maxZ0SinTheta", 3.));
80 // The minimum Pt requirement is lowered to 500 MeV because
81 // the Loose ttva cone variables accept very low-pt tracks
82 // https://gitlab.cern.ch/atlas/athena/blob/21.2/Reconstruction/RecoAlgs/IsolationAlgs/python/IsoUpdatedTrackCones.py#L21
83 ATH_CHECK(config.setProperty("minPt", 500.));
84 ATH_CHECK(config.setProperty("CutLevel", "Loose"));
85 ATH_CHECK(config.makePrivateTool(m_trkselTool));
86 }
88 if (m_ttvaTool.empty()) {
89 asg::AsgToolConfig config{"CP::TrackVertexAssociationTool/ttva_selection_tool"};
90 ATH_CHECK(config.setProperty("WorkingPoint", "Nonprompt_All_MaxWeight"));
91 ATH_CHECK(config.makePrivateTool(m_ttvaTool));
92 }
93 ATH_CHECK(m_trkselTool.retrieve());
94 ATH_CHECK(m_ttvaTool.retrieve());
95
96 if (!m_quality_name.empty()) m_acc_quality = std::make_unique<CharAccessor>(m_quality_name);
97 if (!m_passOR_name.empty()) m_acc_passOR = std::make_unique<CharAccessor>(m_passOR_name);
98 if (!m_isoSelection_name.empty()) m_dec_isoselection = std::make_unique<CharDecorator>(m_isoSelection_name);
99 m_isInitialised = true;
100 return StatusCode::SUCCESS;
101 }
102 void IsolationCloseByCorrectionTool::isoTypesFromWP(const std::vector<std::unique_ptr<IsolationWP>>& WPs, IsoVector& types) {
103 types.clear();
104 for (const std::unique_ptr<IsolationWP>& W : WPs) {
105 for (const std::unique_ptr<IsolationCondition>& C : W->conditions()) {
106 for (unsigned int t = 0; t < C->num_types(); ++t) {
107 const IsoType iso_type = C->type(t);
108 if (std::find(types.begin(), types.end(), iso_type) == types.end()) types.emplace_back(iso_type);
109 if (m_isohelpers.find(iso_type) == m_isohelpers.end()) {
110 m_isohelpers.insert(std::make_pair(iso_type, std::make_unique<IsoVariableHelper>(iso_type, m_backup_prefix, m_isoDecSuffix)));
111 }
112 }
113 }
114 }
115 m_has_nonTTVA |= std::find_if(types.begin(), types.end(),
116 [](const IsolationType& t) { return isTrackIso(t) && !isTrackIsoTTVA(t); }) != types.end();
117 m_hasPflowIso |= std::find_if(types.begin(), types.end(),
118 [](const IsolationType& t) { return isPFlowIso(t); }) != types.end();
119 m_hasEtConeIso |= std::find_if(types.begin(), types.end(),
120 [](const IsolationType& t) { return isTopoEtIso(t); }) != types.end();
121 }
122#ifndef XAOD_ANALYSIS
123 void IsolationCloseByCorrectionTool::declareDependency(const std::vector<std::string>& containers, const IsoVector& types) {
124 for (const std::string& cont : containers) {
125 for (const IsoType iso : types) {
126 // define read accessor iso variable keys
127 m_isoVarKeys.emplace_back(cont + "." + std::string(toString(iso)));
128 // define write decorator iso variable keys - needed for MT, but we do not use handles for writing the decorators in isoHelpers
129 m_isoWriteDecVarKeys.emplace_back(cont + "." + std::string(toString(iso) + (m_isoDecSuffix.empty() ? "" : "_") + m_isoDecSuffix));
130 }
133 for (const std::string& decor : pflowDecors()) m_isoVarKeys.emplace_back(cont + "." + decor);
134 }
136 for (const std::string& decor : caloDecors()) m_isoVarKeys.emplace_back(cont + "." + decor + m_caloDecSuffix);
137 }
138 }
139 }
140#endif
142 if (!container) return;
143 for (const xAOD::IParticle* particle : *container) {
144 if (m_dec_isoselection) (*m_dec_isoselection)(*particle) = true && m_selectorTool->accept(*particle);
145 const IsoVector& iso_types = getIsolationTypes(particle);
146 if (iso_types.empty()) { ATH_MSG_DEBUG("No isolation types have been defined for particle type " << particleName(particle)); }
147 for (const IsoType type : iso_types) {
148 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
149 IsoHelperMap::const_iterator Itr = m_isohelpers.find(type);
150 if (Itr == m_isohelpers.end() || Itr->second->backupIsolation(particle) == CorrectionCode::Error) {
151 ATH_MSG_WARNING("Failed to properly access the vanilla isolation variable "
152 << toString(type) << "for particle " << particleName(particle) << " with pT: "
153 << particle->pt() * MeVtoGeV << " GeV, eta: " << particle->eta() << ", phi: " << particle->phi());
154 }
155 }
156 // Save all particles to be sure to output the new iso decorated values
157 // They either pass or not the selection.
158 // The selected ones participate in the CloseBy and may have their isolation corrected.
159 if (!passSelectionQuality(particle)) {
160 cache.not_sel_parts.insert(particle);
161 }
162 else {
163 cache.prim_parts.insert(particle);
164 }
165 }
166 }
167 void IsolationCloseByCorrectionTool::loadAssociatedObjects(const EventContext& ctx, ObjectCache& cache) const {
168
169 // Use isLRT decoration for LLP particles to avoid looking for tracks from the primary vertex
170 static const CharAccessor isLRT("isLRT");
171
173 for (const xAOD::IParticle* prim : cache.prim_parts) {
174 // skip LRT leptons
175 if (!isLRT.isAvailable(*prim) || !isLRT(*prim) ) {
176 const TrackSet tracks = getAssociatedTracks(prim, cache.prim_vtx);
177 cache.tracks.insert(tracks.begin(), tracks.end());
178 }
179 const ClusterSet clusters = getAssociatedClusters(ctx, prim, cache);
180 cache.clusters.insert(clusters.begin(), clusters.end());
181 }
182 getAssocFlowElements(ctx, cache);
183 }
184 PflowSet IsolationCloseByCorrectionTool::getAssocFlowElements(const EventContext& ctx, const xAOD::IParticle* particle) const {
185 ObjectCache cache{};
186 cache.prim_parts = {particle};
187 loadAssociatedObjects(ctx, cache);
188 return cache.flows;
189 }
190
191 void IsolationCloseByCorrectionTool::getAssocFlowElements(const EventContext& ctx, ObjectCache& cache) const {
192 if (m_PflowKey.empty()) return;
194 if (!readHandle.isValid()) return;
195 std::set<const xAOD::IParticle*> tombola{};
196 for (const xAOD::IParticle* p : cache.prim_parts) tombola.insert(p);
197 for (const TrackPtr& p : cache.tracks) tombola.insert(p);
198 for (const CaloClusterPtr& p : cache.clusters) tombola.insert(p);
199
200 for (const xAOD::FlowElement* flow : *readHandle) {
201 if (!flow) continue;
202 for (size_t ch = 0; ch < flow->nChargedObjects(); ++ch) {
203 const xAOD::IParticle* obj = flow->chargedObject(ch);
204 if (tombola.count(obj)) {
205 const std::vector<float>& weights = flow->chargedObjectWeights();
206 cache.flows.emplace(flow, ch < weights.size() ? weights[ch] : 1.f);
207 }
208 }
209 for (size_t ne = 0; ne < flow->nOtherObjects(); ++ne) {
210 const xAOD::IParticle* obj = flow->otherObject(ne);
211 if (tombola.count(obj)) {
212 const std::vector<float>& weights = flow->otherObjectWeights();
213 cache.flows.emplace(flow, ne < weights.size() ? weights[ne] : 1.f);
214 ATH_MSG_VERBOSE("getAssocFlowElements: neflow " << ne << ", " << obj->type() << ", " << obj->pt() << ", " << obj->eta() << ", " << obj->phi() << ", " << flow->pt() << ", " << flow->eta() << ", " << flow->phi());
215 }
216 }
217 }
218 }
219
220 #ifndef XAOD_ANALYSIS
221 bool IsolationCloseByCorrectionTool::getExtrapEtaPhi(const EventContext& ctx, const xAOD::TrackParticle* tp, float& eta, float& phi) const {
223 ATH_MSG_DEBUG("Geting calo extension caloExtension tool.");
224 // If we have an extension cache then it owns the extension, otherwise we own it
225 // Therefore we have to prepare both an owning and a non-owning pointer
226 std::unique_ptr<Trk::CaloExtension> caloExtension;
227 caloExtension = m_caloExtTool->caloExtension(ctx, *tp);
228 if(!caloExtension){
229 ATH_MSG_WARNING("Can not get caloExtension.");
230 return false;
231 };
232
233 const std::vector<Trk::CurvilinearParameters>& intersections = caloExtension->caloLayerIntersections();
234 if(!intersections.empty()){
235 Amg::Vector3D avePoint(0,0,0);
236 for (unsigned int i = 0; i < intersections.size(); ++i){
237 const Amg::Vector3D& point = intersections[i].position();
238 avePoint += point;
239 }
240 avePoint = (1./intersections.size())*avePoint;
241 eta = avePoint.eta();
242 phi = avePoint.phi();
243 return true;
244 } else {
245 ATH_MSG_WARNING("Muon Calo extension got no intersection!!!");
246 }
248 ATH_MSG_WARNING("Calo extension can not be obtained!!!");
249 return false;
250 }
251 #endif // xAOD
252
254 const EventContext& ctx,
255 const xAOD::ElectronContainer* electrons,
256 const xAOD::MuonContainer* muons,
257 const xAOD::PhotonContainer* photons) const {
258 if (!m_isInitialised) {
259 ATH_MSG_ERROR("The IsolationCloseByCorrectionTool was not initialised!!!");
261 }
262 ObjectCache cache{};
264 loadPrimaryParticles(electrons, cache);
265 loadPrimaryParticles(muons, cache);
266 loadPrimaryParticles(photons, cache);
267
268 loadAssociatedObjects(ctx, cache);
273 return ret;
274 }
276 if (cache.prim_vtx) {
277 // 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
278 for (const xAOD::IParticle* particle : cache.prim_parts) {
279 ATH_MSG_DEBUG("Correct the isolation of particle "<<particleName(particle)<< " with pt: " << particle->pt() * MeVtoGeV << " GeV"
280 << " eta: " << particle->eta()
281 << " phi: " << particle->phi());
282
283 if (subtractCloseByContribution(ctx, particle, cache) == CorrectionCode::Error) {
284 ATH_MSG_ERROR("Failed to correct the isolation of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
285 << " eta: " << particle->eta()
286 << " phi: " << particle->phi());
288 }
289 if (m_dec_isoselection) (*m_dec_isoselection)(*particle) = bool(m_selectorTool->accept(*particle));
290 ATH_MSG_DEBUG("Corrected the isolation of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
291 << " eta: " << particle->eta()
292 << " phi: " << particle->phi());
293
294 }
295 }
296 else {
297 // Missing primary vertex - need to copy the uncorrected iso values
298 for (const xAOD::IParticle* particle : cache.prim_parts) {
299 ATH_MSG_DEBUG("Copy isolation values of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
300 << " eta: " << particle->eta()
301 << " phi: " << particle->phi());
303 ATH_MSG_ERROR("Failed to copy the isolation of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
304 << " eta: " << particle->eta()
305 << " phi: " << particle->phi());
307 }
308 }
309 }
310 // Only need to copy the uncorrected iso values
311 for (const xAOD::IParticle* particle : cache.not_sel_parts) {
312 ATH_MSG_DEBUG("Copy isolation values of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
313 << " eta: " << particle->eta()
314 << " phi: " << particle->phi());
316 ATH_MSG_ERROR("Failed to copy the isolation of particle with pt: " << particle->pt() * MeVtoGeV << " GeV"
317 << " eta: " << particle->eta()
318 << " phi: " << particle->phi());
320 }
321 }
322 return CorrectionCode::Ok;
323 }
325 const IsoVector& isoTypes) const {
326 if (!parts) return;
327
330 const CharDecorator dec_isDecor{caloDecors()[3] + m_caloDecSuffix};
331
332 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
333
334 if (parts->ownPolicy() == SG::VIEW_ELEMENTS) {
336 for (const xAOD::IParticle* part : *parts) {
337 const SG::AuxVectorData* c = part->container();
338 if (conts.insert(c).second) {
339 for (const IsoType t : isoTypes) {
340 auto it = m_isohelpers.find (t);
341 if (it != m_isohelpers.end())
342 it->second->lockDecorations(*part->container());
343 }
345 const_cast<SG::AuxVectorData*> (c);
346 c_nc->lockDecoration (dec_assocEta.auxid());
347 c_nc->lockDecoration (dec_assocPhi.auxid());
348 c_nc->lockDecoration (dec_isDecor.auxid());
349 }
350 }
351 }
352
353 else {
354 for (const IsoType t : isoTypes) {
355 auto it = m_isohelpers.find (t);
356 if (it != m_isohelpers.end())
357 it->second->lockDecorations(*parts);
358 }
360 const_cast<xAOD::IParticleContainer*> (parts);
361 c_nc->lockDecoration (dec_assocEta.auxid());
362 c_nc->lockDecoration (dec_assocPhi.auxid());
363 c_nc->lockDecoration (dec_isDecor.auxid());
364 }
365 }
367 static const IsoVector dummy{};
368 if (!particle) return dummy;
369 if (particle->type() == xAOD::Type::ObjectType::Electron)
370 return m_electron_isoTypes;
371 else if (particle->type() == xAOD::Type::ObjectType::Muon)
372 return m_muon_isoTypes;
373 else if (particle->type() == xAOD::Type::ObjectType::Photon)
374 return m_photon_isoTypes;
375 return dummy;
376 }
377
379 const xAOD::IParticle* par,
380 ObjectCache& cache) const {
381 const IsoVector& types = getIsolationTypes(par);
382 if (types.empty()) {
383 ATH_MSG_WARNING("No isolation types are defiend for " << particleName(par));
385 }
386 for (const IsolationType iso_type : types) {
387 float iso_variable{0.f};
388 if (isTrackIso(iso_type)) {
389 if (getCloseByCorrectionTrackIso(par, iso_type, cache, iso_variable) == CorrectionCode::Error) {
390 ATH_MSG_ERROR("Failed to apply track correction");
392 }
393 } else if (isTopoEtIso(iso_type)) {
394 if (getCloseByCorrectionTopoIso(ctx, par, iso_type, cache, iso_variable) == CorrectionCode::Error) {
395 ATH_MSG_ERROR("Failed to apply topo cluster correction");
397 }
398 } else if (isPFlowIso(iso_type)) {
399 if (getCloseByCorrectionPflowIso(ctx, par, iso_type, cache, iso_variable) == CorrectionCode::Error) {
400 ATH_MSG_ERROR("Failed to apply pflow correction");
402 }
403 }
404 ATH_MSG_DEBUG("subtractCloseByContribution: Set pt, eta, phi " << par->pt() << ", " << par->eta() << ", " << par->phi() << " for " << toString(iso_type) << " to " << iso_variable);
405 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
406 if (m_isohelpers.at(iso_type)->setIsolation(par, iso_variable) == CorrectionCode::Error) {
407 ATH_MSG_ERROR("Cannot set " << toString(iso_type) << " to " << iso_variable);
408 return CorrectionCode::Error;
409 }
410 }
411 return CorrectionCode::Ok;
412 }
413
415 const IsoVector& types = getIsolationTypes(part);
416
417 ATH_MSG_DEBUG("copyIsoValuesForPartsNotSelected " << part->type() << " " << part->pt() * MeVtoGeV << " GeV" << " eta: " << part->eta() << " phi: " << part->phi());
418
419 if (types.empty()) {
420 ATH_MSG_WARNING("No isolation types are defiend for " << particleName(part));
422 }
423 for (const IsolationType iso_type : types) {
424 float iso_variable{0.f};
425 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
426 if (m_isohelpers.at(iso_type)->getIsolation(part, iso_variable) == CorrectionCode::Error) {
427 ATH_MSG_ERROR("Cannot get value for " << toString(iso_type));
428 return CorrectionCode::Error;
429 }
430 ATH_MSG_DEBUG("copyIsoValuesForPartsNotSelected: Set pt, eta " << part->pt() << ", " << part->eta() << ", " << part->phi() << " for " << toString(iso_type) << " to " << iso_variable);
431 if (m_isohelpers.at(iso_type)->setIsolation(part, iso_variable) == CorrectionCode::Error) {
432 ATH_MSG_ERROR("Cannot set " << toString(iso_type) << " to " << iso_variable);
433 return CorrectionCode::Error;
434 }
435 }
436 return CorrectionCode::Ok;
437 }
438
439
441 const std::vector<IsolationType>& types,
442 const xAOD::IParticleContainer& closePar) const {
443
444 if (!m_isInitialised) {
445 ATH_MSG_ERROR("The IsolationCloseByCorrectionTool was not initialised!!!");
447 }
449 {
450 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
451 for (const IsolationType& t : types) {
452 IsoHelperMap::const_iterator Itr = m_isohelpers.find(t);
453 if (Itr != m_isohelpers.end()) { continue; }
454 Itr = m_isohelpers.insert(std::make_pair(t, std::make_unique<IsoVariableHelper>(t, m_backup_prefix, m_isoDecSuffix))).first;
455 }
456 }
457 corrections.assign(types.size(), 0);
458 ObjectCache cache{};
459 loadPrimaryParticles(&closePar, cache);
460 const EventContext& ctx = Gaudi::Hive::currentContext();
461 loadAssociatedObjects(ctx, cache);
462 std::vector<float>::iterator Cone = corrections.begin();
463 for (const IsolationType& iso_type : types) {
464 {
465 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
466 IsoHelperMap::const_iterator Itr = m_isohelpers.find(iso_type);
467 if (Itr->second->backupIsolation(&par) == CP::CorrectionCode::Error) {
468 ATH_MSG_ERROR("Failed to backup isolation");
470 }
471 }
472 if (isTrackIso(iso_type)) {
473 if (getCloseByCorrectionTrackIso(&par, iso_type, cache, (*Cone)) == CorrectionCode::Error) {
474 ATH_MSG_ERROR("Failed to apply track correction");
476
477 }
478 }
479 else if (isTopoEtIso(iso_type)) {
480 if (getCloseByCorrectionTopoIso(ctx, &par, iso_type, cache, (*Cone)) == CorrectionCode::Error) {
481 ATH_MSG_ERROR("Failed to apply topo cluster correction");
483 }
484 }
485 else if (isPFlowIso(iso_type)) {
486 if (getCloseByCorrectionPflowIso(ctx, &par, iso_type, cache, (*Cone)) == CorrectionCode::Error) {
487 ATH_MSG_ERROR("Failed to apply pflow correction");
489 }
490 }
491 ++Cone;
492 }
493 return CorrectionCode::Ok;
494 }
495 // check for non-zero primary vtx - single particle samples don't have one
497 return trk && vtx && m_trkselTool->accept(*trk, vtx) && (!m_has_nonTTVA || m_ttvaTool->isCompatible(*trk, *vtx));
498 }
500 TrackSet to_return{};
501 if (P->type() == xAOD::Type::Muon) {
502 const xAOD::Muon* mu = static_cast<const xAOD::Muon*>(P);
503 if (mu->muonType() != xAOD::Muon::SiliconAssociatedForwardMuon)
504 to_return.emplace(mu->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle));
505 } else if (P->type() == xAOD::Type::TrackParticle) {
506 const xAOD::TrackParticle* trk = static_cast<const xAOD::TrackParticle*>(P);
507 to_return.emplace(trk);
508 } else if (isEgamma(P)) {
509 const xAOD::Egamma* EG = static_cast<const xAOD::Egamma*>(P);
510 std::set<const xAOD::TrackParticle*> trk_vec = xAOD::EgammaHelpers::getTrackParticles(EG, true, true);
511 for (const xAOD::TrackParticle* trk : trk_vec) {
512 ATH_MSG_VERBOSE("Adding egamma track with "
513 << trk->pt() * MeVtoGeV << " GeV, eta: " << trk->eta() << ", phi: " << trk->phi());
514 to_return.emplace(trk);
515 }
516 }
517 return to_return;
518 }
520 const TrackSet assoc_tracks = getAssociatedTracks(P);
521 TrackSet to_ret{};
522 for (const TrackPtr trk : assoc_tracks) {
523 if (passFirstStage(trk, vtx)) to_ret.insert(trk);
524 }
525 return to_ret;
526 }
527 TrackSet IsolationCloseByCorrectionTool::getTrackCandidates(const EventContext& ctx, const xAOD::IParticle* particle) const {
529 }
533
534 // Collect topoclusters for electron, photon and muons
535 // - for electrons and photons, collect the associated clusters
536 // - for muons, use associated cluster, if it exists, to get topocluster, otherwise, extrapolate the InDet trackParticle to calo
537 // and look for topoclusters matching in dR the core muon cone
539 ObjectCache& cache) const {
540 // Remember topoclusters which are associated to an egamma object, electron or photon
541 // This will be used to avoid associating the same object to a muon
542 ClusterSet clusters;
543 if (isEgamma(P)) {
544 const xAOD::Egamma* egamm = static_cast<const xAOD::Egamma*>(P);
545 for (size_t calo = 0; calo < egamm->nCaloClusters(); ++calo) {
546 const xAOD::CaloCluster* clust = egamm->caloCluster(calo);
547 if (!clust) continue;
548 std::vector<const xAOD::CaloCluster*> constituents = xAOD::EgammaHelpers::getAssociatedTopoClusters(clust);
549 for (const xAOD::CaloCluster* cluster : constituents) {
550 if (cluster && std::abs(cluster->eta()) < 7. && cluster->e() > MinClusterEnergy) {
551 clusters.emplace(cluster);
552 cache.eg_associated_clusters.insert(cluster); // set flag that this cluster is associated to an electron or photon
553 ATH_MSG_VERBOSE("getAssociatedClusters: " << P->type() << " has topo cluster with pt: " << cluster->pt() * MeVtoGeV << " GeV, eta: "
554 << cluster->eta() << ", phi: " << cluster->phi());
555 }
556 }
557 }
558 if (clusters.size()) return clusters;
559 }
560 if (m_CaloClusterKey.empty()) return clusters;
562 if (!topoClusters.isValid()) return clusters;
563
564 if (P->type() == xAOD::Type::ObjectType::Muon) {
565 const xAOD::Muon* mu = static_cast<const xAOD::Muon*>(P);
566 const xAOD::CaloCluster* cl = mu->cluster();
567 bool foundMuonTopo = false;
568 if (cl) {
569 ATH_MSG_VERBOSE("getAssociatedClusters: muon has cluster with pt: " << cl->pt() * MeVtoGeV << " GeV, eta: "
570 << cl->eta() << ", phi: " << cl->phi());
571 std::vector<const xAOD::CaloCluster*> constituents = xAOD::EgammaHelpers::getAssociatedTopoClusters(cl);
572 for (const xAOD::CaloCluster* cluster : constituents) {
573 if (cluster && std::abs(cluster->eta()) < 7. && cluster->e() > MinClusterEnergy) {
574 // skip association if this cluster is already associated with an electron or photon - priority is given to egamma reco
575 if (!cache.eg_associated_clusters.contains(cluster)) {
576 clusters.emplace(cluster);
577 foundMuonTopo = true;
578 ATH_MSG_VERBOSE("getAssociatedClusters: muon has topo cluster with pt: " << cluster->pt() * MeVtoGeV << " GeV, eta: "
579 << cluster->eta() << ", phi: " << cluster->phi());
580 }
581 else {
582 ATH_MSG_VERBOSE("getAssociatedClusters: muon topo cluster already associated with an EG objet - cluster with pt: "
583 << cluster->pt() * MeVtoGeV << " GeV, eta: " << cluster->eta() << ", phi: " << cluster->phi());
584 }
585 }
586 }
587 }
588 if (!foundMuonTopo) {
589#ifndef XAOD_ANALYSIS
590 // extraploate muon to calo and look for matching topo cluster
591 const xAOD::TrackParticle* tp = mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
592 if (tp) {
593 ATH_MSG_VERBOSE("getAssociatedClusters: found mu tp " << " with pt: " << tp->pt() * MeVtoGeV << " GeV, eta: " << tp->eta() << ", phi: " << tp->phi());
594 float tpEtaAtCalo;
595 float tpPhiAtCalo;
596 if (getExtrapEtaPhi(ctx, tp, tpEtaAtCalo, tpPhiAtCalo)) {
597 ATH_MSG_VERBOSE("getAssociatedClusters: tp extrapolated - tpEtaAtCalo " << tpEtaAtCalo << ", tpPhiAtCalo " << tpPhiAtCalo);
598 for (const xAOD::CaloCluster* cluster : *topoClusters) {
599 if (cluster && std::abs(cluster->eta()) < 7. && cluster->e() > MinClusterEnergy &&
600 xAOD::P4Helpers::deltaR(tpEtaAtCalo, tpPhiAtCalo, cluster->eta(), cluster->phi()) < m_coreConeMu) {
601 clusters.emplace(cluster);
602 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);
603 }
604 }
605 }
606 }
607#endif
608 }
609 }
610
611 return clusters;
612 }
614 if (!P) return false;
615 if (m_acc_quality && (!m_acc_quality->isAvailable(*P) || !(*m_acc_quality)(*P))) return false;
616 if (m_acc_passOR && (!m_acc_passOR->isAvailable(*P) || !(*m_acc_passOR)(*P))) return false;
617 return true;
618 }
620 const ObjectCache& cache, float& isoValue) const {
621 if (!isTrackIso(type)) {
622 ATH_MSG_ERROR("Invalid isolation type " << toString(type));
624 }
625 {
626 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
627 IsoHelperMap::const_iterator Itr = m_isohelpers.find(type);
628 if (Itr == m_isohelpers.end() || Itr->second->getOriginalIsolation(par, isoValue) == CorrectionCode::Error) {
629 ATH_MSG_WARNING(__func__<<"() -- "<<__LINE__<<" Could not retrieve the isolation variable " << toString(type));
631 } else if (cache.tracks.empty())
632 return CorrectionCode::Ok;
633 }
634
635 float MaxDR = coneSize(par, type);
636 const TrackSet ToExclude = getAssociatedTracks(par);
637
638 const xAOD::IParticle* Ref = isoRefParticle(par);
639 ATH_MSG_VERBOSE(toString(type) << " of " << particleName(par) << " with pt: " << par->pt() * MeVtoGeV << " GeV, eta: " << par->eta()
640 << ", phi: " << par->phi() << " before correction: " << isoValue * MeVtoGeV << " GeV. "
641 << ToExclude.size() << " tracks will be excluded.");
642
643 for (const TrackPtr& poluting_trk : cache.tracks) {
644 // Checks for the Pile-up robust isolation WP's
645 if (poluting_trk->pt() < trackPtCut(type)) continue;
647 if (isTrackIsoTTVA(type) && m_has_nonTTVA && !m_ttvaTool->isCompatible(*poluting_trk, *cache.prim_vtx)) continue;
648
649 if (overlap(Ref, poluting_trk, MaxDR) && !ToExclude.count(poluting_trk)) {
650 ATH_MSG_VERBOSE("Subtract track with "
651 << poluting_trk->pt() * MeVtoGeV << " GeV, eta: " << poluting_trk->eta() << ", phi: " << poluting_trk->phi()
652 << " with dR: " << std::sqrt(deltaR2(Ref, poluting_trk)) << " from the isolation cone " << toString(type)
653 << " " << (isoValue * MeVtoGeV) << " GeV.");
654 isoValue -= poluting_trk->pt();
655 }
656 }
657 isoValue = std::max(0.f, isoValue);
658 ATH_MSG_VERBOSE(toString(type) << " of " << particleName(par) << " with pt: " << par->pt() * MeVtoGeV << " GeV, eta: " << par->eta()
659 << ", phi: " << par->phi() << " after correction: " << isoValue * MeVtoGeV << " GeV");
660 return CorrectionCode::Ok;
661 }
663 const IsoType type, const ObjectCache& cache,
664 float& isoValue) const {
665 if (!isPFlowIso(type)) {
666 ATH_MSG_ERROR("getCloseByCorrectionPflowIso() -- The isolation type is not a Pflow variable " << toString(type));
668 }
669 if (m_isohelpers.at(type)->getOriginalIsolation(primary, isoValue) == CorrectionCode::Error) {
670 ATH_MSG_ERROR("getCloseByCorrectionPflowIso() -- Could not retrieve the isolation variable.");
672 }
674 if (isoValue <= 0.) {
675 ATH_MSG_DEBUG("Pflow varible is already sufficiently isolated ");
676 return CorrectionCode::Ok;
677 }
678 const float coneDR = coneSize(primary, type);
679 float ref_eta{0.f}, ref_phi{0.f};
680 getExtrapEtaPhi(primary, ref_eta, ref_phi);
683 ATH_MSG_VERBOSE("getCloseByCorrectionPflowIso: " << toString(type) << " of " << particleName(primary) << " with pt: "
684 << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
685 << ", phi: " << primary->phi() << " before correction: " << isoValue * MeVtoGeV << " GeV. ");
686 PflowSet assoc_coll = getAssocFlowElements(ctx, primary);
687 for (const FlowElementPtr& flow : cache.flows) {
688 ATH_MSG_VERBOSE("Loop over pflow element: " << flow->pt() << " GeV, eta: " << flow->eta() << " phi: " << flow->phi());
689
690 const float dR = xAOD::P4Helpers::deltaR(ref_eta,ref_phi, flow->eta(),flow->phi());
691 if(dR < (primary->type() == xAOD::Type::ObjectType::Muon ? m_coreConeMu : m_coreConeEl)) {
692 ATH_MSG_VERBOSE("Flow element is in core cone");
693 continue;
694 }
695 if (assoc_coll.count(flow)) {
696 ATH_MSG_VERBOSE("Flow element is directly associated with the object");
697 continue;
698 }
699 if (dR < coneDR) {
700 ATH_MSG_VERBOSE("Found overlapping pflow element: " << flow->pt() << " GeV, eta: " << flow->eta()
701 << " phi: " << flow->phi() << " dR: " << dR);
702 isoValue -= flow->pt() * flow.weight;
703 }
704 }
705 ATH_MSG_VERBOSE("getCloseByCorrectionPflowIso: " << toString(type) << " of " << particleName(primary) << " with pt: "
706 << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
707 << ", phi: " << primary->phi() << " after correction: " << isoValue * MeVtoGeV << " GeV. ");
709 static const FloatAccessor acc_eta{pflowDecors()[0]};
710 static const FloatAccessor acc_phi{pflowDecors()[1]};
711 static const FloatAccessor acc_ene{pflowDecors()[2]};
712 static const CharAccessor acc_isDecor{pflowDecors()[3]};
713 for (const xAOD::IParticle* others : cache.prim_parts) {
714 if (others == primary) continue;
715 if (!acc_isDecor.isAvailable(*others) || !acc_isDecor(*others)) {
716 ATH_MSG_ERROR("The variable energy averaged pflow decorations are not available for "<<particleName(others)<<". Please check");
718 }
719 const float other_eta = acc_eta(*others);
720 const float other_phi = acc_phi(*others);
721 const float dR = xAOD::P4Helpers::deltaR(ref_eta,ref_phi,other_eta,other_phi);
722 if (dR > coneDR) continue;
723 if (dR< (primary->type() == xAOD::Type::ObjectType::Muon ? m_coreConeMu : m_coreConeEl)) continue;
724 isoValue -= acc_ene(*others);
725 }
726 } else {
727 ATH_MSG_ERROR("Unknown calo correction model "<<m_caloModel);
729 }
730 isoValue = std::max(0.f, isoValue);
731 return CorrectionCode::Ok;
732 }
733
735 const IsoType type, ObjectCache& cache,
736 float& isoValue) const {
737 // check if the isolation can be loaded
738 if (!isTopoEtIso(type)) {
739 ATH_MSG_ERROR("getCloseByCorrectionTopoIso() -- The isolation type is not an et cone variable " << toString(type));
741 }
742 {
743 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
744 if (m_isohelpers.at(type)->getOriginalIsolation(primary, isoValue) == CorrectionCode::Error) {
745 ATH_MSG_WARNING("Could not retrieve the isolation variable.");
747 }
748 }
750 if (isoValue <= 0.) {
751 ATH_MSG_DEBUG("Topo et cone variable is already sufficiently isolated");
752 return CorrectionCode::Ok;
753 }
754 float ref_eta{0.f}, ref_phi{0.f};
755 getExtrapEtaPhi(primary, ref_eta, ref_phi);
756 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: " << toString(type) << " of " << particleName(primary) << " with ref eta: " << ref_eta << ", ref phi " << ref_phi);
757
758 float MaxDR = coneSize(primary, type) * (primary->type() != xAOD::Type::ObjectType::Muon ? 1. : m_ConeSizeVariation.value());
760 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: " << toString(type) << " of " << particleName(primary) << " with pt: "
761 << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
762 << ", phi: " << primary->phi() << " before correction: " << isoValue * MeVtoGeV << " GeV. ");
763 ClusterSet assoc = getAssociatedClusters(ctx, primary, cache);
764 for (const CaloClusterPtr& calo : cache.clusters) {
765 const float dR = xAOD::P4Helpers::deltaR(ref_eta, ref_phi, calo->eta(), calo->phi());
766 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: Loop over cluster: " << calo->pt() * MeVtoGeV << " GeV, eta: " << calo->eta() << " phi: " << calo->phi() << " dR: " << dR);
767 if (dR > MaxDR) continue;
768 // REMOVED CORE CUT SINCE TOPOCLUSTERS SHOULD BE ASSOCIATED TO THE ELECTRONS AND MUONS AND WILL BE CUT BY ASSOC CUT BELOW
769 if (assoc.count(calo)) {
770 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: skip due to assoc " << assoc.count(calo));
771 continue;
772 }
773 float Polution = clusterEtMinusTile(calo) / (isoValue != 0 ? isoValue : 1.);
774 if (Polution < 0. || Polution > m_maxTopoPolution) {
775 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: skip due to polution " << Polution << ", clus noTile " << clusterEtMinusTile(calo) * MeVtoGeV << " GeV");
776 continue;
777 }
778 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: Found overlapping topocluster: " << calo->pt() * MeVtoGeV << " GeV, lessTile " << clusterEtMinusTile(calo) * MeVtoGeV << " GeV, eta: " << calo->eta()
779 << " phi: " << calo->phi() << " dR: " << dR);
780 isoValue -= clusterEtMinusTile(calo);
781 }
782 ATH_MSG_VERBOSE("getCloseByCorrectionTopoIso: " << toString(type) << " of " << particleName(primary) << " with pt: "
783 << primary->pt() * MeVtoGeV << " GeV, eta: " << primary->eta()
784 << ", phi: " << primary->phi() << " after correction: " << isoValue * MeVtoGeV << " GeV. ");
786 const FloatAccessor acc_eta{caloDecors()[0] + m_caloDecSuffix};
787 const FloatAccessor acc_phi{caloDecors()[1] + m_caloDecSuffix};
788 const FloatAccessor acc_ene{caloDecors()[2] + m_caloDecSuffix};
789 const CharAccessor acc_isDecor{caloDecors()[3] + m_caloDecSuffix};
790 for (const xAOD::IParticle* others : cache.prim_parts) {
791 if (others == primary) continue;
792 if (!acc_isDecor.isAvailable(*others) || !acc_isDecor(*others)) {
793 ATH_MSG_ERROR("The averaged calo cluster decorations are not available for "<<particleName(others)<<". Please check");
795 }
796 const float other_eta = acc_eta(*others);
797 const float other_phi = acc_phi(*others);
798 const float dR = xAOD::P4Helpers::deltaR(ref_eta,ref_phi,other_eta,other_phi);
799 if (dR > MaxDR) continue;
800 if (dR< (primary->type() == xAOD::Type::ObjectType::Muon ? m_coreConeMu : m_coreConeEl)) continue;
801 isoValue -= acc_ene(*others);
802 }
803 }
804 isoValue = std::max(0.f, isoValue);
805 return CorrectionCode::Ok;
806 }
810 const CharAccessor acc_isDecor{caloDecors()[3] + m_caloDecSuffix};
811 if (par->type() != xAOD::Type::ObjectType::Muon) {
812 const xAOD::Egamma* egam = dynamic_cast<const xAOD::Egamma*>(par);
813 if( egam ) {
814 eta = egam->caloCluster()->eta();
815 phi = egam->caloCluster()->phi();
816 }
817 else {
818 eta = par->eta();
819 phi = par->phi();
820 }
821 } else if (acc_isDecor.isAvailable(*par) && acc_isDecor(*par)) {
822 eta = acc_assocEta(*par);
823 phi = acc_assocPhi(*par);
824 } else {
825 float assoc_ene{0.f};
828 const CharDecorator dec_isDecor{caloDecors()[3] + m_caloDecSuffix};
829 associateCluster(par,eta, phi, assoc_ene);
830 dec_assocEta(*par) = eta;
831 dec_assocPhi(*par) = phi;
832 dec_isDecor(*par) = true;
833 }
834 }
835 void IsolationCloseByCorrectionTool::associateFlowElement(const EventContext& ctx, const xAOD::IParticle* particle, float& eta,
836 float& phi, float& energy) const {
837 phi = eta = energy = 0.;
838 PflowSet flowCollection = getAssocFlowElements(ctx, particle);
839 if (flowCollection.empty()) {
840 phi = particle->phi();
841 eta = particle->eta();
842 return;
843 }
844 for (const FlowElementPtr& ele : flowCollection) {
845 const float flow_energy = ele->e() * ele.weight;
846 if (flow_energy < MinClusterEnergy) continue;
847 phi += ele->phi() * flow_energy;
848 eta += ele->eta() * flow_energy;
849 energy += flow_energy;
850 }
851 if (energy < MinClusterEnergy) {
852 phi = particle->phi();
853 eta = particle->eta();
854 return;
855 }
856 phi = xAOD::P4Helpers::deltaPhi(phi / energy, 0.);
857 eta /= energy;
858 }
859 void IsolationCloseByCorrectionTool::associateCluster(const xAOD::IParticle* particle, float& eta, float& phi, float& energy) const {
860 phi = particle->phi();
861 eta = particle->eta();
862 energy = -1.;
863 if (particle->type() == xAOD::Type::ObjectType::Muon) {
864 const xAOD::Muon* mu = static_cast<const xAOD::Muon*>(particle);
865 const xAOD::CaloCluster* cluster = mu->cluster();
866 if (!cluster) return;
867 energy = cluster->e();
868 // At the moment no cluster associated with muons is in the derivations
869 int nSample{0};
870 float etaT{0.f}, phiT{0.f}, dphiT{0.f};
871
872 for (unsigned int i = 0; i < CaloSampling::Unknown; ++i) {
874 if (cluster->hasSampling(s)) {
875 ATH_MSG_VERBOSE("Sampling: " << i << "eta-phi (" << cluster->etaSample(s) << ", " << cluster->phiSample(s) << ")");
876 etaT += cluster->etaSample(s);
877 if (!nSample)
878 phiT = cluster->phiSample(s);
879 else
880 dphiT += xAOD::P4Helpers::deltaPhi(cluster->phiSample(s), phiT);
881 ++nSample;
882 }
883 }
884 if (!nSample) return;
885 ATH_MSG_DEBUG("Eta, phi before sampling: " << eta << ", " << phi << " and after sampling: " << etaT / nSample << ", "
886 << phiT / nSample);
887 phi = xAOD::P4Helpers::deltaPhi(phiT + dphiT / nSample, 0);
888 eta = etaT / nSample;
889 ATH_MSG_VERBOSE("associateCluster: mu with pt: " << mu->pt() * MeVtoGeV << " GeV, eta: "
890 << mu->eta() << ", phi: " << mu->phi() << " energy, eta, phi " << energy << ", " << eta << ", " << phi
891 << ", et " << energy * mu->pt() / mu->e());
892 }
893 if (!isEgamma(particle)) return;
894 const xAOD::Egamma* egamm = static_cast<const xAOD::Egamma*>(particle);
895 eta = phi = energy = 0.;
896 for (unsigned int cl = 0; cl < egamm->nCaloClusters(); ++cl) {
897 const xAOD::CaloCluster* prim_cluster = egamm->caloCluster(cl);
898 if (!prim_cluster) {
899 ATH_MSG_DEBUG("Cluster " << cl << " is not defined " << egamm);
900 continue;
901 }
902 std::vector<const xAOD::CaloCluster*> constituents = xAOD::EgammaHelpers::getAssociatedTopoClusters(prim_cluster);
903 for (const xAOD::CaloCluster* cluster : constituents) {
904 if (!cluster) continue;
905 const float clus_e = clusterEtMinusTile(cluster);
907 if (clus_e < MinClusterEnergy) continue;
908 eta += cluster->eta() * clus_e;
909 phi += cluster->phi() * clus_e;
910 energy += clus_e;
911 ATH_MSG_VERBOSE("associateCluster: eg add in clus with e: " << clus_e * MeVtoGeV << " clus et " << cluster->pt() * MeVtoGeV << " GeV, eta: "
912 << cluster->eta() << ", phi: " << cluster->phi());
913 }
914 }
915 if (energy >= MinClusterEnergy) {
916 phi = xAOD::P4Helpers::deltaPhi(phi / energy, 0.);
917 eta /= energy;
918 ATH_MSG_VERBOSE("associateCluster: eg with pt: " << egamm->pt() * MeVtoGeV << " GeV, eta: "
919 << egamm->eta() << ", phi: " << egamm->phi() << " energy, eta, phi " << energy << ", " << eta << ", " << phi );
920 } else {
921 ATH_MSG_DEBUG("Average energy from the clusters is too low " << energy << " copy particle properties");
922 eta = egamm->eta();
923 phi = egamm->phi();
924 energy = egamm->e();
925 }
926 }
928 const xAOD::IParticleContainer& closePar) const {
929 if (!m_isInitialised) { ATH_MSG_WARNING("The IsolationCloseByCorrectionTool was not initialised!!!"); }
930 assert(!m_selectorTool.empty());
931 const IsoVector& iso_types = getIsolationTypes(&x);
932 if (iso_types.empty()) {
933 // TODO: figure out if this is actually a valid situation
934 // or if we should just fail at this point.
935 ATH_MSG_WARNING("Could not cast particle for acceptCorrected. Will return false.");
936 static const asg::AcceptInfo dummyAcceptInfo = []() {
937 asg::AcceptInfo info;
938 info.addCut("castCut", "whether we managed to cast to a known type");
939 return info;
940 }();
941 if (m_dec_isoselection) (*m_dec_isoselection)(x) = false;
942 return asg::AcceptData(&dummyAcceptInfo);
943 }
944
945 if (closePar.empty()) return m_selectorTool->accept(x);
946 strObj strPar;
947 strPar.isolationValues.resize(numIsolationTypes);
948 strPar.pt = x.pt();
949 strPar.eta = x.eta();
950 strPar.type = x.type();
951 std::vector<float> corrections;
952 if (getCloseByCorrection(corrections, x, iso_types, closePar) == CorrectionCode::Error) {
953 ATH_MSG_WARNING("Could not calculate the corrections. acceptCorrected(x) is done without the corrections.");
954 if (m_dec_isoselection) (*m_dec_isoselection)(x) = bool(m_selectorTool->accept(x));
955 return m_selectorTool->accept(x);
956 }
957 for (unsigned int i = 0; i < iso_types.size(); ++i) {
958 strPar.isolationValues[iso_types[i]] = corrections[i];
960 float old = (*acc)(x);
961 ATH_MSG_DEBUG("Correcting " << toString(iso_types.at(i)) << " from " << old << " to " << corrections[i]);
962 }
963 auto accept = m_selectorTool->accept(strPar);
964 if (m_dec_isoselection) (*m_dec_isoselection)(x) = bool(accept);
965 return accept;
966 }
969 if (!Verticies.isValid() || !Verticies->size()) {
970 ATH_MSG_WARNING("Failed to load vertex collection " << m_VtxKey.key());
971 return nullptr;
972 }
973 for (const xAOD::Vertex* V : *Verticies) {
974 if (V->vertexType() == xAOD::VxType::VertexType::PriVtx) {
975 ATH_MSG_VERBOSE("retrieveIDBestPrimaryVertex: vertex found ");
976 return V;
977 }
978 }
979 ATH_MSG_VERBOSE("retrieveIDBestPrimaryVertex: no vertex found ");
980 return nullptr;
981 }
982
985 float ConeDR = coneSize(Cone);
987 const xAOD::IParticle* Reference = isoRefParticle(P);
988 float MiniIso = m_ptvarconeRadius / unCalibPt(Reference);
989 if (MiniIso < ConeDR) return MiniIso;
990 }
991 return ConeDR;
992 }
994 if (!P) {
995 ATH_MSG_WARNING("No partcile given. Return stupidly big number. ");
996 return 1.e25;
997 }
999 if (!OR) {
1000 ATH_MSG_VERBOSE("No reference from the shallow copy container of " << particleName(P) << " could be found");
1001 return P->pt();
1002 }
1003 return OR->pt();
1004 }
1005
1007 if (!P) {
1008 ATH_MSG_ERROR("Nullptr given");
1009 return nullptr;
1010 }
1011 // Use for muons the associated ID track. Else the particle itself
1012 if (P->type() == xAOD::Type::ObjectType::Muon) {
1013 const xAOD::Muon* muon = static_cast<const xAOD::Muon*>(P);
1014 const xAOD::TrackParticle* idTrk = muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
1015 return idTrk ? idTrk : muon->primaryTrackParticle();
1016 }
1017 return P;
1018 }
1020 if (!P || !P1) {
1021 ATH_MSG_WARNING("Nullptr were given");
1022 return true;
1023 }
1024 return (P == P1);
1025 }
1026
1027 float IsolationCloseByCorrectionTool::deltaR2(const xAOD::IParticle* P, const xAOD::IParticle* P1, bool AvgCalo) const {
1028 if (isSame(P, P1)) return 0.;
1029 // Check if one of the objects is a CaloCluster or the Averaging over the clusters is requested.
1030 if (AvgCalo || (P->type() != P1->type() &&
1032 float phi1{0.f}, eta1{0.f}, eta2{0.f}, phi2{0.f};
1033 getExtrapEtaPhi(P, eta1, phi1);
1034 getExtrapEtaPhi(P1, eta2, phi2);
1035 return xAOD::P4Helpers::deltaR2(eta1, phi1, eta2, phi2);
1036 }
1037 float dPhi = xAOD::P4Helpers::deltaPhi(P, P1);
1038 float dEta = P->eta() - P1->eta();
1039 return dEta * dEta + dPhi * dPhi;
1040 }
1042 return (!isSame(P, P1) && deltaR2(P, P1) < (dR * dR));
1043 }
1045 std::lock_guard<std::mutex> guard{m_isoHelpersMutex};
1046 IsoHelperMap::const_iterator itr = m_isohelpers.find(isoVariable);
1047 float isovalue = 0;
1048 if (itr == m_isohelpers.end() || itr->second->getOriginalIsolation(particle, isovalue) == CorrectionCode::Error) {
1049 ATH_MSG_ERROR("Failed to retrieve the original isolation cone ");
1050 isovalue = FLT_MAX;
1051 }
1052 return isovalue;
1053 }
1058 float Et{0.f};
1059 if (cluster) {
1060 try {
1061 Et = cluster->p4(xAOD::CaloCluster::State::UNCALIBRATED).Et();
1062 Et = Et - cluster->eSample(xAOD::CaloCluster::CaloSample::TileGap3) /
1063 std::cosh(cluster->p4(xAOD::CaloCluster::State::UNCALIBRATED).Eta());
1064 } catch (...) { Et = cluster->p4().Et(); }
1065 }
1066 return std::max(Et, 0.f);
1067 }
1070 if (T == xAOD::Type::ObjectType::Electron) return "Electron";
1071 if (T == xAOD::Type::ObjectType::Photon) return "Photon";
1072 if (T == xAOD::Type::ObjectType::Muon) return "Muon";
1073 if (T == xAOD::Type::ObjectType::TrackParticle) return "Track";
1074 if (T == xAOD::Type::ObjectType::CaloCluster) return "Cluster";
1075 return "Unknown";
1076 }
1101 ATH_MSG_INFO("The following isolation cones are considered for " << particleName(T));
1102 for (const IsoType& cone : types) { ATH_MSG_INFO(" --- " << toString(cone)); }
1103 }
1115} // namespace CP
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(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.
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
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.
SG::auxid_t auxid() const
Return the aux id for this variable.
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
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
std::string toString(const IsoType &iso)
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".
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...
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")
const SG::AuxElement::Accessor< float > * getIsolationAccessor(Iso::IsolationType type)
Get the Accessor object for a given isolation type.
static const SG::AuxElement::Accessor< std::vector< std::string > > names("thrNames")
Accessor for the names of the passed thresholds.
Muon_v1 Muon
Reference the current persistent version:
setBGCode setTAP setLVL2ErrorBits bool
static const SG::AuxElement::Accessor< ElementLink< IParticleContainer > > acc("originalObjectLink")
Object used for setting/getting the dynamic decoration in question.
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.
For the flow elements we need a special derivate which also contains the weights.
std::vector< float > isolationValues
xAOD::Type::ObjectType type