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);
29 return seedRes.error();
32 const auto& seedVertex = *seedRes;
34 if (seedVertex.fullPosition()[
eZ] ==
35 vertexingOptions.constraint.position().z()) {
36 ACTS_DEBUG(
"No more seed found. Break and stop primary vertex finding.");
43 std::vector<const InputTrack_t*> tracksToFit;
44 std::vector<const InputTrack_t*> tracksToFitSplitVertex;
47 auto res = fillTracksToFit(seedTracks, seedVertex, tracksToFit,
48 tracksToFitSplitVertex, vertexingOptions,
state);
54 ACTS_DEBUG(
"Number of tracks used for fit: " << tracksToFit.size());
60 if (vertexingOptions.useConstraintInFit && !tracksToFit.empty()) {
61 auto fitResult =
m_cfg.vertexFitter.fit(
62 tracksToFit,
m_cfg.linearizer, vertexingOptions,
state.fitterState);
66 return fitResult.error();
68 }
else if (!vertexingOptions.useConstraintInFit && tracksToFit.size() > 1) {
69 auto fitResult =
m_cfg.vertexFitter.fit(
70 tracksToFit,
m_cfg.linearizer, vertexingOptions,
state.fitterState);
74 return fitResult.error();
77 if (
m_cfg.createSplitVertices && tracksToFitSplitVertex.size() > 1) {
79 m_cfg.vertexFitter.fit(tracksToFitSplitVertex,
m_cfg.linearizer,
80 vertexingOptions,
state.fitterState);
82 currentSplitVertex =
std::move(*fitResult);
84 return fitResult.error();
89 << currentVertex.fullPosition().transpose());
92 double ndf = currentVertex.fitQuality().second;
93 double ndfSplitVertex = currentSplitVertex.
fitQuality().second;
96 int nTracksAtVertex = countSignificantTracks(currentVertex);
97 int nTracksAtSplitVertex = countSignificantTracks(currentSplitVertex);
99 bool isGoodVertex = ((!vertexingOptions.useConstraintInFit && ndf > 0 &&
100 nTracksAtVertex >= 2) ||
101 (vertexingOptions.useConstraintInFit && ndf > 3 &&
102 nTracksAtVertex >= 2));
105 removeTracks(tracksToFit, seedTracks);
107 if (
m_cfg.reassignTracksAfterFirstFit && (!
m_cfg.createSplitVertices)) {
111 auto result = reassignTracksToNewVertex(
112 vertexCollection, currentVertex, tracksToFit, seedTracks,
113 origTracks, vertexingOptions,
state);
115 return result.error();
117 isGoodVertex = *result;
122 removeUsedCompatibleTracks(currentVertex, tracksToFit, seedTracks,
123 vertexingOptions,
state);
126 "Number of seed tracks after removal of compatible tracks "
128 << seedTracks.size());
133 bool isGoodSplitVertex =
false;
134 if (
m_cfg.createSplitVertices) {
135 isGoodSplitVertex = (ndfSplitVertex > 0 && nTracksAtSplitVertex >= 2);
137 if (!isGoodSplitVertex) {
138 removeTracks(tracksToFitSplitVertex, seedTracks);
140 removeUsedCompatibleTracks(currentSplitVertex, tracksToFitSplitVertex,
141 seedTracks, vertexingOptions,
state);
146 vertexCollection.push_back(currentVertex);
148 if (isGoodSplitVertex &&
m_cfg.createSplitVertices) {
149 vertexCollection.push_back(currentSplitVertex);
155 return vertexCollection;
158 template <
typename vfitter_t,
typename sfinder_t>
160 const std::vector<const InputTrack_t*>& seedTracks,
163 typename sfinder_t::State finderState;
164 auto res =
m_cfg.seedFinder.find(seedTracks, vertexingOptions, finderState);
167 ACTS_DEBUG(
"Seeding error: internal. Number of input tracks: "
168 << seedTracks.size());
169 return VertexingError::SeedingError;
172 const auto& vertexCollection = *res;
174 if (vertexCollection.empty()) {
175 ACTS_DEBUG(
"Seeding error: no seeds. Number of input tracks: "
176 << seedTracks.size());
177 return VertexingError::SeedingError;
180 ACTS_DEBUG(
"Found " << vertexCollection.size() <<
" seeds");
187 << seedVertex.fullPosition()[
eX] <<
", "
188 << seedVertex.fullPosition()[
eY] <<
", "
189 << seedVertex.fullPosition()[
eZ] <<
", " << seedVertex.time()
190 <<
"). Number of input tracks: " << seedTracks.size());
195 template <
typename vfitter_t,
typename sfinder_t>
197 const std::vector<const InputTrack_t*>& tracksToRemove,
198 std::vector<const InputTrack_t*>& seedTracks)
const {
199 for (
const auto& trk : tracksToRemove) {
203 std::find_if(seedTracks.begin(), seedTracks.end(),
204 [¶ms,
this](
const auto seedTrk) {
205 return params == m_extractParameters(*seedTrk);
207 if (foundIter != seedTracks.end()) {
209 seedTracks.erase(foundIter);
211 ACTS_WARNING(
"Track to be removed not found in seed tracks.")
216 template <
typename vfitter_t,
typename sfinder_t>
224 auto result =
m_cfg.linearizer.linearizeTrack(
229 return result.error();
236 linTrack.covarianceAtPCA.template block<2, 2>(0, 0);
239 (linTrack.positionJacobian *
240 (vertex.
fullCovariance() * linTrack.positionJacobian.transpose()))
241 .template block<2, 2>(0, 0);
242 weightReduced += errorVertexReduced;
243 weightReduced = weightReduced.inverse().eval();
247 linTrack.parametersAtPCA.template block<2, 1>(0, 0);
248 double compatibility =
249 trackParameters2D.dot(weightReduced * trackParameters2D);
251 return compatibility;
254 template <
typename vfitter_t,
typename sfinder_t>
258 std::vector<const InputTrack_t*>& seedTracks,
261 std::vector<TrackAtVertex<InputTrack_t>> tracksAtVertex = vertex.
tracks();
263 for (
const auto& trackAtVtx : tracksAtVertex) {
265 if (trackAtVtx.trackWeight <
m_cfg.cutOffTrackWeight) {
271 std::find_if(seedTracks.begin(), seedTracks.end(),
272 [&trackAtVtx](
const auto seedTrk) {
273 return trackAtVtx.originalParams == seedTrk;
275 if (foundSeedIter != seedTracks.end()) {
276 seedTracks.erase(foundSeedIter);
278 ACTS_WARNING(
"Track trackAtVtx not found in seedTracks!");
283 std::find_if(tracksToFit.begin(), tracksToFit.end(),
284 [&trackAtVtx](
const auto fitTrk) {
285 return trackAtVtx.originalParams == fitTrk;
287 if (foundFitIter != tracksToFit.end()) {
288 tracksToFit.erase(foundFitIter);
290 ACTS_WARNING(
"Track trackAtVtx not found in tracksToFit!");
294 ACTS_DEBUG(
"After removal of tracks belonging to vertex, "
295 << seedTracks.size() <<
" seed tracks left.");
300 ACTS_DEBUG(
"Number of outliers: " << tracksToFit.size());
302 const std::shared_ptr<PerigeeSurface> vertexPerigeeSurface =
303 Surface::makeShared<PerigeeSurface>(
306 for (
const auto& trk : tracksToFit) {
309 getCompatibility(m_extractParameters(*trk), vertex,
310 *vertexPerigeeSurface, vertexingOptions, state);
313 return result.error();
316 double chi2 = *result;
320 if (chi2 <
m_cfg.maximumChi2cutForSeeding) {
322 std::find_if(seedTracks.begin(), seedTracks.end(),
323 [&trk](
const auto seedTrk) {
return trk == seedTrk; });
324 if (foundIter != seedTracks.end()) {
326 seedTracks.erase(foundIter);
332 auto foundIter = std::find_if(
333 tracksAtVertex.begin(), tracksAtVertex.end(),
334 [&trk](
auto trkAtVtx) {
return trk == trkAtVtx.originalParams; });
335 if (foundIter != tracksAtVertex.end()) {
337 tracksAtVertex.erase(foundIter);
348 template <
typename vfitter_t,
typename sfinder_t>
351 const std::vector<const InputTrack_t*>& seedTracks,
353 std::vector<const InputTrack_t*>& tracksToFitOut,
354 std::vector<const InputTrack_t*>& tracksToFitSplitVertexOut,
357 int numberOfTracks = seedTracks.size();
362 for (
const auto& sTrack : seedTracks) {
365 if (numberOfTracks <= 2) {
366 tracksToFitOut.push_back(sTrack);
368 }
else if (numberOfTracks <= 4 && !
m_cfg.createSplitVertices) {
369 tracksToFitOut.push_back(sTrack);
371 }
else if (numberOfTracks <= 4 *
m_cfg.splitVerticesTrkInvFraction &&
372 m_cfg.createSplitVertices) {
373 if (count %
m_cfg.splitVerticesTrkInvFraction != 0) {
374 tracksToFitOut.push_back(sTrack);
377 tracksToFitSplitVertexOut.push_back(sTrack);
385 auto distanceRes =
m_cfg.ipEst.calculateDistance(
388 if (!distanceRes.ok()) {
389 return distanceRes.error();
393 return VertexingError::NoCovariance;
397 double hypotVariance =
401 if (hypotVariance == 0.) {
403 "Track impact parameter covariances are zero. Track was not "
404 "assigned to vertex.");
408 if (*distanceRes / hypotVariance <
m_cfg.significanceCutSeeding) {
409 if (!
m_cfg.createSplitVertices ||
410 count %
m_cfg.splitVerticesTrkInvFraction != 0) {
411 tracksToFitOut.push_back(sTrack);
414 tracksToFitSplitVertexOut.push_back(sTrack);
423 template <
typename vfitter_t,
typename sfinder_t>
428 std::vector<const InputTrack_t*>& tracksToFit,
429 std::vector<const InputTrack_t*>& seedTracks,
430 const std::vector<const InputTrack_t*>& ,
433 int numberOfAddedTracks = 0;
435 const std::shared_ptr<PerigeeSurface> currentVertexPerigeeSurface =
436 Surface::makeShared<PerigeeSurface>(
441 for (
auto& vertexIt : vertexCollection) {
443 std::vector<TrackAtVertex<InputTrack_t>> tracksAtVertex = vertexIt.tracks();
444 auto tracksBegin = tracksAtVertex.begin();
445 auto tracksEnd = tracksAtVertex.end();
447 const std::shared_ptr<PerigeeSurface> vertexItPerigeeSurface =
448 Surface::makeShared<PerigeeSurface>(
451 for (
auto tracksIter = tracksBegin; tracksIter != tracksEnd;) {
454 if (tracksIter->trackWeight >
m_cfg.cutOffTrackWeightReassign) {
460 m_extractParameters(*(tracksIter->originalParams));
463 auto resultNew = getCompatibility(origParams, currentVertex,
464 *currentVertexPerigeeSurface,
465 vertexingOptions, state);
466 if (!resultNew.ok()) {
469 double chi2NewVtx = *resultNew;
472 getCompatibility(origParams, vertexIt, *vertexItPerigeeSurface,
473 vertexingOptions, state);
474 if (!resultOld.ok()) {
477 double chi2OldVtx = *resultOld;
479 ACTS_DEBUG(
"Compatibility to new vs old vertex: " << chi2NewVtx <<
" vs "
482 if (chi2NewVtx < chi2OldVtx) {
483 tracksToFit.push_back(tracksIter->originalParams);
489 seedTracks.push_back(tracksIter->originalParams);
496 numberOfAddedTracks += 1;
499 tracksIter = tracksAtVertex.erase(tracksIter);
500 tracksBegin = tracksAtVertex.begin();
501 tracksEnd = tracksAtVertex.end();
511 vertexIt.setTracksAtVertex(tracksAtVertex);
515 <<
" tracks from old (other) vertices for new fit");
522 auto fitResult =
m_cfg.vertexFitter.fit(
524 if (fitResult.ok()) {
530 auto fitResult =
m_cfg.vertexFitter.fit(
532 if (fitResult.ok()) {
540 double ndf = currentVertex.
fitQuality().second;
543 int nTracksAtVertex = countSignificantTracks(currentVertex);
546 nTracksAtVertex >= 2) ||
548 nTracksAtVertex >= 2));
551 removeTracks(tracksToFit, seedTracks);
554 << seedTracks.size() <<
"seed tracks after BAD vertex.");
560 template <
typename vfitter_t,
typename sfinder_t>
563 return std::count_if(vtx.
tracks().begin(), vtx.
tracks().end(),
565 return trk.trackWeight >
m_cfg.cutOffTrackWeight;