ATLAS Offline Software
CorrectPFOTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // CorrectPFOTool.cxx
6 
8 #include "PFlowUtils/FEHelpers.h"
10 
11 #include <cmath>
12 
15  m_weightPFOTool("",this) {
16 
17  // Configuration
18  declareProperty("WeightPFOTool", m_weightPFOTool, "Name of tool that extracts the cPFO weights.");
19  declareProperty("InputIsEM", m_inputIsEM = true, "True if neutral PFOs are EM scale clusters.");
20  declareProperty("CalibratePFO", m_calibrate = false, "True if LC calibration should be applied to EM PFOs.");
21  declareProperty("CorrectNeutral", m_correctneutral = true, "True to use the neutral component of PFlow.");
22  declareProperty("CorrectCharged", m_correctcharged = true, "True if use the charged component of PFlow.");
23  declareProperty("UseChargedWeights",m_useChargedWeights = true, "True if we make use of weighting scheme for charged PFO");
24  declareProperty("DoByVertex", m_doByVertex = false, "True to add vertex-by-vertex corrections for neutral PFOs");
25 
26  // Input properties
27  declareProperty("VertexContainerKey",
28  m_vertexContainer_key="PrimaryVertices",
29  "Datahandle key for the primary vertex container");
30 }
31 
34  ATH_MSG_ERROR("This tool is configured to do nothing!");
35  return StatusCode::FAILURE;
36  }
38  ATH_MSG_ERROR("CorrectPFOTool requires PFO inputs. It cannot operate on objects of type "
39  << m_inputType);
40  return StatusCode::FAILURE;
41  }
43  ATH_CHECK( m_weightPFOTool.retrieve() );
44  }
45  ATH_CHECK( m_vertexContainer_key.initialize() );
46 
47  ATH_MSG_INFO("Running CorrectPFOTool by vertex:" << m_doByVertex);
48  return StatusCode::SUCCESS;
49 }
50 
52  // Type-checking happens in the JetConstituentModifierBase class
53  // so it is safe just to static_cast
55  xAOD::FlowElementContainer* feCont = static_cast<xAOD::FlowElementContainer*>(cont);
56  if(!feCont->empty() && !(feCont->front()->signalType() & xAOD::FlowElement::PFlow)){
57  ATH_MSG_ERROR("CorrectPFOTool received FlowElements that aren't PFOs");
58  return StatusCode::FAILURE;
59  }
60  return m_doByVertex ? correctPFOByVertex(*feCont) : correctPFO(*feCont);
61  }
62  xAOD::PFOContainer* pfoCont = static_cast<xAOD::PFOContainer*> (cont);
63  return m_doByVertex ? correctPFOByVertex(*pfoCont) : correctPFO(*pfoCont);
64 }
65 
67  // Retrieve Primary Vertices
69  if (!handle.isValid()){
70  ATH_MSG_WARNING(" This event has no primary vertex container" );
71  return nullptr;
72  }
73 
74  const xAOD::VertexContainer* pvtxs = handle.cptr();
75  if(pvtxs->empty()){
76  ATH_MSG_WARNING(" Failed to retrieve valid primary vertex container" );
77  return nullptr;
78  }
79 
80  //Usually the 0th vertex is the primary one, but this is not always
81  // the case. So we will choose the first vertex of type PriVtx
82  for (const auto *theVertex : *pvtxs) {
83  if (theVertex->vertexType()==xAOD::VxType::PriVtx) {
84  return theVertex;
85  }//If we have a vertex of type primary vertex
86  }//iterate over the vertices and check their type
87 
88  // If we failed to find an appropriate vertex, return the dummy vertex
89  ATH_MSG_DEBUG("Could not find a primary vertex in this event " );
90  for (const auto *theVertex : *pvtxs) {
91  if (theVertex->vertexType()==xAOD::VxType::NoVtx) {
92  return theVertex;
93  }
94  }
95 
96  // If there is no primary vertex, then we cannot do PV matching.
97  ATH_MSG_WARNING("Primary vertex container was empty");
98  return nullptr;
99 }
100 
102 
103  const xAOD::Vertex* vtx = nullptr;
104  if(m_correctneutral) {
105  vtx = getPrimaryVertex();
106  if(vtx==nullptr) {
107  ATH_MSG_ERROR("Primary vertex container was empty or no valid vertex found!");
108  return StatusCode::FAILURE;
109  } else if (vtx->vertexType()==xAOD::VxType::NoVtx) {
110  ATH_MSG_VERBOSE("No genuine primary vertex found. Will not apply origin correction");
111  }
112  }
113 
114  for ( xAOD::PFO* ppfo : cont ) {
115 
116  if ( std::abs(ppfo->charge())<FLT_MIN) { // Neutral PFOs
117  if(m_correctneutral) {
118  ATH_CHECK( applyNeutralCorrection(*ppfo, *vtx) );
119  }
120  } else { // Charged PFOs
121  if(m_correctcharged) {
123  }
124  }
125  } // PFO loop
126 
127  return StatusCode::SUCCESS;
128 }
129 
131 
132  const xAOD::Vertex* vtx = nullptr;
133  if(m_correctneutral) {
134  vtx = getPrimaryVertex();
135  if(vtx==nullptr) {
136  ATH_MSG_ERROR("Primary vertex container was empty or no valid vertex found!");
137  return StatusCode::FAILURE;
138  } else if (vtx->vertexType()==xAOD::VxType::NoVtx) {
139  ATH_MSG_VERBOSE("No genuine primary vertex found. Will not apply origin correction");
140  }
141  }
142 
143  for ( xAOD::FlowElement* ppfo : cont ) {
144 
145  if ( !ppfo->isCharged()) { // Neutral PFOs
146  if(m_correctneutral) {
147  ATH_CHECK( applyNeutralCorrection(*ppfo, *vtx) );
148  }
149  } else { // Charged PFOs
150  if(m_correctcharged) {
152  }
153  }
154  } // PFO loop
155 
156  return StatusCode::SUCCESS;
157 }
158 
160  static const SG::AuxElement::Accessor<unsigned> copyIndex("ConstituentCopyIndex");
161  // Retrieve Primary Vertices
162  auto handle = SG::makeHandle(m_vertexContainer_key);
163  if (!handle.isValid()){
164  ATH_MSG_WARNING(" This event has no primary vertex container" );
165  return StatusCode::FAILURE;
166  }
167 
168  const xAOD::VertexContainer* pvtxs = handle.cptr();
169  if(pvtxs->empty()){
170  ATH_MSG_WARNING(" Failed to retrieve valid primary vertex container" );
171  return StatusCode::FAILURE;
172  }
173 
174  for ( xAOD::PFO* ppfo : cont ) {
175 
176  if ( std::abs(ppfo->charge())<FLT_MIN) { // Neutral PFOs
177  if(m_correctneutral) {
178  // Neutral PFOs - there are copies, one per vertex, already created
179  // We need to now need to correct each copy to point to the corresponding vertex
180  if (!copyIndex.isAvailable(*ppfo))
181  {
182  ATH_MSG_WARNING("Encountered a neutral per-vertex PFO object without the corresponding vertex index attribute");
183  continue;
184  }
185 
186  const unsigned iVtx = copyIndex(*ppfo);
187  if (iVtx >= pvtxs->size())
188  {
189  ATH_MSG_WARNING("Encountered a neutral per-vertex PFO object with an index beyond the size of the vertex container");
190  continue;
191  }
192  const xAOD::Vertex* vtx = pvtxs->at(iVtx);
193  // Determine the correct four-vector interpretation for a neutral PFO associated with this vertex
194  // Cannot use applyNeutralCorrection as that only used VxType::PriVtx, but we want to apply to all primary vertices
195  // As such, extract the relevant parts and modify appropriately here
196  // This is necessary to avoid changing sign of pT for pT<0 PFO
197  if (ppfo->e() < FLT_MIN) {
198  ppfo->setP4(0, 0, 0, 0);
199  }
200  if (!m_inputIsEM || m_calibrate) { // Use LC four-vector
201  ppfo->setP4(ppfo->GetVertexCorrectedFourVec(*vtx));
202  } else { // Use EM four-vector
203  ppfo->setP4(ppfo->GetVertexCorrectedEMFourVec(*vtx));
204  }
205  }
206  } else { // Charged PFOs
207  if(m_correctcharged) {
209  }
210  }
211  } // PFO loop
212 
213 
214  return StatusCode::SUCCESS;
215 }
216 
218  static const SG::AuxElement::Accessor<unsigned> copyIndex("ConstituentCopyIndex");
219 
220  // Retrieve Primary Vertices
221  auto handle = SG::makeHandle(m_vertexContainer_key);
222  if (!handle.isValid()){
223  ATH_MSG_WARNING(" This event has no primary vertex container" );
224  return StatusCode::FAILURE;
225  }
226 
227  const xAOD::VertexContainer* pvtxs = handle.cptr();
228  if(pvtxs->empty()){
229  ATH_MSG_WARNING(" Failed to retrieve valid primary vertex container" );
230  return StatusCode::FAILURE;
231  }
232 
233  for ( xAOD::FlowElement* ppfo : cont ) {
234 
235  if ( !ppfo->isCharged()) { // Neutral PFOs
236  if(m_correctneutral) {
237  // Neutral PFOs - there are copies, one per vertex, already created
238  // We need to now need to correct each copy to point to the corresponding vertex
239  if (!copyIndex.isAvailable(*ppfo))
240  {
241  ATH_MSG_WARNING("Encountered a neutral per-vertex PFO object without the corresponding vertex index attribute");
242  continue;
243  }
244 
245  const unsigned iVtx = copyIndex(*ppfo);
246  if (iVtx >= pvtxs->size())
247  {
248  ATH_MSG_WARNING("Encountered a neutral per-vertex PFO object with an index beyond the size of the vertex container");
249  continue;
250  }
251  const xAOD::Vertex* vtx = pvtxs->at(iVtx);
252  // Determine the correct four-vector interpretation for a neutral PFO associated with this vertex
253  // Cannot use applyNeutralCorrection as that only used VxType::PriVtx, but we want to apply to all primary vertices
254  // As such, extract the relevant parts and modify appropriately here
255  // This is necessary to avoid changing sign of pT for pT<0 PFO
256  if (ppfo->e() < FLT_MIN) {
257  ppfo->setP4(0, 0, 0, 0);
258  }
259  ppfo->setP4(FEHelpers::getVertexCorrectedFourVec(*ppfo, *vtx));
260  }
261  } else { // Charged PFOs
262  if(m_correctcharged) {
264  }
265  }
266  } // PFO loop
267 
268 
269  return StatusCode::SUCCESS;
270 }
271 
272 
274  if (pfo.e() < FLT_MIN) { //This is necessary to avoid changing sign of pT for pT<0 PFO
275  pfo.setP4(0,0,0,0);
276  } else {
277  if ( !m_inputIsEM || m_calibrate ) { // Use LC four-vector
278  // Only correct if we really reconstructed a vertex
279  if(vtx.vertexType()==xAOD::VxType::PriVtx) {
280  pfo.setP4(pfo.GetVertexCorrectedFourVec(vtx));
281  }
282  } else { // Use EM four-vector
283  // Only apply origin correction if we really reconstructed a vertex
284  if(vtx.vertexType()==xAOD::VxType::PriVtx) {
285  pfo.setP4(pfo.GetVertexCorrectedEMFourVec(vtx));
286  } else {pfo.setP4(pfo.p4EM());} // Just set EM 4-vec
287  }
288  }
289  return StatusCode::SUCCESS;
290 }
291 
293  if (pfo.e() < FLT_MIN) { //This is necessary to avoid changing sign of pT for pT<0 PFO
294  pfo.setP4(0,0,0,0);
295  }
296  // Only apply origin correction if we really reconstructed a vertex
297  else if(vtx.vertexType() == xAOD::VxType::PriVtx) {
299  }
300  return StatusCode::SUCCESS;
301 }
302 
304  if (m_useChargedWeights) {
305  float weight = 0.0;
306  ATH_CHECK( m_weightPFOTool->fillWeight( pfo, weight ) );
307  ATH_MSG_VERBOSE("Fill pseudojet for CPFO with weighted pt: " << pfo.pt()*weight);
308  pfo.setP4(pfo.p4()*weight);
309  }//if should use charged PFO weighting scheme
310  return StatusCode::SUCCESS;
311 }
312 
314  if (m_useChargedWeights) {
315  float weight = 0.0;
316  ATH_CHECK( m_weightPFOTool->fillWeight( pfo, weight ) );
317  ATH_MSG_VERBOSE("Fill pseudojet for CPFO with weighted pt: " << pfo.pt()*weight);
318  pfo.setP4(pfo.p4()*weight);
319  }//if should use charged PFO weighting scheme
320  return StatusCode::SUCCESS;
321 }
CorrectPFOTool::CorrectPFOTool
CorrectPFOTool(const std::string &name)
Definition: CorrectPFOTool.cxx:13
CorrectPFOTool::m_vertexContainer_key
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexContainer_key
Definition: CorrectPFOTool.h:66
FEHelpers.h
xAOD::PFO_v1::pt
virtual double pt() const
The transverse momentum ( ) of the particle.
Definition: PFO_v1.cxx:52
CorrectPFOTool::m_inputIsEM
bool m_inputIsEM
Definition: CorrectPFOTool.h:58
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
SG::Accessor
Helper class to provide type-safe access to aux data.
Definition: Control/AthContainers/AthContainers/Accessor.h:66
CorrectPFOTool::m_weightPFOTool
ToolHandle< CP::IWeightPFOTool > m_weightPFOTool
Definition: CorrectPFOTool.h:64
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
CorrectPFOTool::correctPFO
StatusCode correctPFO(xAOD::PFOContainer &cont) const
Definition: CorrectPFOTool.cxx:101
CorrectPFOTool.h
CorrectPFOTool::m_calibrate
bool m_calibrate
If true EM clusters are used for neutral PFOs.
Definition: CorrectPFOTool.h:59
xAOD::FlowElement_v1::pt
virtual double pt() const override
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
xAOD::Vertex_v1::vertexType
VxType::VertexType vertexType() const
The type of the vertex.
xAOD::VxType::NoVtx
@ NoVtx
Dummy vertex. TrackParticle was not used in vertex fit.
Definition: TrackingPrimitives.h:570
xAOD::PFO_v1::GetVertexCorrectedFourVec
TLorentzVector GetVertexCorrectedFourVec(const xAOD::Vertex &vertexToCorrectTo) const
Correct 4-vector to point at a vertex.
Definition: PFO_v1.cxx:722
xAOD::PFO_v1::p4EM
FourMom_t p4EM() const
get EM scale 4-vector
Definition: PFO_v1.cxx:144
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:200
xAOD::FlowElement_v1::PFlow
@ PFlow
Definition: FlowElement_v1.h:45
SG::makeHandle
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition: ReadCondHandle.h:269
xAOD::PFO_v1::e
virtual double e() const
The total energy of the particle.
Definition: PFO_v1.cxx:81
CorrectPFOTool::getPrimaryVertex
const xAOD::Vertex * getPrimaryVertex() const
Definition: CorrectPFOTool.cxx:66
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
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
xAOD::VxType::PriVtx
@ PriVtx
Primary vertex.
Definition: TrackingPrimitives.h:571
DataVector::front
const T * front() const
Access the first element in the collection as an rvalue.
xAOD::PFO_v1::p4
virtual FourMom_t p4() const
The full 4-momentum of the particle.
Definition: PFO_v1.cxx:95
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
xAODType::ParticleFlow
@ ParticleFlow
The object is a particle-flow object.
Definition: ObjectType.h:41
CorrectPFOTool::process_impl
StatusCode process_impl(xAOD::IParticleContainer *cont) const override final
Definition: CorrectPFOTool.cxx:51
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
CorrectPFOTool::m_correctcharged
bool m_correctcharged
Definition: CorrectPFOTool.h:61
CorrectPFOTool::correctPFOByVertex
StatusCode correctPFOByVertex(xAOD::PFOContainer &cont) const
Definition: CorrectPFOTool.cxx:159
CorrectPFOTool::applyChargedCorrection
StatusCode applyChargedCorrection(xAOD::PFO &pfo) const
Definition: CorrectPFOTool.cxx:303
CorrectPFOTool::initialize
StatusCode initialize() override final
Dummy implementation of the initialisation function.
Definition: CorrectPFOTool.cxx:32
xAOD::PFO_v1
Class describing a particle flow object.
Definition: PFO_v1.h:35
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
JetConstituentModifierBase
Definition: JetConstituentModifierBase.h:22
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
CorrectPFOTool::m_doByVertex
bool m_doByVertex
Definition: CorrectPFOTool.h:63
xAOD::PFO_v1::setP4
void setP4(const FourMom_t &vec)
set the 4-vec
Definition: PFO_v1.cxx:107
JetConstituentModifierBase::m_inputType
unsigned int m_inputType
Definition: JetConstituentModifierBase.h:60
xAOD::FlowElement_v1::p4
virtual FourMom_t p4() const override
The full 4-momentum of the particle.
Definition: FlowElement_v1.cxx:33
CorrectPFOTool::applyNeutralCorrection
StatusCode applyNeutralCorrection(xAOD::PFO &pfo, const xAOD::Vertex &vtx) const
Definition: CorrectPFOTool.cxx:273
xAOD::Vertex_v1
Class describing a Vertex.
Definition: Vertex_v1.h:42
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
xAOD::FlowElement_v1::setP4
void setP4(float pt, float eta, float phi, float m)
Definition: FlowElement_v1.cxx:39
CorrectPFOTool::m_correctneutral
bool m_correctneutral
If true, EM PFOs are calibrated to LC.
Definition: CorrectPFOTool.h:60
SG::ConstAccessor< T, AuxAllocator_t< T > >::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
DataVector::at
const T * at(size_type n) const
Access an element, as an rvalue.
CorrectPFOTool::m_useChargedWeights
bool m_useChargedWeights
Definition: CorrectPFOTool.h:62
xAOD::PFO_v1::GetVertexCorrectedEMFourVec
TLorentzVector GetVertexCorrectedEMFourVec(const xAOD::Vertex &vertexToCorrectTo) const
Correct EM scale 4-vector to point at a vertex.
Definition: PFO_v1.cxx:737
FEHelpers::getVertexCorrectedFourVec
TLorentzVector getVertexCorrectedFourVec(const xAOD::FlowElement &fe, const xAOD::Vertex &vertexToCorrectTo)
Definition: FEHelpers.cxx:13
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
DataVector::empty
bool empty() const noexcept
Returns true if the collection is empty.
xAOD::FlowElement_v1
A detector object made of other lower level object(s)
Definition: FlowElement_v1.h:25