ATLAS Offline Software
JetPFlowSelectionAlg.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
9 
10 #include "xAODEgamma/Electron.h"
12 #include "xAODMuon/Muon.h"
13 #include "xAODPFlow/FlowElement.h"
15 #include "xAODPFlow/FEHelpers.h"
16 
18  ATH_MSG_DEBUG("Initializing " );
19 
24  }
33 
34 
35  return StatusCode::SUCCESS;
36 }
37 
38 StatusCode JetPFlowSelectionAlg::execute(const EventContext& ctx) const {
39  ATH_MSG_DEBUG(" execute() ... ");
40 
42  if (! ChargedPFlowObjects.isValid()){
43  ATH_MSG_ERROR("Can't retrieve input container "<< m_ChargedPFlowContainerKey);
44  return StatusCode::FAILURE;
45  }
46 
48  if (! NeutralPFlowObjects.isValid()){
49  ATH_MSG_ERROR("Can't retrieve input container "<< m_NeutralPFlowContainerKey);
50  return StatusCode::FAILURE;
51  }
52 
54  if (!chargedFE_ElectronLinks.isValid()){
55  ATH_MSG_ERROR("Can't retrieve input decoration " << chargedFE_ElectronLinks.key());
56  return StatusCode::FAILURE;
57  }
58 
60  if (!chargedFE_MuonLinks.isValid()){
61  ATH_MSG_ERROR("Can't retrieve input decoration "<< chargedFE_MuonLinks.key());
62  return StatusCode::FAILURE;
63  }
64 
66  if (!neutralFE_ElectronLinks.isValid()){
67  ATH_MSG_ERROR("Can't retrieve input decoration "<< neutralFE_ElectronLinks.key());
68  return StatusCode::FAILURE;
69  }
70 
72  if (!neutralFE_MuonLinks.isValid()){
73  ATH_MSG_ERROR("Can't retrieve input decoration "<< neutralFE_MuonLinks.key());
74  return StatusCode::FAILURE;
75  }
76 
77  auto selectedChargedPFlowObjects = std::make_unique<xAOD::FlowElementContainer>(); // SG::VIEW_ELEMENTS
78  auto selectedChargedPFlowObjectsAux = std::make_unique<xAOD::FlowElementAuxContainer>();
79  selectedChargedPFlowObjects->setStore(selectedChargedPFlowObjectsAux.get());
80 
81  auto selectedNeutralPFlowObjects = std::make_unique<xAOD::FlowElementContainer>();
82  auto selectedNeutralPFlowObjectsAux = std::make_unique<xAOD::FlowElementAuxContainer>();
83  selectedNeutralPFlowObjects->setStore(selectedNeutralPFlowObjectsAux.get());
84 
85  // To store the charged FE objects matched to an electron/muon
86  std::vector< const xAOD::FlowElement* > ChargedPFlowObjects_matched;
87 
88  // Loop over Charged FE objects
89  for ( const xAOD::FlowElement* fe : *ChargedPFlowObjects ) {
90 
91  // Select FE object if not matched to an electron or muon via links
92  if ( !checkElectronLinks(chargedFE_ElectronLinks(*fe)) && !checkMuonLinks(chargedFE_MuonLinks(*fe)) ){
93  xAOD::FlowElement* selectedFE = new xAOD::FlowElement();
94  selectedChargedPFlowObjects->push_back(selectedFE);
95  *selectedFE = *fe; // copies auxdata
96  }
97  else { // Use the matched object to put back its energy later
98  ChargedPFlowObjects_matched.push_back(fe);
99  }
100 
101  } // End loop over Charged FE Objects
102 
103 
104  // Loop over Neutral FE objects
105  for ( const xAOD::FlowElement* fe : *NeutralPFlowObjects ) {
106 
107  //if links to an electron, then we veto entire neutral FE
109  if (checkElectronLinks(neutralFE_ElectronLinks(*fe))) continue;
110  }
111 
112  xAOD::FlowElement* selectedFE = new xAOD::FlowElement();
113  selectedNeutralPFlowObjects->push_back(selectedFE);
114  *selectedFE = *fe;
115 
116  //if links to a muon, then we need to subtract off the muon energy in
117  //this calorimeter cluster
118  if (m_removeNeutralMuonFE && checkMuonLinks(neutralFE_MuonLinks(*fe))){
120  double totalMuonCaloEnergy = 0.0;
121  for (auto energy : clusterMuonEnergyFracs(*fe) ) totalMuonCaloEnergy += energy;
122  TLorentzVector newP4;
123  newP4.SetPxPyPzE(fe->p4().Px(),fe->p4().Py(),fe->p4().Pz(),fe->e() - totalMuonCaloEnergy);
124  selectedFE->setP4(newP4);
125  }
126 
127 
128  } // End loop over Neutral FE Objects
129 
130  // Add the energy from removed charged FE clusters to neutral FE object
131  // if shared clusters exist, create the new neutral FE object otherwise
132  for ( const xAOD::FlowElement* chargedFE : ChargedPFlowObjects_matched ){
133 
134  // Get charged FE topoclusters and weights
135  std::vector<std::pair<const xAOD::IParticle*,float> > theOtherPairs_charged = chargedFE->otherObjectsAndWeights();
136  std::vector<ElementLink<xAOD::IParticleContainer>> theOtherLinks_charged = chargedFE->otherObjectLinks();
137 
138  // Loop over charged FE topoclusters
139  for (unsigned int iCluster = 0; iCluster < chargedFE->nOtherObjects(); ++iCluster){
140 
141  bool thisCluster_matched = false;
142 
143  std::pair<const xAOD::IParticle*,float> theOtherPair_charged = theOtherPairs_charged[iCluster];
144  const xAOD::IParticle* theCluster_charged = theOtherPair_charged.first;
145  float theClusterWeight_charged = theOtherPair_charged.second;
146 
147  // Loop over neutral FE objects
148  for ( xAOD::FlowElement* neutralFE : *selectedNeutralPFlowObjects ) {
149  if (thisCluster_matched) continue;
150 
151  // Loop over neutral FE topoclusters
152  std::vector<std::pair<const xAOD::IParticle*,float> > theOtherPairs_neutral = neutralFE->otherObjectsAndWeights();
153  for (auto& [theCluster_neutral, theClusterWeight_neutral] : theOtherPairs_neutral){
154 
155  // If topoclusters are matched, add the energy to the neutral FE object
156  if (theCluster_charged == theCluster_neutral){
157 
158  // Add the energy to the neutral FE object
159  float newEnergy = neutralFE->e() + theClusterWeight_charged;
160  neutralFE->setP4(newEnergy/cosh(neutralFE->eta()),
161  neutralFE->eta(),
162  neutralFE->phi(),
163  neutralFE->m());
164 
165  ATH_MSG_DEBUG("Updated neutral FlowElement with E, pt, eta and phi: "
166  << neutralFE->e() << ", " << neutralFE->pt() << ", "
167  << neutralFE->eta() << " and " << neutralFE->phi());
168 
169  thisCluster_matched = true;
170  }
171 
172  } // End loop over neutral FE clusters
173  } // End loop over neutral FE objects
174 
175  // If a topocluster is left unmatched, create a neutral FE object.
176  // Ignore topoclusters with nullptr
177  if ( !thisCluster_matched && theCluster_charged ){
178 
179  //check if charged cluster belongs to an electron, before we put it back as neutral
180  bool belongsToElectron = false;
182 
183  //get container index of charged cluster and compare to indices of electron topoclusters
184  unsigned int chargedClusterIndex = theCluster_charged->index();
185 
187  if (!electronReadHandle.isValid()){
188  ATH_MSG_ERROR("Can't retrieve electron container "<< m_electronContainerKey.key());
189  return StatusCode::FAILURE;
190  }
191 
192  for (auto thisElectron : *electronReadHandle){
193  const std::vector<const xAOD::CaloCluster*> electronTopoClusters = xAOD::EgammaHelpers::getAssociatedTopoClusters(thisElectron->caloCluster());
194  for (auto thisElectronTopoCluster : electronTopoClusters){
195  if (thisElectronTopoCluster->index() == chargedClusterIndex){
196  belongsToElectron = true;
197  break;
198  }
199  }
200  }
201  }
202 
203  if (belongsToElectron) continue;
204 
205  bool belongsToMuon = false;
206  double muonCaloEnergy = 0.0;
207  if (m_removeNeutralMuonFE){
209  std::vector<double> muonCaloEnergies = chargedFE_energy_match_muonReadHandle(*chargedFE);
210  muonCaloEnergy = muonCaloEnergies[iCluster];
211  }
212 
213  if (belongsToMuon) continue;
214 
215  xAOD::FlowElement* newFE = new xAOD::FlowElement();
216  selectedNeutralPFlowObjects->push_back(newFE);
217 
218  newFE->setP4((theClusterWeight_charged - muonCaloEnergy) / cosh(theCluster_charged->eta()), // using energy from charged FE weight, not cluster->e()
219  theCluster_charged->eta(),
220  theCluster_charged->phi(),
221  theCluster_charged->m());
222  newFE->setCharge(0);
223  newFE->setSignalType(xAOD::FlowElement::SignalType::NeutralPFlow);
224 
225  ATH_MSG_DEBUG("Created neutral FlowElement with E, pt, eta and phi: "
226  << newFE->e() << ", " << newFE->pt() << ", "
227  << newFE->eta() << " and " << newFE->phi());
228 
229  std::vector<ElementLink<xAOD::IParticleContainer>> theClusters;
231  theIParticleLink.resetWithKeyAndIndex(theOtherLinks_charged[iCluster].persKey(), theOtherLinks_charged[iCluster].persIndex());
232 
233  theClusters.push_back(theIParticleLink);
234  newFE->setOtherObjectLinks(theClusters);
235 
236  //Add Standard data to these new FlowElements
238  const xAOD::CaloCluster* castCluster_charged = dynamic_cast<const xAOD::CaloCluster*>(theCluster_charged);
239  FEFiller.addStandardMoments(*newFE,*castCluster_charged);
240  FEFiller.addStandardSamplingEnergies(*newFE,*castCluster_charged);
241 
242  float layerEnergy_TileBar0 = castCluster_charged->eSample(xAOD::CaloCluster::CaloSample::TileBar0);
243  float layerEnergy_TileExt0 = castCluster_charged->eSample(xAOD::CaloCluster::CaloSample::TileExt0);
244  const static SG::AuxElement::Accessor<float> accFloatTIle0E("LAYERENERGY_TILE0");
245  accFloatTIle0E(*newFE) = layerEnergy_TileBar0 + layerEnergy_TileExt0;
246 
247  const static SG::AuxElement::Accessor<float> accFloatTiming("TIMING");
248  accFloatTiming(*newFE) = castCluster_charged->time();
249  }
250 
251  } // End loop over topoclusters of removed charged FE objects
252  } // End loop over removed charged FE objects
253 
254 
255  auto handle_ChargedPFlow_out = SG::makeHandle(m_outputChargedPFlowHandleKey, ctx);
256  if (!handle_ChargedPFlow_out.record(std::move(selectedChargedPFlowObjects), std::move(selectedChargedPFlowObjectsAux)) ){
257  ATH_MSG_ERROR("Can't record output PFlow container "<< m_outputChargedPFlowHandleKey);
258  return StatusCode::FAILURE;
259  }
260 
261  auto handle_NeutralPFlow_out = SG::makeHandle(m_outputNeutralPFlowHandleKey, ctx);
262  if (!handle_NeutralPFlow_out.record(std::move(selectedNeutralPFlowObjects), std::move(selectedNeutralPFlowObjectsAux)) ){
263  ATH_MSG_ERROR("Can't record output PFlow container "<< m_outputNeutralPFlowHandleKey);
264  return StatusCode::FAILURE;
265  }
266 
267  return StatusCode::SUCCESS;
268 }
269 
270 bool JetPFlowSelectionAlg::checkElectronLinks(const std::vector < ElementLink< xAOD::ElectronContainer > >& FE_ElectronLinks) const{
271 
272  // Links to electrons
273  for (const ElementLink<xAOD::ElectronContainer>& ElectronLink: FE_ElectronLinks){
274  if (!ElectronLink.isValid()){
275  ATH_MSG_WARNING("JetPFlowSelectionAlg encountered an invalid electron element link. Skipping. ");
276  continue;
277  }
278 
280  bool passElectronID = false;
281  bool gotID = electron->passSelection(passElectronID, m_electronID);
282  if (!gotID) {
283  ATH_MSG_WARNING("Could not get Electron ID");
284  continue;
285  }
286 
287  if( electron->pt() > 10000 && passElectronID){
288  return true;
289  }
290  }
291 
292  return false;
293 }
294 
295 bool JetPFlowSelectionAlg::checkMuonLinks(const std::vector < ElementLink< xAOD::MuonContainer > >& FE_MuonLinks) const{
296 
297  // Links to muons
298  for (const ElementLink<xAOD::MuonContainer>& MuonLink: FE_MuonLinks){
299  if (!MuonLink.isValid()){
300  ATH_MSG_WARNING("JetPFlowSelectionAlg encountered an invalid muon element link. Skipping. ");
301  continue;
302  }
303 
304  //Details of medium muons are here:
305  //https://twiki.cern.ch/twiki/bin/view/Atlas/MuonSelectionTool
306  const xAOD::Muon* muon = *MuonLink;
307  xAOD::Muon::Quality quality = xAOD::Muon::VeryLoose;
308 
309  if (m_muonID == "Loose") quality = xAOD::Muon::Loose;
310  else if (m_muonID == "Medium") quality = xAOD::Muon::Medium;
311  else if (m_muonID == "Tight") quality = xAOD::Muon::Tight;
312 
313  if ( muon->quality() <= quality && muon->muonType() == xAOD::Muon::Combined ){
314  return true;
315  }
316  }
317 
318  return false;
319 }
WriteHandle.h
Handle class for recording to StoreGate.
LikeEnum::Loose
@ Loose
Definition: LikelihoodEnums.h:12
xAOD::CaloCluster_v1::time
flt_t time() const
Access cluster time.
FEHelpers::FillNeutralFlowElements::addStandardSamplingEnergies
void addStandardSamplingEnergies(xAOD::FlowElement &theFE, const xAOD::CaloCluster &theCluster)
Definition: FEHelpers.cxx:246
xAOD::muon
@ muon
Definition: TrackingPrimitives.h:195
MuonLink
ElementLink< xAOD::MuonContainer > MuonLink
Definition: BPhysHelper.cxx:21
JetPFlowSelectionAlg::m_chargedFE_energy_match_muonReadHandleKey
SG::ReadDecorHandleKey< xAOD::FlowElementContainer > m_chargedFE_energy_match_muonReadHandleKey
Definition: JetPFlowSelectionAlg.h:64
xAOD::EgammaHelpers::getAssociatedTopoClusters
std::vector< const xAOD::CaloCluster * > getAssociatedTopoClusters(const xAOD::CaloCluster *cluster)
Return a vector of all the topo clusters associated with the egamma cluster.
Definition: EgammaxAODHelpers.cxx:66
LikeEnum::VeryLoose
@ VeryLoose
Definition: LikelihoodEnums.h:11
FEHelpers::FillNeutralFlowElements::addStandardMoments
void addStandardMoments(xAOD::FlowElement &theFE, const xAOD::CaloCluster &theCluster)
Definition: FEHelpers.cxx:213
JetPFlowSelectionAlg::m_chargedFEElectronsReadDecorKey
SG::ReadDecorHandleKey< xAOD::FlowElementContainer > m_chargedFEElectronsReadDecorKey
Definition: JetPFlowSelectionAlg.h:54
SG::Accessor
Helper class to provide type-safe access to aux data.
Definition: Control/AthContainers/AthContainers/Accessor.h:66
Muon.h
ElectronLink
ElementLink< xAOD::ElectronContainer > ElectronLink
Definition: BPhysHelper.cxx:23
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
CaloCell_ID_FCS::TileExt0
@ TileExt0
Definition: FastCaloSim_CaloCell_ID.h:37
xAOD::FlowElement_v1::setSignalType
void setSignalType(signal_t t)
JetPFlowSelectionAlg::m_electronContainerKey
SG::ReadHandleKey< xAOD::ElectronContainer > m_electronContainerKey
Definition: JetPFlowSelectionAlg.h:48
JetPFlowSelectionAlg::m_outputNeutralPFlowHandleKey
SG::WriteHandleKey< xAOD::FlowElementContainer > m_outputNeutralPFlowHandleKey
Definition: JetPFlowSelectionAlg.h:52
JetPFlowSelectionAlg::m_removeNeutralMuonFE
Gaudi::Property< bool > m_removeNeutralMuonFE
Definition: JetPFlowSelectionAlg.h:44
JetPFlowSelectionAlg::m_ChargedPFlowContainerKey
SG::ReadHandleKey< xAOD::FlowElementContainer > m_ChargedPFlowContainerKey
Definition: JetPFlowSelectionAlg.h:46
xAOD::FlowElement_v1::phi
virtual double phi() const override
The azimuthal angle ( ) of the particle.
xAOD::FlowElement_v1::pt
virtual double pt() const override
SG::VarHandleKey::key
const std::string & key() const
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:141
xAOD::FlowElement_v1::setOtherObjectLinks
void setOtherObjectLinks(const std::vector< ElementLink< IParticleContainer >> &elV)
SG::VarHandleKey::empty
bool empty() const
Test if the key is blank.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:150
xAOD::IParticle
Class providing the definition of the 4-vector interface.
Definition: Event/xAOD/xAODBase/xAODBase/IParticle.h:40
JetPFlowSelectionAlg::m_chargedFEMuonsReadDecorKey
SG::ReadDecorHandleKey< xAOD::FlowElementContainer > m_chargedFEMuonsReadDecorKey
Definition: JetPFlowSelectionAlg.h:55
xAOD::Muon_v1
Class describing a Muon.
Definition: Muon_v1.h:38
JetPFlowSelectionAlg::m_outputChargedPFlowHandleKey
SG::WriteHandleKey< xAOD::FlowElementContainer > m_outputChargedPFlowHandleKey
Definition: JetPFlowSelectionAlg.h:51
xAOD::FlowElement_v1::setCharge
void setCharge(float c)
JetPFlowSelectionAlg::m_NeutralPFlowContainerKey
SG::ReadHandleKey< xAOD::FlowElementContainer > m_NeutralPFlowContainerKey
Definition: JetPFlowSelectionAlg.h:47
FEHelpers::FillNeutralFlowElements
Definition: Event/xAOD/xAODPFlow/xAODPFlow/FEHelpers.h:27
SG::makeHandle
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition: ReadCondHandle.h:269
xAOD::CaloCluster_v1
Description of a calorimeter cluster.
Definition: CaloCluster_v1.h:59
EgammaxAODHelpers.h
JetPFlowSelectionAlg::m_removeNeutralElectronFE
Gaudi::Property< bool > m_removeNeutralElectronFE
Definition: JetPFlowSelectionAlg.h:41
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
FlowElementAuxContainer.h
ParticleGun_FastCalo_ChargeFlip_Config.energy
energy
Definition: ParticleGun_FastCalo_ChargeFlip_Config.py:78
SG::ReadDecorHandle
Handle class for reading a decoration on an object.
Definition: StoreGate/StoreGate/ReadDecorHandle.h:94
FlowElement.h
CaloCell_ID_FCS::TileBar0
@ TileBar0
Definition: FastCaloSim_CaloCell_ID.h:31
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
xAOD::FlowElement
FlowElement_v1 FlowElement
Definition of the current "pfo version".
Definition: FlowElement.h:16
JetPFlowSelectionAlg::checkMuonLinks
bool checkMuonLinks(const std::vector< ElementLink< xAOD::MuonContainer > > &FE_MuonLinks) const
Definition: JetPFlowSelectionAlg.cxx:295
JetPFlowSelectionAlg::m_muonID
Gaudi::Property< std::string > m_muonID
Definition: JetPFlowSelectionAlg.h:43
JetPFlowSelectionAlg::execute
StatusCode execute(const EventContext &ctx) const override
Definition: JetPFlowSelectionAlg.cxx:38
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
SG::AuxElement::index
size_t index() const
Return the index of this element within its container.
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
Trk::Combined
@ Combined
Definition: TrackSummaryTool.h:32
JetPFlowSelectionAlg::checkElectronLinks
bool checkElectronLinks(const std::vector< ElementLink< xAOD::ElectronContainer > > &FE_ElectronLinks) const
Definition: JetPFlowSelectionAlg.cxx:270
JetPFlowSelectionAlg::m_neutralFEMuonsReadDecorKey
SG::ReadDecorHandleKey< xAOD::FlowElementContainer > m_neutralFEMuonsReadDecorKey
Definition: JetPFlowSelectionAlg.h:59
LikeEnum::Tight
@ Tight
Definition: LikelihoodEnums.h:15
JetPFlowSelectionAlg::m_neutralFEMuons_efrac_match_DecorKey
SG::ReadDecorHandleKey< xAOD::FlowElementContainer > m_neutralFEMuons_efrac_match_DecorKey
Definition: JetPFlowSelectionAlg.h:62
FEHelpers.h
ReadHandle.h
Handle class for reading from StoreGate.
xAOD::FlowElement_v1::e
virtual double e() const override
The total energy of the particle.
Definition: FlowElement_v1.cxx:25
JetPFlowSelectionAlg::m_neutralFEElectronsReadDecorKey
SG::ReadDecorHandleKey< xAOD::FlowElementContainer > m_neutralFEElectronsReadDecorKey
Definition: JetPFlowSelectionAlg.h:57
xAOD::Electron_v1
Definition: Electron_v1.h:34
xAOD::FlowElement_v1::eta
virtual double eta() const override
The pseudorapidity ( ) of the particle.
xAOD::CaloCluster_v1::eSample
float eSample(const CaloSample sampling) const
Definition: CaloCluster_v1.cxx:521
LikeEnum::Medium
@ Medium
Definition: LikelihoodEnums.h:14
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
xAOD::IParticle::eta
virtual double eta() const =0
The pseudorapidity ( ) of the particle.
ReadDecorHandle.h
Handle class for reading a decoration on an object.
xAOD::EgammaParameters::electron
@ electron
Definition: EgammaEnums.h:18
xAOD::FlowElement_v1::setP4
void setP4(float pt, float eta, float phi, float m)
Definition: FlowElement_v1.cxx:39
Electron.h
xAOD::IParticle::phi
virtual double phi() const =0
The azimuthal angle ( ) of the particle.
JetPFlowSelectionAlg.h
JetPFlowSelectionAlg::m_electronID
Gaudi::Property< std::string > m_electronID
Definition: JetPFlowSelectionAlg.h:40
JetPFlowSelectionAlg::initialize
StatusCode initialize() override
Athena algorithm's Hooks.
Definition: JetPFlowSelectionAlg.cxx:17
xAOD::IParticle::e
virtual double e() const =0
The total energy of the particle.
xAOD::IParticle::m
virtual double m() const =0
The invariant mass of the particle.
xAOD::FlowElement_v1
A detector object made of other lower level object(s)
Definition: FlowElement_v1.h:25