ATLAS Offline Software
Loading...
Searching...
No Matches
ChargedHadronSubtractionTool.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef JETRECTOOLS_CHARGEDHADRONSUBTRACTIONTOOL_H
6#define JETRECTOOLS_CHARGEDHADRONSUBTRACTIONTOOL_H
7
15
16#include <string>
19
26
28
29
32
33 public:
34
35 ChargedHadronSubtractionTool(const std::string& name);
36
37 // Check that the configuration is reasonable
38 StatusCode initialize();
39
40 private:
41 // Implement the correction
42 StatusCode process_impl(xAOD::IParticleContainer* cont) const;
43 template <class T, class U> StatusCode matchToPrimaryVertex(T &) const;
44 template <class T, class U> StatusCode matchByPrimaryVertex(T &) const;
45
46 const xAOD::Vertex* getPrimaryVertex() const;
47
48 // properties -----------------
49
50 Gaudi::Property<bool> m_useTrackToVertexTool = {this, "UseTrackToVertexTool", false, "True if we will use the track to vertex tool"};
51 Gaudi::Property<bool> m_ignoreVertex = {this, "IgnoreVertex", false, "Dummy option for cosmics - accept everything"};
52 Gaudi::Property<float> m_z0sinThetaCutValue = {this, "Z0sinThetaCutValue", 2.0, "True if we will use the track to vertex tool"};
53 Gaudi::Property<bool> m_byVertex = {this, "DoByVertex", false, "True if we should match to each primary vertex, not just PV0"};
54
55 static double calcAbsZ0SinTheta(const xAOD::TrackParticle& trk, const xAOD::Vertex& vtx);
56
57 SG::ReadHandleKey<xAOD::VertexContainer> m_vertexContainer_key = {this, "VertexContainerKey", "PrimaryVertices", "key for the primary vertex container"};
58 SG::ReadHandleKey<jet::TrackVertexAssociation> m_trkVtxAssoc_key = {this, "TrackVertexAssociation", "JetTrackVtxAssoc", "key for the TrackVertexAssociation object"};
59
60
61
62};
63
64
65template <class T, class U> StatusCode ChargedHadronSubtractionTool::matchToPrimaryVertex(T& cont) const
66{
67 const static SG::AuxElement::Accessor<char> PVMatchedAcc("matchedToPV");
68 const static SG::AuxElement::Accessor<char> PUsidebandMatchedAcc("matchedToPUsideband");
69
70 // Use only one of TVA or PV
71 const jet::TrackVertexAssociation *trkVtxAssoc = nullptr;
72 const xAOD::Vertex *vtx = nullptr;
73 if (!m_ignoreVertex)
74 {
75 // In cosmics, there's no PV container so we need to avoid attempting
76 // to retrieve anything related to it
78 {
79 auto handle = SG::makeHandle(m_trkVtxAssoc_key);
80 if (!handle.isValid())
81 {
82 ATH_MSG_ERROR("Can't retrieve TrackVertexAssociation : " << m_trkVtxAssoc_key.key());
83 return StatusCode::FAILURE;
84 }
85 trkVtxAssoc = handle.cptr();
86 }
87 else
88 {
89 vtx = getPrimaryVertex();
90 if (vtx == nullptr)
91 {
92 ATH_MSG_ERROR("Primary vertex container was empty or no valid vertex found!");
93 return StatusCode::FAILURE;
94 }
95 else if (vtx->vertexType() == xAOD::VxType::NoVtx)
96 {
97 ATH_MSG_VERBOSE("No genuine primary vertex found. Will consider all PFOs matched.");
98 }
99 }
100 }
101
102 for (U *ppfo : cont)
103 {
104 // Ignore neutral PFOs
105 if constexpr (std::is_same_v<U, xAOD::PFO>) {
106 if (std::abs(ppfo->charge()) < FLT_MIN)
107 continue;
108 } else if constexpr (std::is_same_v<U, xAOD::FlowElement>) {
109 if (!ppfo->isCharged())
110 continue;
111 }
112
113 bool matchedToPrimaryVertex = false;
114 bool matchedToPileupSideband = false;
115 if (m_ignoreVertex)
116 {
117 // If we don't use vertex information, don't bother computing the decision
118 // Just pass every cPFO -- there shouldn't be many in cosmics!
119 matchedToPrimaryVertex = true;
120 }
121 else
122 {
123 const xAOD::TrackParticle* ptrk = nullptr;
124
125 // Use different methods to get TrackParticle based on U
126 if constexpr (std::is_same_v<U, xAOD::PFO>) {
127 ptrk = ppfo->track(0);
128 } else if constexpr (std::is_same_v<U, xAOD::FlowElement>) {
129 ptrk = dynamic_cast<const xAOD::TrackParticle*>(ppfo->chargedObject(0));
130 }
131 if (ptrk == nullptr)
132 {
133 ATH_MSG_WARNING("Charged PFO with index " << ppfo->index() << " has no ID track!");
134 continue;
135 }
136 if (trkVtxAssoc)
137 { // Use TrackVertexAssociation
138 const xAOD::Vertex *thisTracksVertex = trkVtxAssoc->associatedVertex(ptrk);
139 if (thisTracksVertex == nullptr)
140 {
141 ATH_MSG_DEBUG("No vertex associated to track " << ptrk->index() << "! So it cannot be associated to the primary vertex");
142 matchedToPrimaryVertex = false;
143 }
144 else
145 {
146 matchedToPrimaryVertex = (xAOD::VxType::PriVtx == thisTracksVertex->vertexType());
147
148 // r21 PU sideband definition (see below)
149 // needed for comparisons with new r22 definition (neutral only)
150 vtx = getPrimaryVertex();
151 if (vtx != nullptr && vtx->vertexType() != xAOD::VxType::NoVtx)
152 {
153 const double absZ0sinTheta = calcAbsZ0SinTheta(*ptrk, *vtx);
154 if (absZ0sinTheta < 2.0 * m_z0sinThetaCutValue && absZ0sinTheta >= m_z0sinThetaCutValue)
155 matchedToPileupSideband = true;
156 }
157 }
158 }
159 else
160 { // Use Primary Vertex
161 if (vtx->vertexType() == xAOD::VxType::NoVtx)
162 { // No reconstructed vertices
163 matchedToPrimaryVertex = true; // simply match all cPFOs in this case
164 }
165 else
166 { // Had a good reconstructed vertex.
167 // vtz.z() provides z of that vertex w.r.t the center of the beamspot (z = 0).
168 // Thus we correct the track z0 to be w.r.t z = 0
169 float z0 = ptrk->z0() + ptrk->vz() - vtx->z();
170 float theta = ptrk->theta();
171 matchedToPrimaryVertex = (std::abs(z0 * sin(theta)) < m_z0sinThetaCutValue);
172 if (std::abs(z0 * sin(theta)) < 2.0 * m_z0sinThetaCutValue && std::abs(z0 * sin(theta)) >= m_z0sinThetaCutValue)
173 matchedToPileupSideband = true;
174 }
175 } // TVA vs PV decision
176 }
177 PVMatchedAcc(*ppfo) = matchedToPrimaryVertex;
178 PUsidebandMatchedAcc(*ppfo) = matchedToPileupSideband;
179 }
180
181 return StatusCode::SUCCESS;
182}
183
184template <class T, class U> StatusCode ChargedHadronSubtractionTool::matchByPrimaryVertex(T& cont) const
185{
186 const static SG::AuxElement::Accessor<std::vector<unsigned>> matchingPVs("MatchingPVs");
187 const static SG::AuxElement::Accessor<std::vector<unsigned>> matchingPUSBs("MatchingPUsidebands");
188
189 // Retrieve Primary Vertices
191 if (!handle.isValid())
192 {
193 ATH_MSG_WARNING(" This event has no primary vertex container");
194 return StatusCode::FAILURE;
195 }
196
197 const xAOD::VertexContainer *pvtxs = handle.cptr();
198 if (pvtxs->empty())
199 {
200 ATH_MSG_WARNING(" Failed to retrieve valid primary vertex container");
201 return StatusCode::FAILURE;
202 }
203
204 // Use only one of TVA or PV
205 const jet::TrackVertexAssociation *trkVtxAssoc = nullptr;
207 {
208 auto handle = SG::makeHandle(m_trkVtxAssoc_key);
209 if (!handle.isValid())
210 {
211 ATH_MSG_ERROR("Can't retrieve TrackVertexAssociation : " << m_trkVtxAssoc_key.key());
212 return StatusCode::FAILURE;
213 }
214 trkVtxAssoc = handle.cptr();
215 }
216
217 for (U *ppfo : cont)
218 {
219 // Ignore neutral PFOs
220 if constexpr (std::is_same_v<U, xAOD::PFO>) {
221 if (std::abs(ppfo->charge()) < FLT_MIN)
222 continue;
223 } else if constexpr (std::is_same_v<U, xAOD::FlowElement>) {
224 if (!ppfo->isCharged())
225 continue;
226 }
227
228 // Get the track for this charged PFO
229 const xAOD::TrackParticle* ptrk = nullptr;
230
231 // Use different methods to get TrackParticle based on U
232 if constexpr (std::is_same_v<U, xAOD::PFO>) {
233 ptrk = ppfo->track(0);
234 } else if constexpr (std::is_same_v<U, xAOD::FlowElement>) {
235 ptrk = dynamic_cast<const xAOD::TrackParticle*>(ppfo->chargedObject(0));
236 }
237 if (ptrk == nullptr)
238 {
239 ATH_MSG_WARNING("Charged PFO with index " << ppfo->index() << " has no ID track!");
240 continue;
241 }
242
243 std::vector<unsigned> matchingVertexList;
244 std::vector<unsigned> matchingPUSBList;
245
246 if (trkVtxAssoc)
247 {
248 // Use TrackVertexAssociation
249 const xAOD::Vertex *thisTracksVertex = trkVtxAssoc->associatedVertex(ptrk);
250 if (thisTracksVertex == nullptr)
251 {
252 ATH_MSG_DEBUG("No vertex associated to track " << ptrk->index() << "! So it cannot be associated to the primary vertex");
253 }
254 else
255 {
256 matchingVertexList.push_back(thisTracksVertex->index());
257 for (const xAOD::Vertex *vtx : *pvtxs){
258 if (vtx != nullptr && vtx->vertexType() != xAOD::VxType::NoVtx)
259 {
260 float z0 = ptrk->z0() + ptrk->vz() - vtx->z();
261 float theta = ptrk->theta();
262
263 if (std::abs(z0 * sin(theta)) < 2.0 * m_z0sinThetaCutValue && std::abs(z0 * sin(theta)) >= m_z0sinThetaCutValue)
264 matchingPUSBList.push_back(vtx->index());
265 }
266 }
267 }
268 }
269 else{
270 // Use z0sinThetaCutValue
271 // Loop over the primary vertices to determine which ones potentially match
272 for (const xAOD::Vertex *vtx : *pvtxs)
273 {
274 bool matchedToVertex = false;
275 bool matchedToPileupSideband = false;
276
277 if (vtx == nullptr)
278 {
279 ATH_MSG_WARNING("Encountered a nullptr vertex when trying to match charged PFOs to vertices");
280 continue;
281 }
282 else if (vtx->vertexType() == xAOD::VxType::NoVtx)
283 { // No reconstructed vertices
284 matchedToVertex = true; // simply match all cPFOs in this case
285 }
286 else
287 { // Had a good reconstructed vertex
288 const double absZ0sinTheta = calcAbsZ0SinTheta(*ptrk, *vtx);
289 matchedToVertex = (absZ0sinTheta < m_z0sinThetaCutValue);
290 if (absZ0sinTheta < 2.0 * m_z0sinThetaCutValue && absZ0sinTheta >= m_z0sinThetaCutValue)
291 matchedToPileupSideband = true;
292 }
293
294 if (matchedToVertex)
295 matchingVertexList.push_back(vtx->index());
296 if (matchedToPileupSideband)
297 matchingPUSBList.push_back(vtx->index());
298 }
299 }
300
301 matchingPVs(*ppfo) = matchingVertexList;
302 matchingPUSBs(*ppfo) = matchingPUSBList;
303 }
304
305 return StatusCode::SUCCESS;
306}
307
308#endif
Scalar theta() const
theta method
#define ASG_TOOL_CLASS(CLASSNAME, INT1)
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Property holding a SG store/key/clid from which a ReadHandle is made.
ChargedHadronSubtractionTool(const std::string &name)
StatusCode initialize()
Dummy implementation of the initialisation function.
static double calcAbsZ0SinTheta(const xAOD::TrackParticle &trk, const xAOD::Vertex &vtx)
SG::ReadHandleKey< jet::TrackVertexAssociation > m_trkVtxAssoc_key
const xAOD::Vertex * getPrimaryVertex() const
Gaudi::Property< bool > m_useTrackToVertexTool
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexContainer_key
Gaudi::Property< float > m_z0sinThetaCutValue
StatusCode process_impl(xAOD::IParticleContainer *cont) const
bool empty() const noexcept
Returns true if the collection is empty.
JetConstituentModifierBase(const std::string &name)
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
size_t index() const
Return the index of this element within its container.
Property holding a SG store/key/clid from which a ReadHandle is made.
Class to hold N-to-one aassociations between tracks and vertices.
const xAOD::Vertex * associatedVertex(const xAOD::TrackParticle *trk) const
float z0() const
Returns the parameter.
float theta() const
Returns the parameter, which has range 0 to .
const Trk::Track * track() const
Returns a pointer (which can be NULL) to the Trk::Track which was used to make this TrackParticle.
float vz() const
The z origin for the parameters.
float z() const
Returns the z position.
VxType::VertexType vertexType() const
The type of the vertex.
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
@ PriVtx
Primary vertex.
@ NoVtx
Dummy vertex. TrackParticle was not used in vertex fit.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.