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 if (muon->muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon) { // if muon is a forward muon, skip. Basically the tracks associated
125 // to this are the wrong type (InDetForwardTrackParticle instead of
126 // InDetTrackParticle), so the indices used would be wrong/generate
127 // spurious matches
128 ATH_MSG_DEBUG("Muon is identified as a forward muon, skipping");
129 continue;
130 }
131 if (muon->author() == xAOD::Muon::Author::STACO) { // remove muons primarily authored by STACO algorithm.
132 ATH_MSG_DEBUG("Muon is authored by STACO algorithm, skip");
133 continue;
134 }
135 size_t MuonTrkIndex = muon_trk->index();
136 if (MuonTrkIndex == FETrackIndex) {
137 // Add Muon element link to a vector
138 // index() is the unique index of the muon in the muon container
139 FEMuonLinks.emplace_back(*muonReadHandle, muon->index());
140 // Add flow element link to a vector
141 // index() is the unique index of the cFlowElement in the cFlowElementcontaine
142 muonChargedFEVec.at(muon->index()).emplace_back(*ChargedFEReadHandle, FE->index());
143 } // matching block
144
145 //if in mode where we can access calorimeter cells, then we will check if any of the clusters
146 //that this chargedFE has modified have calorimeter cells that match the muons calorimeter cells
147 //if so then we will decorate the charged FE with the fraction of cluster energy that was matched
149 const xAOD::CaloCluster* muonCluster = muon->cluster();
150 //these clusters are expected to be nullptr sometimes
151 if (!muonCluster) continue;
152 unsigned int counter = 0;
153 for (auto thisCluster : FE->otherObjects()){
154 const xAOD::CaloCluster* thisCaloCluster = dynamic_cast<const xAOD::CaloCluster*>(thisCluster);
155 bool isCellMatched = false;
156 std::pair <double,double> FEAndMuonMatchedCellEnergy = this->doMuonCellMatching(isCellMatched, *thisCaloCluster,*muonCluster);
157 FEMatchedClusterCellEnergies[counter] += FEAndMuonMatchedCellEnergy.first;
158 counter++;
159 }//loop over associated calorimeter clusters
160 }
161 }// end of muon loop
162
163 chargedFE_energy_match_muonWriteHandle(*FE) = FEMatchedClusterCellEnergies;
164
165 // Add vector of muon element links as decoration to FlowElement container
166 ChargedFEmuonWriteDecorHandle(*FE) = FEMuonLinks;
167 } // end of charged Flow Element loop
168
170 // Loop over Neutral FlowElements
172
182 ATH_MSG_VERBOSE("Experimental: Cluster Linkers between neutral FEs and Muons are used");
183 for (const xAOD::FlowElement* FE : *NeutralFEmuonWriteDecorHandle) {
184 int nMatchedFE = 0;
185 // get the index of the cluster corresponding to the Neutral FlowElements
186 ATH_MSG_DEBUG("P1");
187 ATH_MSG_DEBUG("FE with e, eta and phi" << FE->e() << ", " << FE->eta() << " and " << FE->phi());
188 const xAOD::IParticle* otherObject = FE->otherObjects().at(0);
189 //This is expected to happen for low energy FE - sometimes the linked cluster has E < 0 and
190 //is thinned away in the AOD
191 if (!otherObject){
192 ATH_MSG_DEBUG("No linked cluster for Neutral FE with E, eta and phi" << FE->e() << ", " << FE->eta() << " and " << FE->phi());
193 continue;
194 }
195 size_t FEclusterindex = otherObject->index();
196
197 // FE->otherObjects returns a vector of IParticles. We only want the first one
198 const xAOD::IParticle* FE_Iparticle = FE->otherObjects().at(0);
199
200 // dynamic cast to CaloCluster
201 const xAOD::CaloCluster* FE_cluster = dynamic_cast<const xAOD::CaloCluster*>(FE_Iparticle); // cast to CaloCluster
202
203 // debug for Negative energy cluster
204
205 double cluster_E = FE_cluster->p4().E();
206 bool neg_E_cluster = (cluster_E < 0.0);
207
208 // design the vector of ElementLinks
209 std::vector<MuonLink_t> FEMuonLinks;
210 std::vector<double> FE_efrac_clustermatch;
211 std::vector<double> Muon_efrac_clustermatch;
212 for (const xAOD::Muon* muon : *muonNeutralFEWriteDecorHandle) {
213 // Retrieve the ElementLink vector of clusters
214 const xAOD::CaloCluster* cluster = muon->cluster();
215 // de-ref the element link to retrieve the pointer to the original object
216 // check if the ElementLink is valid
217 if (!cluster) {
218 ATH_MSG_DEBUG("Muon has an invalid link to cluster");
219 continue;
220 }
222 // get the linker to the topo clusters
223 const std::vector<ElementLink<xAOD::CaloClusterContainer>>& linksToTopoClusters = acc_constClusterLinks(*cluster);
224 for (const ElementLink<xAOD::CaloClusterContainer>& TopoClusterLink : linksToTopoClusters) {
225 //This is expected to happen for low energy cluster - sometimes the linked cluster has E < 0 and
226 //is thinned away in the AOD
227 if (!TopoClusterLink.isValid()) {
228 ATH_MSG_DEBUG("Muon Calo cluster's TopoCluster link not found, skip");
229 continue;
230 }
231 const xAOD::CaloCluster* MuonTopoCluster = *TopoClusterLink; // de-ref the link to get the topo-cluster
232 size_t MuonTopoCluster_index = MuonTopoCluster->index();
233 if (MuonTopoCluster_index == FEclusterindex) {
234 // Add Muon element link to a vector
235 // index() is the unique index of the muon in the muon container
236 FEMuonLinks.emplace_back(*muonReadHandle, muon->index());
237 // index() is the unique index of the cFlowElement in the cFlowElementcontaine
238 muonNeutralFEVec.at(muon->index()).emplace_back(*NeutralFEReadHandle, FE->index());
239 ATH_MSG_VERBOSE("Got a match between NFE and Muon");
240 nMatchedFE++; // count number of matches between FE and muons
241 if (neg_E_cluster) ATH_MSG_ERROR("Muon cluster matched to negative E topocluster from FE");
242 } // check block of index matching
243 } // end of loop over element links
244 } // end of TopoCluster specific block
245 else { // case when we don't use Topoclusters, just match the caloclusters to the flow element
246 // if we don't match topoclusters, do something more complex:
247 // Retrieve cells in both the FE cluster and muon cluster
248 // Define the link as where at least one calo cell is shared between the FE cluster and the Muon Cluster
249
250 bool isCellMatched = false;
251 std::pair<double,double> FEAndMuonMatchedCellEnergy = this->doMuonCellMatching(isCellMatched, *FE_cluster,*cluster);
252
253 double FE_sum_matched_cellEnergy = FEAndMuonMatchedCellEnergy.first;
254 double Muon_sum_matched_cellEnergy = FEAndMuonMatchedCellEnergy.second;
255
256 double frac_FE_cluster_energy_matched = 0;
257 // retrieve total cluster energy from the FE cluster
258 double tot_FE_cluster_energy = FE_cluster->e();
259 if (tot_FE_cluster_energy != 0) { // ! div 0
260 frac_FE_cluster_energy_matched = FE_sum_matched_cellEnergy / tot_FE_cluster_energy;
261 }
262 double tot_muon_cluster_energy = cluster->e();
263 double frac_muon_cluster_energy_matched = 0;
264 if (tot_muon_cluster_energy != 0) {
265 frac_muon_cluster_energy_matched = Muon_sum_matched_cellEnergy / tot_muon_cluster_energy;
266 }
267 if (frac_FE_cluster_energy_matched > 0) {
268 ATH_MSG_VERBOSE("Fraction of FE cluster energy used in match: " << frac_FE_cluster_energy_matched << ", ismatched? "
269 << isCellMatched << "");
270 ATH_MSG_VERBOSE("Numerator and denominator are " << FE_sum_matched_cellEnergy << " and " << tot_FE_cluster_energy);
271 ATH_MSG_VERBOSE("Fraction of Muon cluster energy used in match: " << frac_muon_cluster_energy_matched << "");
272 }
273
274 if (isCellMatched) { // cell matched => Link the two objects.
275 // Add Muon element link to a vector
276 // index() is the unique index of the muon in the muon container
277 FEMuonLinks.emplace_back(*muonReadHandle, muon->index());
278 // index() is the unique index of the nFlowElement in the nFlowElementcontainer
279 muonNeutralFEVec.at(muon->index()).emplace_back(*NeutralFEReadHandle, FE->index());
280 // save the energy fraction used in the cluster matching - mostly for debug/extension studies
281 FE_efrac_clustermatch.push_back(frac_FE_cluster_energy_matched); // fraction of FE cluster energy matched
282 muonNeutralFE_frac_cluster_energy_matched_Vec.at(muon->index())
283 .push_back(frac_muon_cluster_energy_matched); // fraction of Muon cluster energy matched
284 nMatchedFE++; // count number of matches incrementally
285 if (neg_E_cluster) { ATH_MSG_ERROR("Muon cluster matched to negative E topocluster from FE"); }
286 }
287
288 } // end of calocluster specific block
289 // loop over caloclusters
290 } // loop over muons
291 NeutralFEmuon_nMatches_WriteDecorHandle(*FE) = nMatchedFE;
292 NeutralFEmuonWriteDecorHandle(*FE) = FEMuonLinks;
293 NeutralFE_efrac_match_muonWriteDecorHandle(*FE) = FE_efrac_clustermatch;
294 } // loop over neutral FE
295 } // end of the Gaudi check block
296
298 // WRITE OUTPUT: ADD HANDLES TO MUON CONTAINERS
300 // Add the vectors of the Flow Element Links as decoations to the muon container
301 for (const xAOD::Muon* muon : *muonChargedFEWriteDecorHandle) {
302 muonChargedFEWriteDecorHandle(*muon) = muonChargedFEVec.at(muon->index());
303 } // end of muon loop
304 if (m_LinkNeutralFEClusters) { // Experimental
305 for (const xAOD::Muon* muon : *muonNeutralFEWriteDecorHandle) {
306 if (!muonNeutralFEVec.empty()) {
307 muonNeutralFEWriteDecorHandle(*muon) = muonNeutralFEVec.at(muon->index());
308 muonNeutralFE_muon_efrac_WriteDecorHandle(*muon) = muonNeutralFE_frac_cluster_energy_matched_Vec.at(muon->index());
309 }
310 // For debug of the muon clusters used, add also: dR between caloclusters and number of caloclusters associated to each muon.
311 // retrieve element link again to cluster
312 // use elem link to retrieve container
313 const xAOD::CaloCluster* MuonCluster = muon->cluster();
314 // retrieve the vector of delta R between muon and its associated calo cluster.
315 muon_ClusterInfo_deltaR_WriteDecorHandle(*muon) = MuonCluster ? xAOD::P4Helpers::deltaR(MuonCluster,muon,false) : -1.;
316 }
317 } // end of experimental block
318 ATH_MSG_VERBOSE("Execute completed successfully");
319
320 return StatusCode::SUCCESS;
321}
322
323std::pair<double,double> PFMuonFlowElementAssoc::doMuonCellMatching(bool& isCellMatched,const xAOD::CaloCluster& FECluster, const xAOD::CaloCluster& muonCluster)
324const {
325
326 const CaloClusterCellLink* FECellLinks = FECluster.getCellLinks();
327 if (!FECellLinks && !m_useMuonTopoClusters) {
328 ATH_MSG_WARNING("Flow Element CaloCluster CaloClusterCellLink is nullptr");
329 return std::make_pair(0.0,0.0);
330 }
331
332 const CaloClusterCellLink* muonCellLinks = muonCluster.getCellLinks();
333 if (!muonCellLinks) {
334 ATH_MSG_WARNING("This Muon calo cluster does not have any cells associated to it");
335 return std::make_pair(0.0,0.0);
336 }
337
338 //sum of energy of FE cells that are matched
339 double FE_matchedCellEnergy = 0;
340 //sum of energy of muon cells that are matched
341 double muon_matchedCellEnergy = 0;
342
343 for (auto thisFECell : *FECellLinks){
344 Identifier FECellID = thisFECell->ID();
345 for (auto thisMuonCell : *muonCellLinks){
346 Identifier muonCellID = thisMuonCell->ID();
347 if (muonCellID == FECellID){
348 isCellMatched = true;
349 FE_matchedCellEnergy += thisFECell->e();
350 muon_matchedCellEnergy += thisMuonCell->e();
351 }//if FE cell is also a muon cell
352 }//loop on muon cells
353 }//loop on FE cluster cells
354
355 return std::make_pair(FE_matchedCellEnergy,muon_matchedCellEnergy);
356
357}
#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.
size_t size() const
Number of registered mappings.
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)
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: