ATLAS Offline Software
Loading...
Searching...
No Matches
PFMuonFlowElementAssoc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
6
9#include "xAODMuon/Muon.h"
13
14// includes for CaloCluster algo
15#include "CaloEvent/CaloCell.h"
17#include "Identifier/Identifier.h"
21//
22// Algorithm created by M.T. Anthony
23//
24// =============================================================
25PFMuonFlowElementAssoc::PFMuonFlowElementAssoc(const std::string& name, ISvcLocator* pSvcLocator) :
26 AthReentrantAlgorithm(name, pSvcLocator) {
27 // Declare the decoration keys
28}
29
31
32// =============================================================
34 ATH_MSG_VERBOSE("Initializing " << name() << "...");
35
36 // Initialise the decoration keys
44
45 // init the experimental keys
49
50 // init ReadHandleKeys
51 ATH_CHECK(m_muonReadHandleKey.initialize());
54
55 ATH_MSG_VERBOSE("Initialization completed successfully");
56
57 return StatusCode::SUCCESS;
58}
59
60// =========================================================================
61StatusCode PFMuonFlowElementAssoc::execute(const EventContext& ctx) const {
62 // WriteDecorHandles for the charged/neutral Flow Elements and Muons
63 // Links a Muon that has a track to a charged flow element if possible
64
65 ATH_MSG_VERBOSE("Started execute step");
66
67 // Get container for muons
69 ctx);
71 ctx);
72 // get container for charged flow elements
74 ctx);
76 ctx);
77
78 // extra container handles between neutral FE cluster and Muon CaloCluster - these are all for studies based on neutral Flow Element
79 // matching - All of these handles are experimental
80 SG::WriteDecorHandle<xAOD::FlowElementContainer, std::vector<double>> NeutralFE_efrac_match_muonWriteDecorHandle(
82 SG::WriteDecorHandle<xAOD::MuonContainer, std::vector<double>> muonNeutralFE_muon_efrac_WriteDecorHandle(
84 SG::WriteDecorHandle<xAOD::FlowElementContainer, int> NeutralFEmuon_nMatches_WriteDecorHandle(
86 SG::WriteDecorHandle<xAOD::MuonContainer, double> muon_ClusterInfo_deltaR_WriteDecorHandle(
88
89 // store readhandles for muon and charged flow elements
90 SG::ReadHandle<xAOD::MuonContainer> muonReadHandle(m_muonReadHandleKey, ctx); // readhandle for muon
94 // now init some Flow element link containers
95 std::vector<std::vector<FlowElementLink_t>> muonChargedFEVec(muonReadHandle->size());
96 std::vector<std::vector<FlowElementLink_t>> muonNeutralFEVec(muonReadHandle->size());
97
98 // for neutral flow element studies
99 std::vector<std::vector<double>> muonNeutralFE_frac_cluster_energy_matched_Vec(muonReadHandle->size());
100
102
103 // Loop over the Flow Elements
104
106 // CHARGED LOOP
108 for (const xAOD::FlowElement* FE : *ChargedFEmuonWriteDecorHandle) {
109 // get the track associated to the charged flow element (or at least the index of said track)
110 size_t FETrackIndex = FE->chargedObjects().at(0)->index();
111 // Init a vector of element links to muons
112 std::vector<MuonLink_t> FEMuonLinks;
113
114 //vector of fractions of FE cluster energy matched to muons
115 std::vector<double> FEMatchedClusterCellEnergies;
116 for (unsigned int counter = 0; counter < FE->otherObjects().size(); ++counter) FEMatchedClusterCellEnergies.push_back(0.0);
117
118 // loop over muons in container
119 for (const xAOD::Muon* muon : *muonChargedFEWriteDecorHandle) {
120 const xAOD::TrackParticle* muon_trk = muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
122 if (!muon_trk) continue;
123 // skip muon matching if the following cases occur
124 int MuonType = muon->muonType();
125 int MuonAuthor = muon->author();
126 if (MuonType == xAOD::Muon::SiliconAssociatedForwardMuon) { // if muon is a forward muon, skip. Basically the tracks associated
127 // to this are the wrong type (InDetForwardTrackParticle instead of
128 // InDetTrackParticle), so the indices used would be wrong/generate
129 // spurious matches
130 ATH_MSG_DEBUG("Muon is identified as a forward muon, skipping");
131 continue;
132 }
133 if (MuonAuthor == xAOD::Muon::Author::STACO) { // remove muons primarily authored by STACO algorithm.
134 ATH_MSG_DEBUG("Muon is authored by STACO algorithm, skip");
135 continue;
136 }
137 size_t MuonTrkIndex = muon_trk->index();
138 if (MuonTrkIndex == FETrackIndex) {
139 // Add Muon element link to a vector
140 // index() is the unique index of the muon in the muon container
141 FEMuonLinks.emplace_back(*muonReadHandle, muon->index());
142 // Add flow element link to a vector
143 // index() is the unique index of the cFlowElement in the cFlowElementcontaine
144 muonChargedFEVec.at(muon->index()).emplace_back(*ChargedFEReadHandle, FE->index());
145 } // matching block
146
147 //if in mode where we can access calorimeter cells, then we will check if any of the clusters
148 //that this chargedFE has modified have calorimeter cells that match the muons calorimeter cells
149 //if so then we will decorate the charged FE with the fraction of cluster energy that was matched
151 const xAOD::CaloCluster* muonCluster = muon->cluster();
152 //these clusters are expected to be nullptr sometimes
153 if (!muonCluster) continue;
154 unsigned int counter = 0;
155 for (auto thisCluster : FE->otherObjects()){
156 const xAOD::CaloCluster* thisCaloCluster = dynamic_cast<const xAOD::CaloCluster*>(thisCluster);
157 bool isCellMatched = false;
158 std::pair <double,double> FEAndMuonMatchedCellEnergy = this->doMuonCellMatching(isCellMatched, *thisCaloCluster,*muonCluster);
159 FEMatchedClusterCellEnergies[counter] += FEAndMuonMatchedCellEnergy.first;
160 counter++;
161 }//loop over associated calorimeter clusters
162 }
163 }// end of muon loop
164
165 chargedFE_energy_match_muonWriteHandle(*FE) = FEMatchedClusterCellEnergies;
166
167 // Add vector of muon element links as decoration to FlowElement container
168 ChargedFEmuonWriteDecorHandle(*FE) = FEMuonLinks;
169 } // end of charged Flow Element loop
170
172 // Loop over Neutral FlowElements
174
184 ATH_MSG_VERBOSE("Experimental: Cluster Linkers between neutral FEs and Muons are used");
185 for (const xAOD::FlowElement* FE : *NeutralFEmuonWriteDecorHandle) {
186 int nMatchedFE = 0;
187 // get the index of the cluster corresponding to the Neutral FlowElements
188 ATH_MSG_DEBUG("P1");
189 ATH_MSG_DEBUG("FE with e, eta and phi" << FE->e() << ", " << FE->eta() << " and " << FE->phi());
190 const xAOD::IParticle* otherObject = FE->otherObjects().at(0);
191 //This is expected to happen for low energy FE - sometimes the linked cluster has E < 0 and
192 //is thinned away in the AOD
193 if (!otherObject){
194 ATH_MSG_DEBUG("No linked cluster for Neutral FE with E, eta and phi" << FE->e() << ", " << FE->eta() << " and " << FE->phi());
195 continue;
196 }
197 size_t FEclusterindex = otherObject->index();
198
199 // FE->otherObjects returns a vector of IParticles. We only want the first one
200 const xAOD::IParticle* FE_Iparticle = FE->otherObjects().at(0);
201
202 // dynamic cast to CaloCluster
203 const xAOD::CaloCluster* FE_cluster = dynamic_cast<const xAOD::CaloCluster*>(FE_Iparticle); // cast to CaloCluster
204
205 // debug for Negative energy cluster
206
207 double cluster_E = FE_cluster->p4().E();
208 bool neg_E_cluster = (cluster_E < 0.0);
209
210 // design the vector of ElementLinks
211 std::vector<MuonLink_t> FEMuonLinks;
212 std::vector<double> FE_efrac_clustermatch;
213 std::vector<double> Muon_efrac_clustermatch;
214 for (const xAOD::Muon* muon : *muonNeutralFEWriteDecorHandle) {
215 // Retrieve the ElementLink vector of clusters
216 const xAOD::CaloCluster* cluster = muon->cluster();
217 // de-ref the element link to retrieve the pointer to the original object
218 // check if the ElementLink is valid
219 if (!cluster) {
220 ATH_MSG_DEBUG("Muon has an invalid link to cluster");
221 continue;
222 }
224 // get the linker to the topo clusters
225 const std::vector<ElementLink<xAOD::CaloClusterContainer>>& linksToTopoClusters = acc_constClusterLinks(*cluster);
226 for (const ElementLink<xAOD::CaloClusterContainer>& TopoClusterLink : linksToTopoClusters) {
227 //This is expected to happen for low energy cluster - sometimes the linked cluster has E < 0 and
228 //is thinned away in the AOD
229 if (!TopoClusterLink.isValid()) {
230 ATH_MSG_DEBUG("Muon Calo cluster's TopoCluster link not found, skip");
231 continue;
232 }
233 const xAOD::CaloCluster* MuonTopoCluster = *TopoClusterLink; // de-ref the link to get the topo-cluster
234 size_t MuonTopoCluster_index = MuonTopoCluster->index();
235 if (MuonTopoCluster_index == FEclusterindex) {
236 // Add Muon element link to a vector
237 // index() is the unique index of the muon in the muon container
238 FEMuonLinks.emplace_back(*muonReadHandle, muon->index());
239 // index() is the unique index of the cFlowElement in the cFlowElementcontaine
240 muonNeutralFEVec.at(muon->index()).emplace_back(*NeutralFEReadHandle, FE->index());
241 ATH_MSG_VERBOSE("Got a match between NFE and Muon");
242 nMatchedFE++; // count number of matches between FE and muons
243 if (neg_E_cluster) ATH_MSG_ERROR("Muon cluster matched to negative E topocluster from FE");
244 } // check block of index matching
245 } // end of loop over element links
246 } // end of TopoCluster specific block
247 else { // case when we don't use Topoclusters, just match the caloclusters to the flow element
248 // if we don't match topoclusters, do something more complex:
249 // Retrieve cells in both the FE cluster and muon cluster
250 // Define the link as where at least one calo cell is shared between the FE cluster and the Muon Cluster
251
252 bool isCellMatched = false;
253 std::pair<double,double> FEAndMuonMatchedCellEnergy = this->doMuonCellMatching(isCellMatched, *FE_cluster,*cluster);
254
255 double FE_sum_matched_cellEnergy = FEAndMuonMatchedCellEnergy.first;
256 double Muon_sum_matched_cellEnergy = FEAndMuonMatchedCellEnergy.second;
257
258 double frac_FE_cluster_energy_matched = 0;
259 // retrieve total cluster energy from the FE cluster
260 double tot_FE_cluster_energy = FE_cluster->e();
261 if (tot_FE_cluster_energy != 0) { // ! div 0
262 frac_FE_cluster_energy_matched = FE_sum_matched_cellEnergy / tot_FE_cluster_energy;
263 }
264 double tot_muon_cluster_energy = cluster->e();
265 double frac_muon_cluster_energy_matched = 0;
266 if (tot_muon_cluster_energy != 0) {
267 frac_muon_cluster_energy_matched = Muon_sum_matched_cellEnergy / tot_muon_cluster_energy;
268 }
269 if (frac_FE_cluster_energy_matched > 0) {
270 ATH_MSG_VERBOSE("Fraction of FE cluster energy used in match: " << frac_FE_cluster_energy_matched << ", ismatched? "
271 << isCellMatched << "");
272 ATH_MSG_VERBOSE("Numerator and denominator are " << FE_sum_matched_cellEnergy << " and " << tot_FE_cluster_energy);
273 ATH_MSG_VERBOSE("Fraction of Muon cluster energy used in match: " << frac_muon_cluster_energy_matched << "");
274 }
275
276 if (isCellMatched) { // cell matched => Link the two objects.
277 // Add Muon element link to a vector
278 // index() is the unique index of the muon in the muon container
279 FEMuonLinks.emplace_back(*muonReadHandle, muon->index());
280 // index() is the unique index of the nFlowElement in the nFlowElementcontainer
281 muonNeutralFEVec.at(muon->index()).emplace_back(*NeutralFEReadHandle, FE->index());
282 // save the energy fraction used in the cluster matching - mostly for debug/extension studies
283 FE_efrac_clustermatch.push_back(frac_FE_cluster_energy_matched); // fraction of FE cluster energy matched
284 muonNeutralFE_frac_cluster_energy_matched_Vec.at(muon->index())
285 .push_back(frac_muon_cluster_energy_matched); // fraction of Muon cluster energy matched
286 nMatchedFE++; // count number of matches incrementally
287 if (neg_E_cluster) { ATH_MSG_ERROR("Muon cluster matched to negative E topocluster from FE"); }
288 }
289
290 } // end of calocluster specific block
291 // loop over caloclusters
292 } // loop over muons
293 NeutralFEmuon_nMatches_WriteDecorHandle(*FE) = nMatchedFE;
294 NeutralFEmuonWriteDecorHandle(*FE) = FEMuonLinks;
295 NeutralFE_efrac_match_muonWriteDecorHandle(*FE) = FE_efrac_clustermatch;
296 } // loop over neutral FE
297 } // end of the Gaudi check block
298
300 // WRITE OUTPUT: ADD HANDLES TO MUON CONTAINERS
302 // Add the vectors of the Flow Element Links as decoations to the muon container
303 for (const xAOD::Muon* muon : *muonChargedFEWriteDecorHandle) {
304 muonChargedFEWriteDecorHandle(*muon) = muonChargedFEVec.at(muon->index());
305 } // end of muon loop
306 if (m_LinkNeutralFEClusters) { // Experimental
307 for (const xAOD::Muon* muon : *muonNeutralFEWriteDecorHandle) {
308 if (!muonNeutralFEVec.empty()) {
309 muonNeutralFEWriteDecorHandle(*muon) = muonNeutralFEVec.at(muon->index());
310 muonNeutralFE_muon_efrac_WriteDecorHandle(*muon) = muonNeutralFE_frac_cluster_energy_matched_Vec.at(muon->index());
311 }
312 // For debug of the muon clusters used, add also: dR between caloclusters and number of caloclusters associated to each muon.
313 // retrieve element link again to cluster
314 // use elem link to retrieve container
315 const xAOD::CaloCluster* MuonCluster = muon->cluster();
316 // retrieve the vector of delta R between muon and its associated calo cluster.
317 muon_ClusterInfo_deltaR_WriteDecorHandle(*muon) = MuonCluster ? xAOD::P4Helpers::deltaR(MuonCluster,muon,false) : -1.;
318 }
319 } // end of experimental block
320 ATH_MSG_VERBOSE("Execute completed successfully");
321
322 return StatusCode::SUCCESS;
323}
324
325std::pair<double,double> PFMuonFlowElementAssoc::doMuonCellMatching(bool& isCellMatched,const xAOD::CaloCluster& FECluster, const xAOD::CaloCluster& muonCluster)
326const {
327
328 const CaloClusterCellLink* FECellLinks = FECluster.getCellLinks();
329 if (!FECellLinks && !m_useMuonTopoClusters) {
330 ATH_MSG_WARNING("Flow Element CaloCluster CaloClusterCellLink is nullptr");
331 return std::make_pair(0.0,0.0);
332 }
333
334 const CaloClusterCellLink* muonCellLinks = muonCluster.getCellLinks();
335 if (!muonCellLinks) {
336 ATH_MSG_WARNING("This Muon calo cluster does not have any cells associated to it");
337 return std::make_pair(0.0,0.0);
338 }
339
340 //sum of energy of FE cells that are matched
341 double FE_matchedCellEnergy = 0;
342 //sum of energy of muon cells that are matched
343 double muon_matchedCellEnergy = 0;
344
345 for (auto thisFECell : *FECellLinks){
346 Identifier FECellID = thisFECell->ID();
347 for (auto thisMuonCell : *muonCellLinks){
348 Identifier muonCellID = thisMuonCell->ID();
349 if (muonCellID == FECellID){
350 isCellMatched = true;
351 FE_matchedCellEnergy += thisFECell->e();
352 muon_matchedCellEnergy += thisMuonCell->e();
353 }//if FE cell is also a muon cell
354 }//loop on muon cells
355 }//loop on FE cluster cells
356
357 return std::make_pair(FE_matchedCellEnergy,muon_matchedCellEnergy);
358
359}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
ElementLink< xAOD::FlowElementContainer > FlowElementLink_t
ElementLink< xAOD::MuonContainer > MuonLink_t
Handle class for reading a decoration on an object.
Handle class for adding a decoration to an object.
An algorithm that can be simultaneously executed in multiple threads.
SG::WriteDecorHandleKey< xAOD::FlowElementContainer > m_ChargedFE_energy_match_muonWriteHandleKey
Write key for adding fraction of nFlowElement cluster energy used in cell matching decoration of Flow...
SG::WriteDecorHandleKey< xAOD::MuonContainer > m_muonNeutralFE_muon_efrac_WriteDecorHandleKey
Write key for adding fraction of Muon cluster energy used in cell matching decoration of MuonContaine...
SG::WriteDecorHandleKey< xAOD::FlowElementContainer > m_NeutralFEmuon_nMatches_WriteDecorHandleKey
Write key to count number of muons matched to a given neutral FE - EXPERIMENTAL.
SG::WriteDecorHandleKey< xAOD::MuonContainer > m_muon_ClusterInfo_deltaR_WriteDecorHandleKey
Write key to measure dR between calo clusters and the muon -EXPERIMENTAL.
SG::WriteDecorHandleKey< xAOD::FlowElementContainer > m_NeutralFE_efrac_match_muonWriteHandleKey
Write key for adding fraction of nFlowElement cluster energy used in cell matching decoration of Flow...
std::pair< double, double > doMuonCellMatching(bool &isCellMatched, const xAOD::CaloCluster &FECluster, const xAOD::CaloCluster &muonCluster) const
Function that flags whether the FE cluster has any cell that is also in the muon list of cells.
SG::ReadDecorHandleKey< xAOD::CaloClusterContainer > m_ClustCollectionLinkKey
Gaudi::Property< bool > m_useMuonTopoClusters
(EXPERIMENTAL) Gaudi Property to configure linkage of Neutral FEs to TopoClusters associated to Muons...
SG::WriteDecorHandleKey< xAOD::MuonContainer > m_muonNeutralFEWriteHandleKey
Write key for adding neutral Flow Element link decorations to muons.
SG::WriteDecorHandleKey< xAOD::FlowElementContainer > m_NeutralFEmuonWriteHandleKey
Write key for adding Muon link decorations to neutral Flow Elements.
SG::ReadHandleKey< xAOD::FlowElementContainer > m_neutralFEReadHandleKey
SG::WriteDecorHandleKey< xAOD::FlowElementContainer > m_ChargedFEmuonWriteHandleKey
Write key for adding Muon link decorations to charged Flow Elements.
SG::WriteDecorHandleKey< xAOD::MuonContainer > m_muonChargedFEWriteHandleKey
Write key for adding charged Flow Element link decorations to muons.
virtual ~PFMuonFlowElementAssoc()
SG::ReadHandleKey< xAOD::FlowElementContainer > m_chargedFEReadHandleKey
Gaudi::Property< bool > m_LinkNeutralFEClusters
Gaudi Property to configure linkage of Neutral Flow Elements to Muon clusters (EXPERIMENTAL - default...
virtual StatusCode initialize()
SG::ReadHandleKey< xAOD::MuonContainer > m_muonReadHandleKey
virtual StatusCode execute(const EventContext &ctx) const
PFMuonFlowElementAssoc(const std::string &name, ISvcLocator *pSvcLocator)
size_t index() const
Return the index of this element within its container.
Handle class for reading a decoration on an object.
Handle class for adding a decoration to an object.
const CaloClusterCellLink * getCellLinks() const
Get a pointer to the CaloClusterCellLink object (const version)
virtual double e() const
The total energy of the particle.
virtual FourMom_t p4() const
The full 4-momentum of the particle.
Class providing the definition of the 4-vector interface.
double deltaR(double rapidity1, double phi1, double rapidity2, double phi2)
from bare bare rapidity,phi
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:
Muon_v1 Muon
Reference the current persistent version: