9 template <
typename vfitter_t,
typename sfinder_t>
11 const std::vector<const InputTrack_t*>& trackVector,
15 const std::vector<const InputTrack_t*>& origTracks = trackVector;
17 std::vector<const InputTrack_t*> seedTracks = trackVector;
20 std::vector<Vertex<InputTrack_t>> vertexCollection;
24 while (seedTracks.size() > 1 && nInterations < m_cfg.maxVertices) {
26 auto seedRes = getVertexSeed(seedTracks, vertexingOptions);
28 return seedRes.error();
36 std::vector<const InputTrack_t*> perigeesToFit;
37 std::vector<const InputTrack_t*> perigeesToFitSplitVertex;
40 auto res = fillPerigeesToFit(seedTracks, seedVertex, perigeesToFit,
41 perigeesToFitSplitVertex, vertexingOptions);
47 ACTS_DEBUG(
"Perigees used for fit: " << perigeesToFit.size());
53 if (m_cfg.useBeamConstraint && !perigeesToFit.empty()) {
54 auto fitResult = m_cfg.vertexFitter.fit(perigeesToFit, m_cfg.linearizer,
57 currentVertex = std::move(*fitResult);
59 return fitResult.error();
61 }
else if (!m_cfg.useBeamConstraint && perigeesToFit.size() > 1) {
62 auto fitResult = m_cfg.vertexFitter.fit(perigeesToFit, m_cfg.linearizer,
65 currentVertex = std::move(*fitResult);
67 return fitResult.error();
70 if (m_cfg.createSplitVertices && perigeesToFitSplitVertex.size() > 1) {
71 auto fitResult = m_cfg.vertexFitter.fit(
72 perigeesToFitSplitVertex, m_cfg.linearizer, vertexingOptions);
74 currentSplitVertex = std::move(*fitResult);
76 return fitResult.error();
80 ACTS_DEBUG(
"Vertex position after fit: " << currentVertex.fullPosition());
83 double ndf = currentVertex.fitQuality().second;
84 double ndfSplitVertex = currentSplitVertex.
fitQuality().second;
87 int nTracksAtVertex = countSignificantTracks(currentVertex);
88 int nTracksAtSplitVertex = countSignificantTracks(currentSplitVertex);
91 ((!m_cfg.useBeamConstraint && ndf > 0 && nTracksAtVertex >= 2) ||
92 (m_cfg.useBeamConstraint && ndf > 3 && nTracksAtVertex >= 2));
95 removeAllTracks(perigeesToFit, seedTracks);
97 if (m_cfg.reassignTracksAfterFirstFit && (!m_cfg.createSplitVertices)) {
101 auto result = reassignTracksToNewVertex(vertexCollection, currentVertex,
102 perigeesToFit, seedTracks,
103 origTracks, vertexingOptions);
105 return result.error();
107 isGoodVertex = *result;
112 removeUsedCompatibleTracks(currentVertex, perigeesToFit, seedTracks,
116 "Number of seed tracks after removal of compatible tracks "
118 << seedTracks.size());
123 bool isGoodSplitVertex =
false;
124 if (m_cfg.createSplitVertices) {
125 isGoodSplitVertex = (ndfSplitVertex > 0 && nTracksAtSplitVertex >= 2);
127 if (!isGoodSplitVertex) {
128 removeAllTracks(perigeesToFitSplitVertex, seedTracks);
130 removeUsedCompatibleTracks(currentSplitVertex, perigeesToFitSplitVertex,
131 seedTracks, vertexingOptions);
136 vertexCollection.push_back(currentVertex);
138 if (isGoodSplitVertex && m_cfg.createSplitVertices) {
139 vertexCollection.push_back(currentSplitVertex);
146 return vertexCollection;
149 template <
typename vfitter_t,
typename sfinder_t>
151 const std::vector<const InputTrack_t*>& seedTracks,
154 auto res = m_cfg.seedFinder.find(seedTracks, vertexingOptions);
156 auto vertexCollection = *res;
157 if (vertexCollection.empty()) {
159 "No seed found. Number of input tracks: " << seedTracks.size());
160 return VertexingError::SeedingError;
168 <<
"). Number of input tracks: " << seedTracks.size());
171 ACTS_DEBUG(
"No seed found. Number of input tracks: " << seedTracks.size());
172 return VertexingError::SeedingError;
176 template <
typename vfitter_t,
typename sfinder_t>
178 const std::vector<const InputTrack_t*>& perigeesToFit,
179 std::vector<const InputTrack_t*>& seedTracks)
const {
180 for (
const auto& fitPerigee : perigeesToFit) {
181 const BoundParameters& fitPerigeeParams = m_extractParameters(*fitPerigee);
184 std::find_if(seedTracks.begin(), seedTracks.end(),
185 [&fitPerigeeParams,
this](
const auto seedTrk) {
186 return fitPerigeeParams == m_extractParameters(*seedTrk);
188 if (foundIter != seedTracks.end()) {
190 seedTracks.erase(foundIter);
192 ACTS_WARNING(
"Track to be removed not found in seed tracks.")
197 template <
typename vfitter_t,
typename sfinder_t>
203 auto result = m_cfg.linearizer.linearizeTrack(
207 return result.error();
210 auto linTrack = std::move(*result);
214 linTrack.covarianceAtPCA.template
block<2, 2>(0, 0);
217 (linTrack.positionJacobian *
218 (vertex.
fullCovariance() * linTrack.positionJacobian.transpose()))
220 weightReduced += errorVertexReduced;
221 weightReduced = weightReduced.inverse();
225 linTrack.parametersAtPCA.template
block<2, 1>(0, 0);
226 double compatibility =
227 trackParameters2D.dot(weightReduced * trackParameters2D);
229 return compatibility;
232 template <
typename vfitter_t,
typename sfinder_t>
236 std::vector<const InputTrack_t*>& perigeesToFit,
237 std::vector<const InputTrack_t*>& seedTracks,
239 std::vector<TrackAtVertex<InputTrack_t>> tracksAtVertex = myVertex.
tracks();
241 for (
const auto& trackAtVtx : tracksAtVertex) {
243 if (trackAtVtx.trackWeight < m_cfg.cutOffTrackWeight) {
249 std::find_if(seedTracks.begin(), seedTracks.end(),
250 [&trackAtVtx,
this](
const auto seedTrk) {
251 return trackAtVtx.originalParams == seedTrk;
253 if (foundSeedIter != seedTracks.end()) {
254 seedTracks.erase(foundSeedIter);
256 ACTS_WARNING(
"Track trackAtVtx not found in seedTracks!");
261 std::find_if(perigeesToFit.begin(), perigeesToFit.end(),
262 [&trackAtVtx,
this](
const auto fitTrk) {
263 return trackAtVtx.originalParams == fitTrk;
265 if (foundFitIter != perigeesToFit.end()) {
266 perigeesToFit.erase(foundFitIter);
268 ACTS_WARNING(
"Track trackAtVtx not found in perigeesToFit!");
272 ACTS_DEBUG(
"After removal of tracks belonging to vertex, "
273 << seedTracks.size() <<
" seed tracks left.");
278 ACTS_DEBUG(
"Number of outliers: " << perigeesToFit.size());
280 for (
const auto& myPerigeeToFit : perigeesToFit) {
282 auto result = getCompatibility(m_extractParameters(*myPerigeeToFit),
283 myVertex, vertexingOptions);
286 return result.error();
289 double chi2 = *result;
293 if (chi2 < m_cfg.maximumChi2cutForSeeding) {
295 std::find_if(seedTracks.begin(), seedTracks.end(),
296 [&myPerigeeToFit,
this](
const auto seedTrk) {
297 return myPerigeeToFit == seedTrk;
299 if (foundIter != seedTracks.end()) {
301 seedTracks.erase(foundIter);
308 std::find_if(tracksAtVertex.begin(), tracksAtVertex.end(),
309 [&myPerigeeToFit,
this](
auto trk) {
310 return myPerigeeToFit == trk.originalParams;
312 if (foundIter != tracksAtVertex.end()) {
314 tracksAtVertex.erase(foundIter);
325 template <
typename vfitter_t,
typename sfinder_t>
328 const std::vector<const InputTrack_t*>& perigeeList,
330 std::vector<const InputTrack_t*>& perigeesToFitOut,
331 std::vector<const InputTrack_t*>& perigeesToFitSplitVertexOut,
333 int numberOfTracks = perigeeList.size();
338 for (
const auto& sTrack : perigeeList) {
339 if (numberOfTracks <= 2) {
340 perigeesToFitOut.push_back(sTrack);
342 }
else if (numberOfTracks <= 4 && !m_cfg.createSplitVertices) {
343 perigeesToFitOut.push_back(sTrack);
345 }
else if (numberOfTracks <= 4 * m_cfg.splitVerticesTrkInvFraction &&
346 m_cfg.createSplitVertices) {
348 if (count % m_cfg.splitVerticesTrkInvFraction == 0) {
349 perigeesToFitOut.push_back(sTrack);
352 perigeesToFitSplitVertexOut.push_back(sTrack);
360 auto distanceRes = m_cfg.ipEst.calculate3dDistance(
362 if (!distanceRes.ok()) {
363 return distanceRes.error();
367 return VertexingError::NoCovariance;
378 if (*distanceRes / error < m_cfg.significanceCutSeeding) {
379 if (count % m_cfg.splitVerticesTrkInvFraction == 0 ||
380 !m_cfg.createSplitVertices) {
381 perigeesToFitOut.push_back(sTrack);
384 perigeesToFitSplitVertexOut.push_back(sTrack);
393 template <
typename vfitter_t,
typename sfinder_t>
398 std::vector<const InputTrack_t*>& perigeesToFit,
399 std::vector<const InputTrack_t*>& seedTracks,
400 const std::vector<const InputTrack_t*>& origTracks,
402 int numberOfAddedTracks = 0;
406 for (
auto& vertexIt : vertexCollection) {
408 std::vector<TrackAtVertex<InputTrack_t>> tracksAtVertex = vertexIt.tracks();
409 auto tracksBegin = tracksAtVertex.begin();
410 auto tracksEnd = tracksAtVertex.end();
412 for (
auto tracksIter = tracksBegin; tracksIter != tracksEnd;) {
415 if (tracksIter->trackWeight > m_cfg.cutOffTrackWeight) {
421 m_extractParameters(*(tracksIter->originalParams));
425 getCompatibility(trackPerigee, currentVertex, vertexingOptions);
426 if (!resultNew.ok()) {
429 double chi2NewVtx = *resultNew;
432 getCompatibility(trackPerigee, vertexIt, vertexingOptions);
433 if (!resultOld.ok()) {
436 double chi2OldVtx = *resultOld;
438 ACTS_DEBUG(
"Compatibility to new vertex: " << chi2NewVtx);
439 ACTS_DEBUG(
"Compatibility to old vertex: " << chi2OldVtx);
441 if (chi2NewVtx < chi2OldVtx) {
442 perigeesToFit.push_back(tracksIter->originalParams);
448 seedTracks.push_back(tracksIter->originalParams);
455 numberOfAddedTracks += 1;
458 tracksIter = tracksAtVertex.erase(tracksIter);
459 tracksBegin = tracksAtVertex.begin();
460 tracksEnd = tracksAtVertex.end();
470 vertexIt.setTracksAtVertex(tracksAtVertex);
474 <<
" tracks from old (other) vertices for new fit");
480 if (m_cfg.useBeamConstraint && !perigeesToFit.empty()) {
481 auto fitResult = m_cfg.vertexFitter.fit(perigeesToFit, m_cfg.linearizer,
483 if (fitResult.ok()) {
484 currentVertex = std::move(*fitResult);
488 }
else if (!m_cfg.useBeamConstraint && perigeesToFit.size() > 1) {
489 auto fitResult = m_cfg.vertexFitter.fit(perigeesToFit, m_cfg.linearizer,
491 if (fitResult.ok()) {
492 currentVertex = std::move(*fitResult);
499 double ndf = currentVertex.
fitQuality().second;
502 int nTracksAtVertex = countSignificantTracks(currentVertex);
505 ((!m_cfg.useBeamConstraint && ndf > 0 && nTracksAtVertex >= 2) ||
506 (m_cfg.useBeamConstraint && ndf > 3 && nTracksAtVertex >= 2));
509 removeAllTracks(perigeesToFit, seedTracks);
512 << seedTracks.size() <<
"seed tracks after BAD vertex.");
518 template <
typename vfitter_t,
typename sfinder_t>
521 return std::count_if(vtx.
tracks().begin(), vtx.
tracks().end(),
523 return trk.trackWeight > m_cfg.cutOffTrackWeight;