ATLAS Offline Software
Loading...
Searching...
No Matches
AdaptiveMultiVertexFitter.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
5/***************************************************************************
6 AdaptiveMultiVertexFitter.cxx - Description in header file
7 ***************************************************************************/
8
10//
15// xAOD Includes
16#include "xAODTracking/Vertex.h"
17//
18// STL
19#include <algorithm> //std::find
20#include <limits>
21#include <numeric> //accumulate, reduce etc
22
23namespace Trk {
24
26 const std::string& n,
27 const IInterface* p)
28 : AthAlgTool(t, n, p)
29 , m_maxIterations(30)
31 , m_initialError(0.0001)
32 , m_doSmoothing(false)
33 , m_minweight(0.001)
34 , m_maxRelativeShift(0.01)
35{
36 declareProperty("MaxIterations", m_maxIterations);
37 declareProperty("MaxDistToLinPoint", m_maxDistToLinPoint);
38 declareProperty("InitialError", m_initialError);
39 declareProperty("DoSmoothing", m_doSmoothing);
40 declareProperty("MinWeight", m_minweight);
41 declareProperty("MaxRelativeShift", m_maxRelativeShift);
42 declareInterface<AdaptiveMultiVertexFitter>(this);
43}
44
46
47StatusCode
49{
53 ATH_CHECK(m_VertexUpdator.retrieve());
54 // loading smoother in case required
55 if (m_doSmoothing)
56 ATH_CHECK(m_VertexSmoother.retrieve());
57 ATH_CHECK(m_AnnealingMaker.retrieve());
58 ATH_MSG_VERBOSE("Initialize successful");
59 return StatusCode::SUCCESS;
60}
61
62StatusCode
64{
65 ATH_MSG_VERBOSE("Finalize successful");
66 return StatusCode::SUCCESS;
67}
68
69void
70AdaptiveMultiVertexFitter::fit(std::vector<xAOD::Vertex*>& allVertices) const
71{
72 // TODO: put this in a better place
73 // Prepare objects needed to add MVF auxdata to the xAOD::Vertex
74 // For optimization of access speed
75 static const xAOD::Vertex::Accessor<MvfFitInfo*> MvfFitInfo("MvfFitInfo");
76 static const xAOD::Vertex::Accessor<bool> isInitialized("isInitialized");
78 "VTAV");
79 ATH_MSG_DEBUG(" Now fitting all vertices ");
80 // create a vector of vertices, to store the old position...
81 std::map<xAOD::Vertex*, Amg::Vector3D> oldpositions;
82 std::map<xAOD::Vertex*, bool> relinearizations;
83 // count number of steps
84 int num_steps(0);
85 // reset the annealing
87 m_AnnealingMaker->reset(astate);
88 ATH_MSG_DEBUG("Entering cycle of AdaptiveMultiVertexFitter");
89 bool shiftIsSmall(true);
90 // now start to iterate
91 do {
92 for (auto* pThisVertex : allVertices) {
93 // now store all the "old positions"; if vertex is added for the first
94 // time this corresponds to the seed (at the same time fitted vertex will
95 // be updated with the constraint information) check if you need to
96 // reestimate compatibility + linearization
97 ATH_MSG_DEBUG("Now considering candidate with ptr " << pThisVertex);
98 relinearizations[pThisVertex] = false;
99 if (isInitialized(*pThisVertex)) {
100 ATH_MSG_DEBUG("vertex position z: " << (*pThisVertex).position()[2]);
101 oldpositions[pThisVertex] = pThisVertex->position();
102 } else {
103 isInitialized(*pThisVertex) = true;
104 ATH_MSG_DEBUG("Candidate has no position so far: using as old position "
105 "the seedVertex");
106 if (MvfFitInfo(*pThisVertex)->seedVertex() ==
107 nullptr) { // TODO: Is there a way of checking whether a decoration
108 // exists on an object?
109 ATH_MSG_ERROR("Candidate has no seed...CRASHING now!!!");
110 }
111 oldpositions[pThisVertex] = *(MvfFitInfo(*pThisVertex)->seedVertex());
112 }
113 if (MvfFitInfo(*pThisVertex)->linearizationVertex() ==
114 nullptr) { // TODO: Is there a way of checking whether a decoration
115 // exists on an object?
117 " Candidate has no linearization point...CRASHING now!!! ");
118 }
119 if ((oldpositions[pThisVertex] -
120 *MvfFitInfo(*pThisVertex)->linearizationVertex())
121 .perp() > m_maxDistToLinPoint) {
122 ATH_MSG_DEBUG("Candidate has to be relinearized ");
123 relinearizations[pThisVertex] = true;
124 prepareCompatibility(pThisVertex);
125 }
126 ATH_MSG_DEBUG("Setting the Vertex to the initial constraint");
127 // reput everything to the constraint level
128 pThisVertex->setPosition(
129 MvfFitInfo(*pThisVertex)->constraintVertex()->position());
130 pThisVertex->setCovariancePosition(
131 MvfFitInfo(*pThisVertex)->constraintVertex()->covariancePosition());
132 pThisVertex->setFitQuality(
133 MvfFitInfo(*pThisVertex)->constraintVertex()->chiSquared(),
134 MvfFitInfo(*pThisVertex)->constraintVertex()->numberDoF());
135 pThisVertex->setCovariancePosition(
136 pThisVertex->covariancePosition() * 1. /
137 float(m_AnnealingMaker->getWeight(astate, 1.)));
138 ATH_MSG_DEBUG("Running TrackCompatibilityEstimator on each track");
139 // prepare the iterators for the tracks
140 const auto& theseTrackPointersAtVtx = VTAV(*pThisVertex);
141 // iterate and update the vertex with the track information
142 for (const auto& pThisTrack : theseTrackPointersAtVtx) {
143 ATH_MSG_DEBUG("Adding compatibility info to a track of "
144 << theseTrackPointersAtVtx.size());
145 // now recover from cases where the linearization position is !=0, but
146 // you added more tracks later on...
147 if (not pThisTrack->ImpactPoint3dAtaPlane()) {
148 const bool success = m_ImpactPoint3dEstimator->addIP3dAtaPlane(
149 *pThisTrack, *MvfFitInfo(*pThisVertex)->linearizationVertex());
150 if (!success) {
152 "Adding compatibility to vertex information failed. Newton "
153 "distance finder didn't converge...");
154 }
155 }
156 // first -> estimate the compatibility of the track to the vertex
157 m_TrackCompatibilityEstimator->estimate(*pThisTrack,
158 oldpositions[pThisVertex]);
159 ATH_MSG_DEBUG("End of compatibility for a track");
160 }
161 }
162 ATH_MSG_DEBUG("Finished first candidates cycle");
163 // after having estimated the compatibility of all the vertices, you have to
164 // run again on all vertices, to compute the weights
165 for (auto* pThisVertex : allVertices) {
166 // TODO: crude and quite possibly time consuming, but best solution I
167 // could think of...
168 // updated VxTrackAtVertices are stored in VTAV decoration:
169 // so each time a vertex is to be updated with its tracks in this
170 // loop, delete VxTrackAtVertex vector and add correctly updated
171 // VxTrackAtVertex (from VTAV) to the vector just before calling
172 // the vertex updator
173 std::vector<Trk::VxTrackAtVertex>* tracksOfVertex =
174 &(pThisVertex->vxTrackAtVertex());
175 tracksOfVertex->clear();
176 // prepare the iterators for the tracks
177 const auto& theseTrackPointersAtVtx = VTAV(*pThisVertex);
179 "Beginning lin&update of vertex with pointer: " << pThisVertex);
180 for (const auto& pThisTrack : theseTrackPointersAtVtx) {
181 // set the weight according to all other track's weight
182 ATH_MSG_DEBUG("Calling collect weight for track " << pThisTrack);
183 const std::vector<double>& allweights(
184 collectWeights(*(static_cast<Trk::MVFVxTrackAtVertex*>(pThisTrack))
185 ->linkToVertices()));
186 ATH_MSG_DEBUG("The vtxcompatibility for the track is: "
187 << pThisTrack->vtxCompatibility());
188 pThisTrack->setWeight(m_AnnealingMaker->getWeight(
189 astate, pThisTrack->vtxCompatibility(), allweights));
190 ATH_MSG_DEBUG("The resulting weight for the track is "
191 << m_AnnealingMaker->getWeight(
192 astate, pThisTrack->vtxCompatibility(), allweights));
193 if (pThisTrack->weight() > m_minweight) {
194 ATH_MSG_DEBUG("check passed");
195 // now take care if linearization has been done at least once
196 if (not pThisTrack->linState()) {
197 // linearization never done so far: do it now!
198 ATH_MSG_VERBOSE("Linearizing track for the first time");
199 m_LinearizedTrackFactory->linearize(*pThisTrack,
200 oldpositions[pThisVertex]);
201 } else if (relinearizations[pThisVertex]) {
202 ATH_MSG_VERBOSE("Relinearizing track ");
203 m_LinearizedTrackFactory->linearize(*pThisTrack,
204 oldpositions[pThisVertex]);
205 MvfFitInfo(*pThisVertex)
207 new Amg::Vector3D(oldpositions[pThisVertex]));
208 }
209 // now you can proceed with the update
210 ATH_MSG_DEBUG("Update of the track "
211 << pThisTrack << " to the vertex " << pThisVertex);
212 // TODO: obviously not ideal that I have to do this
213 tracksOfVertex->push_back(*pThisTrack);
214 // TODO: add() returns an xAOD::Vertex* - is it really ok to just
215 // have this line without *iter = m_VertexUpdator->add() ? Must
216 // be...
217 m_VertexUpdator->add(*pThisVertex, *pThisTrack);
218 }
219 } // iterator on tracks
220 // show some info about the position
221 ATH_MSG_DEBUG("Vertex pointer " << pThisVertex << " New position x: "
222 << pThisVertex->position().x()
223 << " y: " << pThisVertex->position().y()
224 << " z: " << pThisVertex->position().z());
225 } // iterator on Vertices
226 // call now one more step of annealing
227 if (!(m_AnnealingMaker->isEquilibrium(astate))) {
228 m_AnnealingMaker->anneal(astate);
229 }
230 // August 2009: sometimes the fitter has not converged when the annealing
231 // has finished iterate on all vertex candidates and check whether they moved
232 // significantly from last iteration
233 shiftIsSmall = true;
234 Amg::Vector3D vrtpos;
235 for (const auto& pThisVertex : allVertices) {
236 vrtpos[0] = oldpositions[pThisVertex][0] - pThisVertex->position()[0];
237 vrtpos[1] = oldpositions[pThisVertex][1] - pThisVertex->position()[1];
238 vrtpos[2] = oldpositions[pThisVertex][2] - pThisVertex->position()[2];
239 AmgSymMatrix(3) weightMatrixVertex;
240 weightMatrixVertex = pThisVertex->covariancePosition().inverse();
241 double relativeShift = vrtpos.dot(weightMatrixVertex * vrtpos);
242 if (relativeShift > m_maxRelativeShift) {
243 shiftIsSmall = false;
244 break;
245 }
246 }
247 num_steps += 1;
248 } while (num_steps < m_maxIterations &&
249 (!(m_AnnealingMaker->isEquilibrium(astate)) || !shiftIsSmall));
250
251 if (num_steps >= m_maxIterations) {
252 ATH_MSG_DEBUG("Didn't converge fully after " << num_steps);
253 }
255 "In principle the big multivertex fit step is finished now...");
256 // TODO: I don't think that I need to fiddle with updating
257 // MVFVxTracksAtVertex - vector of VxTrackAtVertex should be available in
258 // the usual way now and be enough
259 if (m_doSmoothing) {
260 auto trackAvailable = [](const xAOD::Vertex* pV) {
261 return pV->vxTrackAtVertexAvailable() and
262 not(pV->vxTrackAtVertex()).empty();
263 };
264 for (const auto& pThisVertex : allVertices) {
265 if (trackAvailable(pThisVertex)) {
266 m_VertexSmoother->smooth(*pThisVertex);
267 }
268 }
269 } else { // TODO: I added this during xAOD migration
270 for (auto* pThisVertex : allVertices) {
271 const auto& theseTrackPointersAtVtx = VTAV(*pThisVertex);
272 for (const auto& pTrack : theseTrackPointersAtVtx) {
273 if (pTrack->initialPerigee())
274 pTrack->setPerigeeAtVertex((pTrack->initialPerigee())->clone());
275 }
276 }
277 }
278}
279
280std::vector<double>
282 Trk::TrackToVtxLink& tracklink) const
283{
284 ATH_MSG_DEBUG("Collecting weights for tracklink " << &tracklink);
285 // TODO: put this in a better place
286 // Prepare objects holding the decoration of xAOD::Vertex with MVF auxdata
287 // For optimization of access speed
289 "VTAV");
290 const auto& theseVertices = *(tracklink.vertices());
291 std::vector<double> myvector;
292 myvector.reserve(theseVertices.size());
293 for (const auto& pThisVertex : theseVertices) {
294 // really stupid, now you have still to find the weight value (right track
295 // in this vertex) but if you later remove tracks from candidate, you cannot
296 // do much better (maybe update on demand...)
297 const auto& trackPointersForThisVertex = VTAV(*pThisVertex);
298 for (const auto& pThisTrack : trackPointersForThisVertex) {
299 if ((static_cast<Trk::MVFVxTrackAtVertex*>(pThisTrack))
300 ->linkToVertices() == &tracklink) {
301 ATH_MSG_DEBUG("found one weight: it's : "
302 << pThisTrack->vtxCompatibility() << " for track "
303 << pThisTrack);
304 myvector.push_back(pThisTrack->vtxCompatibility());
305 break; // gain time in avoiding to look for other tracks if you already
306 // found the right one
307 }
308 }
309 }
310 return myvector;
311}
312
313void
315{
316 ATH_MSG_VERBOSE(" Now entered addVtxToFit ");
317 // TODO: put this in a better place
318 // Prepare objects holding the decoration of xAOD::Vertex with MVF auxdata
319 // For optimization of access speed
321 "VTAV");
322
323 if (VTAV(*newvertex).empty()) {
325 "The candidate you're adding has no tracks: please fix the problem");
326 }
327 std::vector<xAOD::Vertex*>
328 allVerticesToFit; // how many vertices do you expect?
329 allVerticesToFit.reserve(10); // try 10
330 prepareCompatibility(newvertex);
331 //
332 ATH_MSG_VERBOSE("Iterating on tracks");
333 std::vector<xAOD::Vertex*> addedVerticesLastIteration;
334 std::vector<xAOD::Vertex*> addedVerticesNewIteration;
335 addedVerticesLastIteration.push_back(newvertex);
336 do {
337 for (const auto& vertexIterator : addedVerticesLastIteration) {
338 // now you have to check what are the other vertices which still have to
339 // do with your new one
340 const auto& vertexTracksAtVertex = VTAV(*vertexIterator);
341 for (const auto& thisTrack : vertexTracksAtVertex) {
342 const auto& pTheseVertices =
343 (static_cast<Trk::MVFVxTrackAtVertex*>(thisTrack))
344 ->linkToVertices()
345 ->vertices();
346 for (const auto& thisVertex : *pTheseVertices) {
347 // add the vertex if it's still not there
348 if (not findAmongVertices(thisVertex, allVerticesToFit)) {
349 allVerticesToFit.push_back(thisVertex);
350 if (thisVertex != vertexIterator) {
351 addedVerticesNewIteration.push_back(thisVertex);
352 }
353 }
354 }
355 } // iterate on tracks at considered vertex
356 } // end iteration on addedVerticesLastIteration
357
358 addedVerticesLastIteration = addedVerticesNewIteration;
359 addedVerticesNewIteration.clear();
360 } while (not addedVerticesLastIteration.empty());
361 //
362 // now fitting everything together
363 fit(allVerticesToFit);
364}
365
366void
368{
369 ATH_MSG_VERBOSE("Entered prepareCompatibility() ");
370 // TODO: put this in a better place
371 // Prepare objects holding the decoration of xAOD::Vertex with MVF auxdata
372 // For optimization of access speed
373 static const xAOD::Vertex::Accessor<MvfFitInfo*> MvfFitInfo("MvfFitInfo");
375 "VTAV");
376 const Amg::Vector3D* seedPoint = MvfFitInfo(*newvertex)->seedVertex();
377 ATH_MSG_VERBOSE("Now adding compatibility info to the track");
378 // lambda adds impact point and 'ANDs' with previous success result
379 auto addImpactPoint = [this, seedPoint](const auto& thisVxTrack) {
380 return this->m_ImpactPoint3dEstimator->addIP3dAtaPlane(*thisVxTrack,
381 *seedPoint);
382 };
383 const auto& vertexTracksAtVertex = VTAV(*newvertex);
384 // std::reduce might be quicker, if compiler implemented it
385 const bool success = std::all_of(
386 vertexTracksAtVertex.begin(), vertexTracksAtVertex.end(), addImpactPoint);
387 if (not success) {
388 ATH_MSG_DEBUG("Adding compatibility to vertex information failed. Newton "
389 "distance finder didn't converge...");
390 }
391}
392
393bool
395 const xAOD::Vertex* vertex,
396 const std::vector<xAOD::Vertex*>& previousVertices)
397{
398 return (std::find(previousVertices.begin(), previousVertices.end(), vertex) !=
399 previousVertices.end());
400}
401}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
#define AmgSymMatrix(dim)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
ToolHandle< Trk::IImpactPoint3dEstimator > m_ImpactPoint3dEstimator
double m_minweight
Minimum weight a track as to have in order to be considered in the fit of one of the vertices.
virtual ~AdaptiveMultiVertexFitter()
destructor
ToolHandle< Trk::IVertexSmoother > m_VertexSmoother
static bool findAmongVertices(const xAOD::Vertex *vertex, const std::vector< xAOD::Vertex * > &previousVertices)
Internal method to find a VxCandidate among a vector of VxCandidates.
long int m_maxIterations
Max number of iterations.
ToolHandle< Trk::IVertexAnnealingMaker > m_AnnealingMaker
void addVtxToFit(xAOD::Vertex *pVtx) const
Adds a new MVFVxCandidate to a previous multi-vertex fit and fits everything together.
void prepareCompatibility(xAOD::Vertex *newvertex) const
Internal function to prepare the compatibility information of all the tracks of the new vertex (an IP...
bool m_doSmoothing
True if smoothing after fit iterations has to be performed: otherwise the Smoother AlgoTool provided ...
double m_initialError
Initial error in form of diagonal elements of the inverse of the covariance matrix (name is misleadin...
ToolHandle< Trk::IVertexUpdator > m_VertexUpdator
ToolHandle< Trk::IVertexLinearizedTrackFactory > m_LinearizedTrackFactory
ToolHandle< Trk::IVertexTrackCompatibilityEstimator > m_TrackCompatibilityEstimator
double m_maxRelativeShift
Maximum shift allowed for last iteration... (in terms of Delta|VecR|/sigma|VecR|)
double m_maxDistToLinPoint
Maximum distance of linearization point of track to actual fitted vertex before needing to relineariz...
void fit(std::vector< xAOD::Vertex * > &allVertices) const
fit all the provided MVFVxCandidate, which have to be already properly initialized.
AdaptiveMultiVertexFitter(const std::string &t, const std::string &n, const IInterface *p)
default constructor due to Athena interface
std::vector< double > collectWeights(TrackToVtxLink &tracklink) const
Internal function to collect the weights of the tracks partecipating to all the possible vertices (ne...
const xAOD::Vertex * constraintVertex(void) const
Const access to the constraint vertex.
Definition MvfFitInfo.h:123
void setLinearizationVertex(Amg::Vector3D *)
Linearization point set method.
const Amg::Vector3D * linearizationVertex(void) const
Const access to the linearization point.
Definition MvfFitInfo.h:143
const Amg::Vector3D * seedVertex(void) const
Const access to the seed vertex.
Definition MvfFitInfo.h:133
float numberDoF() const
Returns the number of degrees of freedom of the vertex fit as float.
float chiSquared() const
Returns the of the vertex fit as float.
const Amg::Vector3D & position() const
Returns the 3-pos.
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the ATLAS eigen extensions are properly loaded.
Vertex_v1 Vertex
Define the latest version of the vertex class.