Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AdaptiveMultiVertexFitter.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file AdaptiveMultiVertexFitter.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019-2023 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
12 
13 template <typename input_track_t, typename linearizer_t>
16  State& state, const std::vector<Vertex<input_track_t>*>& verticesToFit,
17  const linearizer_t& linearizer,
18  const VertexingOptions<input_track_t>& vertexingOptions) const {
19  // Set all vertices to fit in the current state
20  state.vertexCollection = verticesToFit;
21 
22  // Perform fit on all vertices simultaneously
23  auto fitRes = fitImpl(state, linearizer, vertexingOptions);
24 
25  if (!fitRes.ok()) {
26  return fitRes.error();
27  }
28 
29  return {};
30 }
31 
32 template <typename input_track_t, typename linearizer_t>
35  State& state, const linearizer_t& linearizer,
36  const VertexingOptions<input_track_t>& vertexingOptions) const {
37  // Reset annealing tool
39 
40  // Boolean indicating whether any of the vertices has moved more than
41  // m_cfg.maxRelativeShift during the last iteration. We will keep iterating
42  // until the equilibrium (i.e., the lowest temperature) is reached in
43  // the annealing procedure and isSmallShift is true (or until the maximum
44  // number of iterations is exceeded).
45  bool isSmallShift = true;
46 
47  // Number of iterations counter
48  unsigned int nIter = 0;
49 
50  // Start iterating
51  while (nIter < m_cfg.maxIterations &&
52  (!state.annealingState.equilibriumReached || !isSmallShift)) {
53  // Initial loop over all vertices in state.vertexCollection
54  for (auto vtx : state.vertexCollection) {
55  VertexInfo<input_track_t>& vtxInfo = state.vtxInfoMap[vtx];
56  vtxInfo.relinearize = false;
57  // Store old position of vertex, i.e. seed position
58  // in case of first iteration or position determined
59  // in previous iteration afterwards
60  vtxInfo.oldPosition = vtx->fullPosition();
61 
62  // Calculate the x-y-distance between the current vertex position
63  // and the linearization point of the tracks. If it is too large,
64  // we relinearize the tracks and recalculate their 3D impact
65  // parameters.
66  ActsVector<2> xyDiff = vtxInfo.oldPosition.template head<2>() -
67  vtxInfo.linPoint.template head<2>();
68  if (xyDiff.norm() > m_cfg.maxDistToLinPoint) {
69  // Set flag for relinearization
70  vtxInfo.relinearize = true;
71  // Recalculate the track impact parameters at the current vertex
72  // position
73  prepareVertexForFit(state, vtx, vertexingOptions);
74  }
75 
76  // Check if we use the constraint during the vertex fit
77  if (state.vtxInfoMap[vtx].constraint.fullCovariance() !=
78  SquareMatrix4::Zero()) {
79  const Acts::Vertex<input_track_t>& constraint =
80  state.vtxInfoMap[vtx].constraint;
81  vtx->setFullPosition(constraint.fullPosition());
82  vtx->setFitQuality(constraint.fitQuality());
83  vtx->setFullCovariance(constraint.fullCovariance());
84  } else if (vtx->fullCovariance() == SquareMatrix4::Zero()) {
85  return VertexingError::NoCovariance;
86  }
87  double weight = m_cfg.annealingTool.getWeight(state.annealingState, 1.);
88  vtx->setFullCovariance(vtx->fullCovariance() / weight);
89 
90  // Set vertexCompatibility for all TrackAtVertex objects
91  // at the current vertex
92  setAllVertexCompatibilities(state, vtx, vertexingOptions);
93  } // End loop over vertex collection
94 
95  // Recalculate all track weights and update vertices
96  setWeightsAndUpdate(state, linearizer, vertexingOptions);
97 
98  // Cool the system down, i.e., reduce the temperature parameter. At lower
99  // temperatures, outlying tracks are downweighted more.
100  if (!state.annealingState.equilibriumReached) {
101  m_cfg.annealingTool.anneal(state.annealingState);
102  }
103 
104  isSmallShift = checkSmallShift(state);
105  ++nIter;
106  }
107  // Multivertex fit is finished
108 
109  // Check if smoothing is required
110  if (m_cfg.doSmoothing) {
111  doVertexSmoothing(state);
112  }
113 
114  return {};
115 }
116 
117 template <typename input_track_t, typename linearizer_t>
120  State& state, Vertex<input_track_t>& newVertex,
121  const linearizer_t& linearizer,
122  const VertexingOptions<input_track_t>& vertexingOptions) const {
123  if (state.vtxInfoMap[&newVertex].trackLinks.empty()) {
124  return VertexingError::EmptyInput;
125  }
126 
127  std::vector<Vertex<input_track_t>*> verticesToFit;
128 
129  // Save the 3D impact parameters of all tracks associated with newVertex.
130  auto res = prepareVertexForFit(state, &newVertex, vertexingOptions);
131  if (!res.ok()) {
132  return res.error();
133  }
134 
135  // List of vertices added in last iteration
136  std::vector<Vertex<input_track_t>*> lastIterAddedVertices = {&newVertex};
137  // List of vertices added in current iteration
138  std::vector<Vertex<input_track_t>*> currentIterAddedVertices;
139 
140  // Fill verticesToFit with vertices that are connected to newVertex (via
141  // tracks and/or other vertices).
142  while (!lastIterAddedVertices.empty()) {
143  for (auto& lastIterAddedVertex : lastIterAddedVertices) {
144  // Loop over all tracks at lastIterAddedVertex
145  const std::vector<const input_track_t*>& trks =
146  state.vtxInfoMap[lastIterAddedVertex].trackLinks;
147  for (const auto& trk : trks) {
148  // Range of vertices that are associated with trk. The range is
149  // represented via its bounds: begin refers to the first iterator of the
150  // range; end refers to the iterator after the last iterator of the
151  // range.
152  auto [begin, end] = state.trackToVerticesMultiMap.equal_range(trk);
153 
154  for (auto it = begin; it != end; ++it) {
155  // it->first corresponds to trk, it->second to one of its associated
156  // vertices
157  auto vtxToFit = it->second;
158  // Add vertex to the fit if it is not already included
159  if (!isAlreadyInList(vtxToFit, verticesToFit)) {
160  verticesToFit.push_back(vtxToFit);
161 
162  // Collect vertices that were added this iteration
163  if (vtxToFit != lastIterAddedVertex) {
164  currentIterAddedVertices.push_back(vtxToFit);
165  }
166  }
167  } // End for loop over range of associated vertices
168  } // End loop over trackLinks
169  } // End loop over lastIterAddedVertices
170 
171  lastIterAddedVertices = currentIterAddedVertices;
172  currentIterAddedVertices.clear();
173  } // End while loop
174 
175  state.vertexCollection = verticesToFit;
176 
177  // Perform fit on all added vertices
178  auto fitRes = fitImpl(state, linearizer, vertexingOptions);
179  if (!fitRes.ok()) {
180  return fitRes.error();
181  }
182 
183  return {};
184 }
185 
186 template <typename input_track_t, typename linearizer_t>
189  const std::vector<Vertex<input_track_t>*>& vertices) const {
190  return std::find(vertices.begin(), vertices.end(), vtx) != vertices.end();
191 }
192 
193 template <typename input_track_t, typename linearizer_t>
197  const VertexingOptions<input_track_t>& vertexingOptions) const {
198  // Vertex info object
199  auto& vtxInfo = state.vtxInfoMap[vtx];
200  // Vertex seed position
201  const Vector3& seedPos = vtxInfo.seedPosition.template head<3>();
202 
203  // Loop over all tracks at the vertex
204  for (const auto& trk : vtxInfo.trackLinks) {
205  auto res = m_cfg.ipEst.estimate3DImpactParameters(
206  vertexingOptions.geoContext, vertexingOptions.magFieldContext,
207  m_extractParameters(*trk), seedPos, state.ipState);
208  if (!res.ok()) {
209  return res.error();
210  }
211  // Save 3D impact parameters of the track
212  vtxInfo.impactParams3D.emplace(trk, res.value());
213  }
214  return {};
215 }
216 
217 template <typename input_track_t, typename linearizer_t>
222  const VertexingOptions<input_track_t>& vertexingOptions) const {
223  VertexInfo<input_track_t>& vtxInfo = state.vtxInfoMap[vtx];
224 
225  // Loop over all tracks that are associated with vtx and estimate their
226  // compatibility
227  for (const auto& trk : vtxInfo.trackLinks) {
228  auto& trkAtVtx = state.tracksAtVerticesMap.at(std::make_pair(trk, vtx));
229  // Recover from cases where linearization point != 0 but
230  // more tracks were added later on
231  if (vtxInfo.impactParams3D.find(trk) == vtxInfo.impactParams3D.end()) {
232  auto res = m_cfg.ipEst.estimate3DImpactParameters(
233  vertexingOptions.geoContext, vertexingOptions.magFieldContext,
234  m_extractParameters(*trk), VectorHelpers::position(vtxInfo.linPoint),
235  state.ipState);
236  if (!res.ok()) {
237  return res.error();
238  }
239  // Set impactParams3D for current trackAtVertex
240  vtxInfo.impactParams3D.emplace(trk, res.value());
241  }
242  // Set compatibility with current vertex
243  Acts::Result<double> compatibilityResult(0.);
244  if (m_cfg.useTime) {
245  compatibilityResult = m_cfg.ipEst.template getVertexCompatibility<4>(
246  vertexingOptions.geoContext, &(vtxInfo.impactParams3D.at(trk)),
247  vtxInfo.oldPosition);
248  } else {
249  compatibilityResult = m_cfg.ipEst.template getVertexCompatibility<3>(
250  vertexingOptions.geoContext, &(vtxInfo.impactParams3D.at(trk)),
252  }
253  if (!compatibilityResult.ok()) {
254  return compatibilityResult.error();
255  }
256  trkAtVtx.vertexCompatibility = *compatibilityResult;
257  }
258  return {};
259 }
260 
261 template <typename input_track_t, typename linearizer_t>
264  State& state, const linearizer_t& linearizer,
265  const VertexingOptions<input_track_t>& vertexingOptions) const {
266  for (auto vtx : state.vertexCollection) {
267  VertexInfo<input_track_t>& vtxInfo = state.vtxInfoMap[vtx];
268 
269  if (vtxInfo.relinearize) {
270  vtxInfo.linPoint = vtxInfo.oldPosition;
271  }
272 
273  const std::shared_ptr<PerigeeSurface> vtxPerigeeSurface =
274  Surface::makeShared<PerigeeSurface>(
276 
277  for (const auto& trk : vtxInfo.trackLinks) {
278  auto& trkAtVtx = state.tracksAtVerticesMap.at(std::make_pair(trk, vtx));
279 
280  // Set trackWeight for current track
281  trkAtVtx.trackWeight = m_cfg.annealingTool.getWeight(
282  state.annealingState, trkAtVtx.vertexCompatibility,
283  collectTrackToVertexCompatibilities(state, trk));
284 
285  if (trkAtVtx.trackWeight > m_cfg.minWeight) {
286  // Check if track is already linearized and whether we need to
287  // relinearize
288  if (!trkAtVtx.isLinearized || vtxInfo.relinearize) {
289  auto result = linearizer.linearizeTrack(
290  m_extractParameters(*trk), vtxInfo.linPoint[3],
291  *vtxPerigeeSurface, vertexingOptions.geoContext,
292  vertexingOptions.magFieldContext, state.linearizerState);
293  if (!result.ok()) {
294  return result.error();
295  }
296 
297  trkAtVtx.linearizedState = *result;
298  trkAtVtx.isLinearized = true;
299  }
300  // Update the vertex with the new track
301  KalmanVertexUpdater::updateVertexWithTrack<input_track_t>(*vtx,
302  trkAtVtx);
303  } else {
304  ACTS_VERBOSE("Track weight too low. Skip track.");
305  }
306  } // End loop over tracks at vertex
307  ACTS_VERBOSE("New vertex position: " << vtx->fullPosition().transpose());
308  } // End loop over vertex collection
309 
310  return {};
311 }
312 
313 template <typename input_track_t, typename linearizer_t>
314 std::vector<double>
317  const input_track_t* trk) const {
318  // Compatibilities of trk wrt all of its associated vertices
319  std::vector<double> trkToVtxCompatibilities;
320 
321  // Range of vertices that are associated with trk. The range is
322  // represented via its bounds: begin refers to the first iterator of the
323  // range; end refers to the iterator after the last iterator of the range.
324  auto [begin, end] = state.trackToVerticesMultiMap.equal_range(trk);
325 
326  // Allocate space in memory for the vector of compatibilities
327  trkToVtxCompatibilities.reserve(std::distance(begin, end));
328 
329  for (auto it = begin; it != end; ++it) {
330  // it->first corresponds to trk, it->second to one of its associated
331  // vertices
332  trkToVtxCompatibilities.push_back(
333  state.tracksAtVerticesMap.at(std::make_pair(trk, it->second))
334  .vertexCompatibility);
335  }
336 
337  return trkToVtxCompatibilities;
338 }
339 
340 template <typename input_track_t, typename linearizer_t>
342  input_track_t, linearizer_t>::checkSmallShift(State& state) const {
343  for (auto vtx : state.vertexCollection) {
344  Vector3 diff =
345  state.vtxInfoMap[vtx].oldPosition.template head<3>() - vtx->position();
346  const SquareMatrix3& vtxCov = vtx->covariance();
347  double relativeShift = diff.dot(vtxCov.inverse() * diff);
348  if (relativeShift > m_cfg.maxRelativeShift) {
349  return false;
350  }
351  }
352  return true;
353 }
354 
355 template <typename input_track_t, typename linearizer_t>
357  input_track_t, linearizer_t>::doVertexSmoothing(State& state) const {
358  for (const auto vtx : state.vertexCollection) {
359  for (const auto trk : state.vtxInfoMap[vtx].trackLinks) {
360  auto& trkAtVtx = state.tracksAtVerticesMap.at(std::make_pair(trk, vtx));
361  if (trkAtVtx.trackWeight > m_cfg.minWeight) {
362  KalmanVertexTrackUpdater::update<input_track_t>(trkAtVtx, *vtx);
363  }
364  }
365  }
366 }