LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
PMAlgTracking.cxx
Go to the documentation of this file.
1 // Class: PMAlgTracking
3 // Author: D.Stefan (Dorota.Stefan@ncbj.gov.pl),
4 // R.Sulej (Robert.Sulej@cern.ch),
5 // L.Whitehead (leigh.howard.whitehead@cern.ch), June 2016
7 
11 
13 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h"
15 
17 
18 #include "TMath.h"
19 
23 
24 recob::Track pma::convertFrom(const pma::Track3D& src, unsigned int tidx, int pdg)
25 {
26  std::vector<Point_t> positions;
27  positions.reserve(src.size());
28  std::vector<Vector_t> momenta;
29  momenta.reserve(src.size());
30  std::vector<recob::TrajectoryPointFlags> outFlags;
31  outFlags.reserve(src.size());
32 
33  for (size_t i = 0, h = 0; i < src.size(); i++)
34  if (src[i]->IsEnabled()) {
35  auto const& point3d = src[i]->Point3D();
36  positions.emplace_back(point3d.X(), point3d.Y(), point3d.Z());
37  momenta.push_back(src.GetDirection3D(i));
38  outFlags.emplace_back(h++, recob::TrajectoryPointFlags::makeMask());
39  }
40 
41  int ndof = 0;
42  float totChi2 = 0;
43 
44  SMatrixSym55 covStart, covEnd;
45  return recob::Track(
46  recob::TrackTrajectory(std::move(positions), std::move(momenta), std::move(outFlags), false),
47  pdg,
48  totChi2,
49  ndof,
50  covStart,
51  covEnd,
52  tidx);
53 }
54 // ------------------------------------------------------
55 
57  const pma::ProjectionMatchingAlg::Config& pmalgConfig,
58  const pma::PMAlgVertexing::Config& pmvtxConfig)
59  : fProjectionMatchingAlg(pmalgConfig), fPMAlgVertexing(pmvtxConfig)
60 {
61  unsigned int cryo, tpc, view;
62  for (auto const& h : allhitlist) {
63  cryo = h->WireID().Cryostat;
64  tpc = h->WireID().TPC;
65  view = h->WireID().Plane;
66 
67  fHitMap[cryo][tpc][view].push_back(h);
68  }
69 }
70 // ------------------------------------------------------
71 
73 {
74  for (auto t : fResult.tracks())
75  t.DeleteTrack();
76 }
77 // ------------------------------------------------------
78 
80  pma::TrkCandidateColl& tracks)
81 {
82  for (auto const& t : tracks.tracks()) {
83  auto& trk = *(t.Track());
84 
85  unsigned int tpc = trk.FrontTPC(), cryo = trk.FrontCryo();
86  if ((tpc == trk.BackTPC()) && (cryo == trk.BackCryo())) {
87  fProjectionMatchingAlg.guideEndpoints(detProp, trk, fHitMap[cryo][tpc]);
88  }
89  else {
91  detProp, trk, pma::Track3D::kBegin, fHitMap[trk.FrontCryo()][trk.FrontTPC()]);
93  detProp, trk, pma::Track3D::kEnd, fHitMap[trk.BackCryo()][trk.BackTPC()]);
94  }
95  }
96 }
97 // ------------------------------------------------------
98 // ------------------------------------------------------
99 // ------------------------------------------------------
100 
102  const std::vector<recob::Cluster>& clusters,
103  const std::vector<recob::PFParticle>& pfparticles,
104  const art::FindManyP<recob::Hit>& hitsFromClusters,
105  const art::FindManyP<recob::Cluster>& clusFromPfps,
106  const art::FindManyP<recob::Vertex>& vtxFromPfps,
107  const pma::ProjectionMatchingAlg::Config& pmalgConfig,
108  const pma::PMAlgFitter::Config& pmalgFitterConfig,
109  const pma::PMAlgVertexing::Config& pmvtxConfig)
110  : PMAlgTrackingBase(allhitlist, pmalgConfig, pmvtxConfig)
111  , fTrackingOnlyPdg(pmalgFitterConfig.TrackingOnlyPdg())
112  , fTrackingSkipPdg(pmalgFitterConfig.TrackingSkipPdg())
113  , fRunVertexing(pmalgFitterConfig.RunVertexing())
114 {
115  mf::LogVerbatim("PMAlgFitter") << "Found " << allhitlist.size() << "hits in the event.";
116  mf::LogVerbatim("PMAlgFitter") << "Sort hits by clusters assigned to PFParticles...";
117 
118  fCluHits.resize(clusters.size());
119  for (size_t i = 0; i < pfparticles.size(); ++i) {
120  fPfpPdgCodes[i] = pfparticles[i].PdgCode();
121 
122  auto cv = clusFromPfps.at(i);
123  for (const auto& c : cv) {
124  fPfpClusters[i].push_back(c);
125  if (fCluHits[c.key()].empty()) {
126  auto hv = hitsFromClusters.at(c.key());
127  fCluHits[c.key()].reserve(hv.size());
128  for (auto const& h : hv)
129  fCluHits[c.key()].push_back(h);
130  }
131  }
132 
133  if (vtxFromPfps.isValid() && vtxFromPfps.at(i).size()) {
134  double xyz[3];
135  vtxFromPfps.at(i).front()->XYZ(xyz);
136  fPfpVtx[i] = pma::Vector3D(xyz[0], xyz[1], xyz[2]);
137  }
138  }
139 
140  mf::LogVerbatim("PMAlgFitter") << "...done, " << fCluHits.size() << " clusters from "
141  << fPfpClusters.size() << " pfparticles for 3D tracking.";
142 }
143 // ------------------------------------------------------
144 
145 // ------------------------------------------------------
146 // ------------------------------------------------------
148 {
149  if (!fPfpClusters.empty() && !fCluHits.empty()) {
150  // build pm tracks
151  buildTracks(detProp);
152 
153  // add 3D ref.points for clean endpoints of wire-plae parallel tracks
154  guideEndpoints(detProp, fResult);
155 
156  if (fRunVertexing) fPMAlgVertexing.run(detProp, fResult);
157 
158  // build segment of shower
159  buildShowers(detProp);
160  }
161  else {
162  mf::LogWarning("PMAlgFitter") << "no clusters, no pfparticles";
163  return -1;
164  }
165 
166  return fResult.size();
167 }
168 // ------------------------------------------------------
169 // ------------------------------------------------------
170 
172 {
173  bool skipPdg = true;
174  if (!fTrackingSkipPdg.empty() && (fTrackingSkipPdg.front() == 0)) skipPdg = false;
175 
176  bool selectPdg = true;
177  if (!fTrackingOnlyPdg.empty() && (fTrackingOnlyPdg.front() == 0)) selectPdg = false;
178 
179  for (const auto& pfpCluEntry : fPfpClusters) {
180  int pfPartIdx = pfpCluEntry.first;
181  int pdg = fPfpPdgCodes[pfPartIdx];
182 
183  //if (pdg == 11) continue;
184  if (skipPdg && has(fTrackingSkipPdg, pdg)) continue;
185  if (selectPdg && !has(fTrackingOnlyPdg, pdg)) continue;
186 
187  mf::LogVerbatim("PMAlgFitter") << "Process clusters from PFP:" << pfPartIdx << ", pdg:" << pdg;
188 
189  std::vector<art::Ptr<recob::Hit>> allHits;
190 
191  pma::TrkCandidate candidate;
192  std::unordered_map<geo::View_t, size_t> clu_count;
193  for (const auto& c : pfpCluEntry.second) {
194  if (c->NHits() == 0) { continue; }
195 
196  candidate.Clusters().push_back(c.key());
197  clu_count[c->View()]++;
198 
199  allHits.reserve(allHits.size() + fCluHits.at(c.key()).size());
200  for (const auto& h : fCluHits.at(c.key())) {
201  allHits.push_back(h);
202  }
203  }
204  if (clu_count.size() > 1) // try building only if there are clusters from multiple views
205  {
206  candidate.SetKey(pfpCluEntry.first);
207 
208  candidate.SetTrack(fProjectionMatchingAlg.buildMultiTPCTrack(detProp, allHits));
209 
210  if (candidate.IsValid() && candidate.Track()->HasTwoViews() &&
211  (candidate.Track()->Nodes().size() > 1)) {
212  if (!std::isnan(candidate.Track()->Length())) { fResult.push_back(candidate); }
213  else {
214  mf::LogError("PMAlgFitter") << "Trajectory fit lenght is nan.";
215  candidate.DeleteTrack();
216  }
217  }
218  else {
219  candidate.DeleteTrack();
220  }
221  }
222  }
223 }
224 // ------------------------------------------------------
225 
227 {
228  bool skipPdg = true;
229  if (!fTrackingSkipPdg.empty() && (fTrackingSkipPdg.front() == 0)) skipPdg = false;
230 
231  bool selectPdg = true;
232  if (!fTrackingOnlyPdg.empty() && (fTrackingOnlyPdg.front() == 0)) selectPdg = false;
233 
234  for (const auto& pfpCluEntry : fPfpClusters) {
235  int pfPartIdx = pfpCluEntry.first;
236  int pdg = fPfpPdgCodes[pfPartIdx];
237 
238  if (pdg != 11) continue;
239  if (skipPdg && has(fTrackingSkipPdg, pdg)) continue;
240  if (selectPdg && !has(fTrackingOnlyPdg, pdg)) continue;
241 
242  mf::LogVerbatim("PMAlgFitter") << "Process clusters from PFP:" << pfPartIdx << ", pdg:" << pdg;
243 
244  std::vector<art::Ptr<recob::Hit>> allHits;
245 
246  pma::TrkCandidate candidate;
247  std::unordered_map<geo::View_t, size_t> clu_count;
248  for (const auto& c : pfpCluEntry.second) {
249  if (c->NHits() == 0) { continue; }
250 
251  candidate.Clusters().push_back(c.key());
252  clu_count[c->View()]++;
253 
254  allHits.reserve(allHits.size() + fCluHits.at(c.key()).size());
255  for (const auto& h : fCluHits.at(c.key()))
256  allHits.push_back(h);
257  }
258  if (clu_count.size() > 1) // try building only if there are clusters from multiple views
259  {
260  candidate.SetKey(pfpCluEntry.first);
261 
262  mf::LogVerbatim("PMAlgFitter") << "building..."
263  << ", pdg:" << pdg;
264 
265  auto search = fPfpVtx.find(pfPartIdx);
266  if (search != fPfpVtx.end()) {
267  candidate.SetTrack(fProjectionMatchingAlg.buildShowerSeg(detProp, allHits, search->second));
268 
269  if (candidate.IsValid() && candidate.Track()->HasTwoViews() &&
270  (candidate.Track()->Nodes().size() > 1) && !std::isnan(candidate.Track()->Length())) {
271  fResult.push_back(candidate);
272  }
273  else {
274  candidate.DeleteTrack();
275  }
276  }
277  }
278  }
279 }
280 // ------------------------------------------------------
281 // ------------------------------------------------------
282 // ------------------------------------------------------
283 
285  const std::vector<recob::Wire>& wires,
286  const pma::ProjectionMatchingAlg::Config& pmalgConfig,
287  const pma::PMAlgTracker::Config& pmalgTrackerConfig,
288  const pma::PMAlgVertexing::Config& pmvtxConfig,
289  const pma::PMAlgStitching::Config& pmstitchConfig,
290  const pma::PMAlgCosmicTagger::Config& pmtaggerConfig,
291 
292  const std::vector<TH1F*>& hpassing,
293  const std::vector<TH1F*>& hrejected)
294  : PMAlgTrackingBase(allhitlist, pmalgConfig, pmvtxConfig)
295  , fWires(wires)
296  , fMinSeedSize1stPass(pmalgTrackerConfig.MinSeedSize1stPass())
297  , fMinSeedSize2ndPass(pmalgTrackerConfig.MinSeedSize2ndPass())
298  , fTrackLikeThreshold(pmalgTrackerConfig.TrackLikeThreshold())
299  , fMinTwoViewFraction(pmalgConfig.MinTwoViewFraction())
300  , fFlipToBeam(pmalgTrackerConfig.FlipToBeam())
301  , fFlipDownward(pmalgTrackerConfig.FlipDownward())
302  , fFlipToX(pmalgTrackerConfig.FlipToX())
303  , fAutoFlip_dQdx(pmalgTrackerConfig.AutoFlip_dQdx())
304  , fMergeWithinTPC(pmalgTrackerConfig.MergeWithinTPC())
305  , fMergeTransverseShift(pmalgTrackerConfig.MergeTransverseShift())
306  , fMergeAngle(pmalgTrackerConfig.MergeAngle())
307  , fCosmicTagger(pmtaggerConfig)
308  , fTagCosmicTracks(fCosmicTagger.tagAny())
309  , fStitchBetweenTPCs(pmalgTrackerConfig.StitchBetweenTPCs())
310  , fStitchDistToWall(pmalgTrackerConfig.StitchDistToWall())
311  , fStitchTransverseShift(pmalgTrackerConfig.StitchTransverseShift())
312  , fStitchAngle(pmalgTrackerConfig.StitchAngle())
313  , fMatchT0inAPACrossing(pmalgTrackerConfig.MatchT0inAPACrossing())
314  , fMatchT0inCPACrossing(pmalgTrackerConfig.MatchT0inCPACrossing())
315  , fStitcher(pmstitchConfig)
316  , fRunVertexing(pmalgTrackerConfig.RunVertexing())
317  , fAdcInPassingPoints(hpassing)
318  , fAdcInRejectedPoints(hrejected)
319  , fGeom(&*(art::ServiceHandle<geo::Geometry const>()))
320 {
321  for (const auto v : fGeom->Views()) {
322  fAvailableViews.push_back(v);
323  }
324  std::reverse(fAvailableViews.begin(), fAvailableViews.end());
325 
326  mf::LogVerbatim("PMAlgTracker") << "Using views in the following order:";
327  for (const auto v : fAvailableViews) {
328  mf::LogInfo("PMAlgTracker") << " " << v;
329  }
330 
331  // ************************* track validation settings: **************************
332  mf::LogVerbatim("PMAlgTracker") << "Validation mode in config: "
333  << pmalgTrackerConfig.Validation();
334 
335  size_t nplanes = fGeom->MaxPlanes();
336  for (size_t p = 0; p < nplanes; ++p) {
337  fAdcImages.emplace_back(pmalgTrackerConfig.AdcImageAlg());
338  }
339 
340  if (pmalgTrackerConfig.Validation() == "hits") { fValidation = pma::PMAlgTracker::kHits; }
341  else if (pmalgTrackerConfig.Validation() == "adc") {
343  }
344  else if (pmalgTrackerConfig.Validation() == "calib") {
346  }
347  else {
348  throw cet::exception("pma::PMAlgTracker") << "validation name not supported" << std::endl;
349  }
350 
351  if ((nplanes < 3) && (fValidation != pma::PMAlgTracker::kHits)) {
352  mf::LogWarning("PMAlgTracker")
353  << "Not enough planes to perform validation, switch mode to hits.";
355  }
356 
357  fAdcValidationThr = pmalgTrackerConfig.AdcValidationThr();
359  mf::LogVerbatim("PMAlgTracker") << "Validation ADC thresholds per plane:";
360  for (auto thr : fAdcValidationThr) {
361  mf::LogVerbatim("PMAlgTracker") << " " << thr;
362  }
363  }
364 }
365 // ------------------------------------------------------
366 
368 {
369  mf::LogVerbatim("PMAlgTracker") << "Sort hits by clusters...";
370  fCluHits.clear();
371  fCluHits.reserve(hitsFromClusters.size());
372  fCluWeights.clear();
373  fCluWeights.reserve(fCluHits.size());
374  for (size_t i = 0; i < hitsFromClusters.size(); ++i) {
375  auto v = hitsFromClusters.at(i);
377  for (auto const& h : v)
378  fCluHits.back().push_back(h);
379  fCluWeights.push_back(1);
380  }
381  mf::LogVerbatim("PMAlgTracker") << "...done, " << fCluHits.size() << " clusters for 3D tracking.";
382 }
383 // ------------------------------------------------------
384 
386  const std::vector<float>& trackLike)
387 {
388  mf::LogVerbatim("PMAlgTracker") << "Filter track-like clusters using likelihood values...";
389  fCluHits.clear();
390  fCluHits.reserve(hitsFromClusters.size());
391  fCluWeights.clear();
392  fCluWeights.reserve(fCluHits.size());
393  for (size_t i = 0; i < hitsFromClusters.size(); ++i) {
394  auto v = hitsFromClusters.at(i);
396  for (auto const& h : v)
397  fCluHits.back().push_back(h);
398  fCluWeights.push_back(trackLike[i]);
399  }
400 }
401 // ------------------------------------------------------
402 
404  const art::FindManyP<recob::Hit>& hitsFromEmParts)
405 {
406  mf::LogVerbatim("PMAlgTracker") << "Filter track-like clusters...";
407  fCluHits.clear();
408  fCluHits.reserve(hitsFromClusters.size());
409  fCluWeights.clear();
410  fCluWeights.reserve(fCluHits.size());
411  size_t n = 0; // count not-empty clusters
412  for (size_t i = 0; i < hitsFromClusters.size(); ++i) {
413  auto v = hitsFromClusters.at(i);
415  for (auto const& h : v) {
416  bool trkLike = true;
417  for (size_t j = 0; j < hitsFromEmParts.size(); ++j) {
418  auto u = hitsFromEmParts.at(j);
419  for (auto const& g : u) // is hit clustered in one of em-like?
420  {
421  if (g.key() == h.key()) {
422  trkLike = false;
423  break;
424  }
425  }
426  if (!trkLike) break;
427  }
428  if (trkLike) fCluHits.back().push_back(h);
429  }
430  if (!fCluHits.back().empty()) {
431  fCluWeights.push_back(1);
432  ++n;
433  }
434  else {
435  fCluWeights.push_back(0);
436  }
437  }
438  mf::LogVerbatim("PMAlgTracker") << "...done, " << n << " clusters for 3D tracking.";
439 }
440 // ------------------------------------------------------
441 
443  pma::Track3D& trk,
444  unsigned int testView)
445 {
446  if ((trk.FirstElement()->GetDistToWall() < -3.0) || (trk.LastElement()->GetDistToWall() < -3.0)) {
447  mf::LogVerbatim("PMAlgTracker") << "first or last node too far out of its initial TPC";
448  return 0.0;
449  }
450 
451  if (testView != geo::kUnknown) {
452  mf::LogVerbatim("PMAlgTracker") << "validation in plane: " << testView;
453  }
454  else {
455  return 1.0;
456  }
457 
458  double v = 0;
460  {
461  } -> GetProvider();
462  switch (fValidation) {
465  detProp, channelStatus, trk, fAdcImages[testView], fAdcValidationThr[testView]);
466  break;
467 
470  detProp, channelStatus, trk, fHitMap[trk.FrontCryo()][trk.FrontTPC()][testView]);
471  break;
472 
475  detProp,
476  channelStatus,
477  trk,
478  fAdcImages[testView],
479  fHitMap[trk.FrontCryo()][trk.FrontTPC()][testView],
480  fAdcInPassingPoints[testView],
481  fAdcInRejectedPoints[testView]);
482  break;
483 
484  default:
485  throw cet::exception("pma::PMAlgTracker") << "validation mode not supported" << std::endl;
486  break;
487  }
488 
489  return v;
490 }
491 // ------------------------------------------------------
492 
495  pma::TrkCandidateColl& tracks,
496  size_t trk_idx,
497  double dist2)
498 {
499  pma::Track3D* trk1 = tracks[trk_idx].Track();
500 
501  bool result = false;
502  if ((hits.size() > 1) || (dist2 > 1.0)) // min. 2 hits or single hit separated from the rest
503  {
504  pma::Track3D* best_trk = 0;
505 
506  size_t best_u = 0, n_max = 0;
507  for (size_t u = 0; u < tracks.size(); u++)
508  if (trk_idx != u) {
509  pma::Track3D* trk2 = tracks[u].Track();
510  size_t n = fProjectionMatchingAlg.testHits(detProp, *trk2, hits);
511  if (n > n_max) {
512  n_max = n;
513  best_u = u;
514  best_trk = trk2;
515  }
516  }
517 
518  if (best_trk && (n_max >= hits.size() / 3)) // /2
519  {
520  mf::LogVerbatim("PMAlgTrackMaker") << " Reassign(v1) " << n_max << " hits." << std::endl;
521 
522  trk1->RemoveHits(hits);
523  trk1->CleanupTails();
524  trk1->ShiftEndsToHits();
525 
526  pma::Track3D* ext = fProjectionMatchingAlg.extendTrack(detProp, *best_trk, hits, false);
527  ext->SortHits();
528  ext->ShiftEndsToHits();
530  tracks[best_u].SetTrack(ext); // and this deletes best_trk stored at best_u
531  result = true;
532  }
533  else
534  delete ext;
535  }
536  else if (hits.size() >= fMinSeedSize2ndPass) {
537  size_t minSizeCompl = hits.size() / 8; // much smaller minimum required in complementary views
538  if (minSizeCompl < 3) minSizeCompl = 3; // but at least three hits!
539 
540  geo::View_t first_view = (geo::View_t)hits.front()->WireID().Plane;
541  unsigned int tpc = hits.front()->WireID().TPC;
542  unsigned int cryo = hits.front()->WireID().Cryostat;
543 
544  pma::TrkCandidate candidate =
545  matchCluster(detProp, -1, hits, minSizeCompl, tpc, cryo, first_view);
546 
547  if (candidate.IsGood()) {
548  mf::LogVerbatim("PMAlgTrackMaker")
549  << " Add new track, cut hits from source track." << std::endl;
550  tracks.push_back(candidate);
551 
552  trk1->RemoveHits(hits);
553  trk1->CleanupTails();
554  trk1->ShiftEndsToHits();
555  }
556  }
557  }
558  else if ((hits.size() == 1) || (dist2 > 2.25)) // dist > 1.5cm
559  {
560  mf::LogVerbatim("PMAlgTrackMaker") << " Cut single-view isolated hit." << std::endl;
561  trk1->RemoveHits(hits);
562  trk1->CleanupTails();
563  trk1->ShiftEndsToHits();
564  }
565  return result;
566 }
567 
570 {
571  size_t idx = 0;
572  while ((idx < trk.size() - 1) && !(trk[idx]->IsEnabled())) {
573  hits.push_back(trk[idx++]->Hit2DPtr());
574  }
575 
576  double d2 = 0.0;
577  if (idx > 0) {
578  if ((idx < trk.size() - 1) && (trk[idx]->View2D() == trk[idx - 1]->View2D())) {
579  double dprev = pma::Dist2(trk[idx]->Point3D(), trk[idx - 1]->Point3D());
580  double dnext = pma::Dist2(trk[idx]->Point3D(), trk[idx + 1]->Point3D());
581  if (dprev < dnext) { hits.push_back(trk[idx++]->Hit2DPtr()); }
582  }
583  d2 = pma::Dist2(trk[idx]->Point3D(), trk[idx - 1]->Point3D());
584  }
585  return d2;
586 }
587 
590 {
591  size_t idx = trk.size() - 1;
592  while ((idx > 0) && !(trk[idx]->IsEnabled())) {
593  hits.push_back(trk[idx--]->Hit2DPtr());
594  }
595 
596  double d2 = 0.0;
597  if (idx < trk.size() - 1) {
598  if ((idx > 0) && (trk[idx]->View2D() == trk[idx + 1]->View2D())) {
599  double dprev = pma::Dist2(trk[idx]->Point3D(), trk[idx + 1]->Point3D());
600  double dnext = pma::Dist2(trk[idx]->Point3D(), trk[idx - 1]->Point3D());
601  if (dprev < dnext) { hits.push_back(trk[idx--]->Hit2DPtr()); }
602  }
603  d2 = pma::Dist2(trk[idx]->Point3D(), trk[idx + 1]->Point3D());
604  }
605  return d2;
606 }
607 
609  pma::TrkCandidateColl& tracks)
610 {
611  bool result = false;
612  for (size_t t = 0; t < tracks.size(); t++) {
613  pma::Track3D& trk = *(tracks[t].Track());
614  if (trk.size() < 6) continue;
615 
616  trk.DisableSingleViewEnds();
617 
618  std::vector<art::Ptr<recob::Hit>> hits;
619 
620  double d2 = collectSingleViewEnd(trk, hits);
621  result |= reassignHits_1(detProp, hits, tracks, t, d2);
622 
623  hits.clear();
624 
625  d2 = collectSingleViewFront(trk, hits);
626  result |= reassignHits_1(detProp, hits, tracks, t, d2);
627 
628  trk.SelectHits();
629  }
630  return result;
631 }
632 
634  pma::Track3D* trk2,
635  double& dist,
636  double& cos3d,
637  bool& reverseOrder,
638  double distThr,
639  double distThrMin,
640  double distProjThr,
641  double cosThr) const
642 {
643  double lmax;
644  double l1 = trk1->Length();
645  double l2 = trk2->Length();
646 
647  if (l1 > l2)
648  lmax = l1;
649  else
650  lmax = l2;
651 
652  double d = lmax * distThr;
653  if (d < distThrMin) d = distThrMin;
654 
655  unsigned int k = 0;
656  double distFF = pma::Dist2(trk1->front()->Point3D(), trk2->front()->Point3D());
657  dist = distFF;
658 
659  double distFB = pma::Dist2(trk1->front()->Point3D(), trk2->back()->Point3D());
660  if (distFB < dist) {
661  k = 1;
662  dist = distFB;
663  }
664 
665  double distBF = pma::Dist2(trk1->back()->Point3D(), trk2->front()->Point3D());
666  if (distBF < dist) {
667  k = 2;
668  dist = distBF;
669  }
670 
671  double distBB = pma::Dist2(trk1->back()->Point3D(), trk2->back()->Point3D());
672  if (distBB < dist) {
673  k = 3;
674  dist = distBB;
675  }
676 
677  dist = sqrt(dist);
678  cos3d = 0.0;
679 
680  if (dist < d) {
681  pma::Track3D* tmp = 0;
682  switch (k) // swap or flip to get trk1 end before trk2 start
683  {
684  case 0:
685  trk1->Flip(); // detProp);
686  break;
687  case 1:
688  tmp = trk1;
689  trk1 = trk2;
690  trk2 = tmp;
691  break;
692  case 2: break;
693  case 3:
694  trk2->Flip(); // detProp);
695  break;
696  default: mf::LogError("PMAlgTracker") << "Should never happen.";
697  }
698  if (k == 1)
699  reverseOrder = true;
700  else
701  reverseOrder = false;
702 
703  size_t nodeEndIdx = trk1->Nodes().size() - 1;
704 
705  TVector3 endpoint1 = trk1->back()->Point3D();
706  TVector3 trk2front0 = trk2->Nodes()[0]->Point3D();
707  TVector3 trk2front1 = trk2->Nodes()[1]->Point3D();
708  TVector3 proj1 = pma::GetProjectionToSegment(endpoint1, trk2front0, trk2front1);
709  double distProj1 = sqrt(pma::Dist2(endpoint1, proj1));
710 
711  TVector3 endpoint2 = trk2->front()->Point3D();
712  TVector3 trk1back0 = trk1->Nodes()[nodeEndIdx]->Point3D();
713  TVector3 trk1back1 = trk1->Nodes()[nodeEndIdx - 1]->Point3D();
714  TVector3 proj2 = pma::GetProjectionToSegment(endpoint2, trk1back1, trk1back0);
715  double distProj2 = sqrt(pma::Dist2(endpoint2, proj2));
716 
717  pma::Vector3D dir1 = trk1->Segments().back()->GetDirection3D();
718  pma::Vector3D dir2 = trk2->Segments().front()->GetDirection3D();
719 
720  cos3d = dir1.Dot(dir2);
721 
722  if ((cos3d > cosThr) && (distProj1 < distProjThr) && (distProj2 < distProjThr))
723  return true;
724  else // check if parallel to wires & colinear in 2D
725  {
726  const double maxCosXZ = 0.996195; // 5 deg
727 
728  pma::Vector3D dir1_xz(dir1.X(), 0., dir1.Z());
729  dir1_xz *= 1.0 / dir1_xz.R();
730 
731  pma::Vector3D dir2_xz(dir2.X(), 0., dir2.Z());
732  dir2_xz *= 1.0 / dir2_xz.R();
733 
734  if ((fabs(dir1_xz.Z()) > maxCosXZ) && (fabs(dir2_xz.Z()) > maxCosXZ)) {
735  endpoint1.SetY(0.);
736  trk2front0.SetY(0.);
737  trk2front1.SetY(0.);
738  proj1 = pma::GetProjectionToSegment(endpoint1, trk2front0, trk2front1);
739  distProj1 = sqrt(pma::Dist2(endpoint1, proj1));
740 
741  endpoint2.SetY(0.);
742  trk1back0.SetY(0.);
743  trk1back1.SetY(0.);
744  proj2 = pma::GetProjectionToSegment(endpoint2, trk1back1, trk1back0);
745  distProj2 = sqrt(pma::Dist2(endpoint2, proj2));
746 
747  double cosThrXZ = cos(0.5 * acos(cosThr));
748  double distProjThrXZ = 0.5 * distProjThr;
749  double cosXZ = dir1_xz.Dot(dir2_xz);
750  if ((cosXZ > cosThrXZ) && (distProj1 < distProjThrXZ) && (distProj2 < distProjThrXZ))
751  return true;
752  }
753  }
754  }
755  return false;
756 }
757 
759  pma::TrkCandidateColl& tracks) const
760 {
761  double distThr = 0.25; // max gap as a fraction of the longer track length
762  double distThrMin = 0.5; // lower limit of max gap threshold [cm]
763 
764  double distProjThr = fMergeTransverseShift;
765  double cosThr = cos(TMath::Pi() * fMergeAngle / 180.0);
766 
767  bool foundMerge = false;
768 
769  std::sort(tracks.tracks().begin(), tracks.tracks().end(), pma::bTrack3DLonger());
770 
771  bool r;
772  double d, dmin, c, cmax, l, lbest;
773  size_t t = 0, u = 0;
774  while (t < tracks.size()) {
775  pma::Track3D* trk1 = tracks[t].Track();
776 
777  pma::Track3D* trk2 = 0;
778  pma::Track3D* best_trk2 = 0;
779  dmin = 1.0e12;
780  cmax = 0;
781  lbest = 0;
782  size_t ubest = 0;
783  for (u = t + 1; u < tracks.size(); u++) {
784  trk2 = tracks[u].Track();
785  if (areCoLinear(trk1, trk2, d, c, r, distThr, distThrMin, distProjThr, cosThr)) {
786  l = std::sqrt(pma::Dist2(trk2->front()->Point3D(), trk2->back()->Point3D()));
787  if (((c > cmax) && (d < dmin + 0.5 * lbest)) || ((d < dmin) && (l > 1.5 * lbest))) {
788  cmax = c;
789  dmin = d;
790  best_trk2 = trk2;
791  lbest = l;
792  ubest = u;
793  }
794  }
795  trk2 = 0;
796  }
797  trk2 = best_trk2;
798 
799  if (trk2) {
800  mf::LogVerbatim("PMAlgTracker")
801  << "Merge track (" << trk1->size() << ") with track (" << trk2->size() << ")";
802  if (r) {
803  fProjectionMatchingAlg.mergeTracks(detProp, *trk2, *trk1, true);
804  tracks[t].SetTrack(trk2); // deletes old trk1
805  }
806  else {
807  fProjectionMatchingAlg.mergeTracks(detProp, *trk1, *trk2, true);
808  tracks[ubest].DeleteTrack();
809  }
810  tracks.erase_at(ubest);
811  foundMerge = true;
812  }
813  else
814  t++;
815  }
816 
817  return foundMerge;
818 }
819 // ------------------------------------------------------
820 
822 {
823  for (auto const& trk : tracks.tracks())
824  for (auto node : trk.Track()->Nodes())
825  if (node->IsBranching()) node->SetFrozen(true);
826 }
828 {
829  for (auto const& trk : tracks.tracks())
830  for (auto node : trk.Track()->Nodes())
831  node->SetFrozen(false);
832 }
833 
835  detinfo::DetectorPropertiesData const& detProp,
836  pma::tpc_track_map& tracks) const
837 {
838  double distThr = 0.25; // max gap as a fraction of the longer track length
839  double distThrMin = 2.5; // lower limit of max gap threshold [cm]
840 
841  double distProjThr = fStitchTransverseShift;
842  double cosThr = cos(TMath::Pi() * fStitchAngle / 180.0);
843 
844  double wallDistThr = fStitchDistToWall;
845  double dfront1, dback1, dfront2, dback2;
846 
847  for (auto& tpc_entry1 : tracks) {
848  unsigned int tpc1 = tpc_entry1.first;
849  pma::TrkCandidateColl& tracks1 = tpc_entry1.second;
850 
851  size_t t = 0;
852  while (t < tracks1.size()) {
853  bool r, reverse = false;
854  double l, lbest = 0, d, dmin = 1.0e12, c, cmax = 0.0;
855  pma::Track3D* best_trk2 = 0;
856  unsigned int best_tpc = 0;
857  size_t best_idx = 0;
858 
859  pma::Track3D* trk1 = tracks1[t].Track();
860  dfront1 = trk1->Nodes().front()->GetDistToWall();
861  dback1 = trk1->Nodes().back()->GetDistToWall();
862  if ((dfront1 < wallDistThr) || (dback1 < wallDistThr)) {
863  for (auto& tpc_entry2 : tracks) {
864  unsigned int tpc2 = tpc_entry2.first;
865  if (tpc2 == tpc1) continue;
866 
867  pma::TrkCandidateColl& tracks2 = tpc_entry2.second;
868 
869  for (size_t u = 0; u < tracks2.size(); u++) {
870  pma::Track3D* trk2 = tracks2[u].Track();
871  dfront2 = trk2->Nodes().front()->GetDistToWall();
872  dback2 = trk2->Nodes().back()->GetDistToWall();
873  if ((dfront2 < wallDistThr) || (dback2 < wallDistThr)) {
874  if (areCoLinear(trk1, trk2, d, c, r, distThr, distThrMin, distProjThr, cosThr)) {
875  l = std::sqrt(pma::Dist2(trk2->front()->Point3D(), trk2->back()->Point3D()));
876  if (((c > cmax) && (d < dmin + 0.5 * lbest)) || (0.75 * l < dmin)) {
877  cmax = c;
878  dmin = d;
879  lbest = l;
880  best_trk2 = trk2;
881  best_tpc = tpc2;
882  best_idx = u;
883  reverse = r;
884  }
885  }
886  }
887  }
888  }
889  }
890 
891  if (best_trk2) {
892  mf::LogVerbatim("PMAlgTracker")
893  << "Merge track (" << tpc1 << ":" << tracks1.size() << ":" << trk1->size()
894  << ") with track (" << best_tpc << ":" << tracks[best_tpc].size() << ":"
895  << best_trk2->size() << ")";
896  auto const* geom = lar::providerFrom<geo::Geometry>();
897  auto const* first_node_trk1 = trk1->Nodes().front();
898  const geo::TPCGeo& tpc1 =
899  geom->TPC(geo::TPCID(first_node_trk1->Cryo(), first_node_trk1->TPC()));
900  auto const* first_node_trk2 = best_trk2->Nodes().front();
901  const geo::TPCGeo& tpc2 =
902  geom->TPC(geo::TPCID(first_node_trk2->Cryo(), first_node_trk2->TPC()));
903  if (reverse) {
904  fProjectionMatchingAlg.mergeTracks(detProp, *best_trk2, *trk1, true);
905  // This track will have a shift in x equal to zero. This will
906  // properly set the track T0
907  if (tpc1.DetectDriftDirection() * tpc2.DetectDriftDirection() < 0) {
908  best_trk2->ApplyDriftShiftInTree(clockData, detProp, 0.0);
909  }
910  tracks1[t].SetTrack(best_trk2);
911  }
912  else {
913  fProjectionMatchingAlg.mergeTracks(detProp, *trk1, *best_trk2, true);
914  // This track will have a shift in x equal to zero. This will
915  // properly set the track T0
916  if (tpc1.DetectDriftDirection() * tpc2.DetectDriftDirection() < 0) {
917  trk1->ApplyDriftShiftInTree(clockData, detProp, 0.0);
918  }
919  tracks[best_tpc][best_idx].DeleteTrack();
920  }
921  tracks[best_tpc].erase_at(best_idx);
922  }
923  else
924  t++;
925  }
926  }
927 
928  //for (auto & tpc_entry : tracks) releaseAllNodes(tpc_entry.second);
929 }
930 // ------------------------------------------------------
931 
933  const pma::TrkCandidateColl& tracks,
934  const std::vector<art::Ptr<recob::Hit>>& hits) const
935 {
936  size_t max_hits = 0;
937  for (auto const& t : tracks.tracks()) {
938  size_t n = fProjectionMatchingAlg.testHits(detProp, *(t.Track()), hits);
939  if (n > max_hits) { max_hits = n; }
940  }
941  return max_hits;
942 }
943 
944 // ------------------------------------------------------
945 // ------------------------------------------------------
947  detinfo::DetectorPropertiesData const& detProp)
948 {
949  fInitialClusters.clear();
950  fTriedClusters.clear();
951  fUsedClusters.clear();
952 
953  size_t nplanes = fGeom->MaxPlanes();
954 
955  pma::tpc_track_map tracks; // track parts in tpc's
956 
957  for (auto const& tpcid : fGeom->Iterate<geo::TPCID>()) {
958  mf::LogVerbatim("PMAlgTracker")
959  << "Reconstruct tracks within Cryo:" << tpcid.Cryostat << " / TPC:" << tpcid.TPC << ".";
960 
961  if (fValidation != pma::PMAlgTracker::kHits) // initialize ADC images for all planes in
962  // this TPC (in "adc" and "calib")
963  {
964  mf::LogVerbatim("PMAlgTracker") << "Prepare validation ADC images...";
965  bool ok = true;
966  for (size_t p = 0; p < nplanes; ++p) {
967  ok &=
968  fAdcImages[p].setWireDriftData(clockData, detProp, fWires, p, tpcid.TPC, tpcid.Cryostat);
969  }
970  if (ok) { mf::LogVerbatim("PMAlgTracker") << " ...done."; }
971  else {
972  mf::LogVerbatim("PMAlgTracker") << " ...failed.";
973  continue;
974  }
975  }
976 
977  // find reasonably large parts
978  fromMaxCluster_tpc(detProp, tracks[tpcid.TPC], fMinSeedSize1stPass, tpcid.TPC, tpcid.Cryostat);
979  // loop again to find small things
980  fromMaxCluster_tpc(detProp, tracks[tpcid.TPC], fMinSeedSize2ndPass, tpcid.TPC, tpcid.Cryostat);
981 
982  //tryClusterLeftovers();
983 
984  mf::LogVerbatim("PMAlgTracker") << "Found tracks: " << tracks[tpcid.TPC].size();
985  if (tracks[tpcid.TPC].empty()) { continue; }
986 
987  // add 3D ref.points for clean endpoints of wire-plane parallel track
988  guideEndpoints(detProp, tracks[tpcid.TPC]);
989  // try correcting single-view sections spuriously merged on 2D clusters
990  // level
991  reassignSingleViewEnds_1(detProp, tracks[tpcid.TPC]);
992 
993  if (fMergeWithinTPC) {
994  mf::LogVerbatim("PMAlgTracker") << "Merge co-linear tracks within TPC " << tpcid.TPC << ".";
995  while (mergeCoLinear(detProp, tracks[tpcid.TPC])) {
996  mf::LogVerbatim("PMAlgTracker") << " found co-linear tracks";
997  }
998  }
999  }
1000 
1001  if (fStitchBetweenTPCs) {
1002  mf::LogVerbatim("PMAlgTracker") << "Stitch co-linear tracks between TPCs.";
1003  mergeCoLinear(clockData, detProp, tracks);
1004  }
1005 
1006  for (auto& tpc_entry : tracks) // put tracks in the single collection
1007  for (auto& trk : tpc_entry.second.tracks()) {
1008  if (trk.Track()->HasTwoViews() && (trk.Track()->Nodes().size() > 1)) {
1010  }
1011  else {
1012  trk.DeleteTrack();
1013  }
1014  }
1015 
1016  if (fTagCosmicTracks) {
1017  mf::LogVerbatim("PMAlgTracker") << "Tag cosmic tracks activity.";
1018  fCosmicTagger.tag(clockData, fResult);
1019  }
1020 
1021  if (fRunVertexing) {
1022  mf::LogVerbatim("PMAlgTracker") << "Vertex finding / track-vertex reoptimization.";
1023  fPMAlgVertexing.run(detProp, fResult);
1024  }
1025 
1026  fResult.setTreeIds();
1027 
1028  if (fMatchT0inCPACrossing) {
1029  mf::LogVerbatim("PMAlgTracker") << "Find co-linear CPA-crossing tracks with any T0.";
1030  fStitcher.StitchTracksCPA(clockData, detProp, fResult);
1031  }
1032 
1033  if (fMatchT0inAPACrossing) {
1034  mf::LogVerbatim("PMAlgTracker") << "Find co-linear APA-crossing tracks with any T0.";
1035  fStitcher.StitchTracksAPA(clockData, detProp, fResult);
1036  }
1037 
1038  if (fTagCosmicTracks) {
1039  mf::LogVerbatim("PMAlgTracker") << "Second pass cosmic tagging for stitched tracks";
1040  fCosmicTagger.tag(clockData, fResult);
1041  }
1042 
1043  if (fFlipToBeam)
1045  2); // flip the tracks / trees to the beam direction (Z)
1046  else if (fFlipDownward)
1048  1); // flip the tracks / trees to point downward (-Y)
1049  else if (fFlipToX)
1051  0); // flip the tracks / trees to point in -X
1052  // direction (downwards for dual phase)
1053 
1054  if (fAutoFlip_dQdx)
1055  fResult.flipTreesByDQdx(); // flip the tracks / trees to get best dQ/dx sequences
1056 
1058 
1059  listUsedClusters(detProp);
1060  return fResult.size();
1061 }
1062 // ------------------------------------------------------
1063 // ------------------------------------------------------
1064 
1067  size_t minBuildSize,
1068  unsigned int tpc,
1069  unsigned int cryo)
1070 {
1071  fInitialClusters.clear();
1072 
1073  size_t minSizeCompl = minBuildSize / 8; // smaller minimum required in complementary views
1074  if (minSizeCompl < 2) minSizeCompl = 2; // but at least two hits!
1075 
1076  int max_first_idx = 0;
1077  while (max_first_idx >= 0) // loop over clusters, any view, starting from the largest
1078  {
1079  mf::LogVerbatim("PMAlgTracker") << "Find max cluster...";
1080  max_first_idx =
1081  maxCluster(minBuildSize, geo::kUnknown, tpc, cryo); // any view, but must be track-like
1082  if ((max_first_idx >= 0) && !fCluHits[max_first_idx].empty()) {
1083  geo::View_t first_view = fCluHits[max_first_idx].front()->View();
1084 
1085  pma::TrkCandidate candidate =
1086  matchCluster(detProp, max_first_idx, minSizeCompl, tpc, cryo, first_view);
1087 
1088  if (candidate.IsGood()) result.push_back(candidate);
1089  }
1090  else
1091  mf::LogVerbatim("PMAlgTracker") << "small clusters only";
1092  }
1093 
1094  fInitialClusters.clear();
1095 }
1096 // ------------------------------------------------------
1097 
1099  detinfo::DetectorPropertiesData const& detProp,
1100  int first_clu_idx,
1101  const std::vector<art::Ptr<recob::Hit>>& first_hits,
1102  size_t minSizeCompl,
1103  unsigned int tpc,
1104  unsigned int cryo,
1105  geo::View_t first_view)
1106 {
1108 
1109  for (auto av : fAvailableViews) {
1110  fTriedClusters[av].clear();
1111  }
1112 
1113  if (first_clu_idx >= 0) {
1114  fTriedClusters[first_view].push_back((size_t)first_clu_idx);
1115  fInitialClusters.push_back((size_t)first_clu_idx);
1116  }
1117 
1118  unsigned int nFirstHits = first_hits.size(), first_plane_idx = first_hits.front()->WireID().Plane;
1119  mf::LogVerbatim("PMAlgTracker") << std::endl << "--- start new candidate ---";
1120  mf::LogVerbatim("PMAlgTracker") << "use view *** " << first_view << " *** plane idx "
1121  << first_plane_idx << " *** size: " << nFirstHits;
1122 
1123  float xmax = detProp.ConvertTicksToX(first_hits.front()->PeakTime(), first_plane_idx, tpc, cryo);
1124  float xmin = xmax;
1125  for (size_t j = 1; j < first_hits.size(); ++j) {
1126  float x = detProp.ConvertTicksToX(first_hits[j]->PeakTime(), first_plane_idx, tpc, cryo);
1127  if (x > xmax) { xmax = x; }
1128  if (x < xmin) { xmin = x; }
1129  }
1130 
1131  pma::TrkCandidateColl candidates; // possible solutions of the selected cluster and clusters in
1132  // complementary views
1133 
1134  size_t imatch = 0;
1135  bool try_build = true;
1136  while (try_build) // loop over complementary views
1137  {
1138  pma::TrkCandidate candidate;
1139  if (first_clu_idx >= 0) candidate.Clusters().push_back((size_t)first_clu_idx);
1140 
1141  try_build = false;
1142  int idx = -1, av_idx = -1;
1143  unsigned int nMaxHits = 0, nHits = 0;
1144  unsigned int testView = geo::kUnknown, bestView = geo::kUnknown;
1145  for (auto av : fAvailableViews) {
1146  if (av == first_view) continue;
1147 
1148  av_idx =
1149  maxCluster(detProp, first_clu_idx, candidates, xmin, xmax, minSizeCompl, av, tpc, cryo);
1150  if (av_idx >= 0) {
1151  nHits = fCluHits[av_idx].size();
1152  if ((nHits > nMaxHits) && (nHits >= minSizeCompl)) {
1153  nMaxHits = nHits;
1154  idx = av_idx;
1155  bestView = av;
1156  fTriedClusters[av].push_back(idx);
1157  try_build = true;
1158  }
1159  }
1160  }
1161  for (auto av : fAvailableViews) {
1162  if ((av != first_view) && (av != bestView)) {
1163  testView = av;
1164  break;
1165  }
1166  }
1167 
1168  if (try_build) {
1169  mf::LogVerbatim("PMAlgTracker") << "--> " << imatch++ << " match with:";
1170  mf::LogVerbatim("PMAlgTracker")
1171  << " cluster in view *** " << bestView << " *** size: " << nMaxHits;
1172 
1173  if (!fGeom->TPC(geo::TPCID(cryo, tpc)).HasPlane(testView)) {
1174  mf::LogVerbatim("PMAlgTracker") << " no validation plane *** ";
1175  testView = geo::kUnknown;
1176  }
1177  else {
1178  mf::LogVerbatim("PMAlgTracker") << " validation plane *** " << testView << " ***";
1179  }
1180 
1181  double m0 = 0.0, v0 = 0.0;
1182  double mseThr = 0.15, validThr = 0.7; // cuts for a good track candidate
1183 
1184  candidate.Clusters().push_back(idx);
1185  candidate.SetTrack(fProjectionMatchingAlg.buildTrack(detProp, first_hits, fCluHits[idx]));
1186 
1187  if (candidate.IsValid() && // no track if hits from 2 views do not alternate
1188  fProjectionMatchingAlg.isContained(*(candidate.Track()), 2.0F)) // sticks out of TPC's?
1189  {
1190  m0 = candidate.Track()->GetMse();
1191  if (m0 < mseThr) // check validation only if MSE is OK - thanks for Tracy for noticing this
1192  {
1193  v0 = validate(detProp, *(candidate.Track()), testView);
1194  }
1195  }
1196 
1197  if (candidate.Track() && (m0 < mseThr) && (v0 > validThr)) // good candidate, try to extend it
1198  {
1199  mf::LogVerbatim("PMAlgTracker") << " good track candidate, MSE = " << m0 << ", v = " << v0;
1200 
1201  candidate.SetMse(m0);
1202  candidate.SetValidation(v0);
1203  candidate.SetGood(true);
1204 
1205  size_t minSize = 5; // min size for clusters matching
1206  double fraction = 0.5; // min fraction of close hits
1207 
1208  idx = 0;
1209  while (idx >= 0) // try to collect matching clusters, use **any** plane except validation
1210  {
1211  idx = matchCluster(detProp, candidate, minSize, fraction, geo::kUnknown, testView);
1212  if (idx >= 0) {
1213  // try building extended copy:
1214  // src, hits, valid.plane, add nodes
1215  if (extendTrack(detProp, candidate, fCluHits[idx], testView, true)) {
1216  candidate.Clusters().push_back(idx);
1217  }
1218  else
1219  idx = -1;
1220  }
1221  }
1222 
1223  mf::LogVerbatim("PMAlgTracker") << "merge clusters from the validation plane";
1224  fraction = 0.7; // only well matching the existing track
1225 
1226  idx = 0;
1227  bool extended = false;
1228  while ((idx >= 0) &&
1229  (testView != geo::kUnknown)) { // match clusters from the
1230  // plane used previously
1231  // for the validation
1232  idx = matchCluster(detProp, candidate, minSize, fraction, testView, geo::kUnknown);
1233  if (idx >= 0) {
1234  // validation not checked here, no new nodes:
1235  if (extendTrack(detProp, candidate, fCluHits[idx], geo::kUnknown, false)) {
1236  candidate.Clusters().push_back(idx);
1237  extended = true;
1238  }
1239  else
1240  idx = -1;
1241  }
1242  }
1243  // need to calculate again only if trk was extended w/o checking
1244  // validation:
1245  if (extended) candidate.SetValidation(validate(detProp, *(candidate.Track()), testView));
1246  }
1247  else {
1248  mf::LogVerbatim("PMAlgTracker") << "track REJECTED, MSE = " << m0 << "; v = " << v0;
1249  candidate.SetGood(false); // save also bad matches to avoid trying again
1250  // the same pair of clusters
1251  }
1252  candidates.push_back(candidate);
1253  }
1254  else {
1255  mf::LogVerbatim("PMAlgTracker") << "no matching clusters";
1256  }
1257  } // end loop over complementary views
1258 
1259  if (!candidates.empty()) // return best candidate, release other tracks and clusters
1260  {
1261  int best_trk = -1;
1262  double f, max_f = 0., min_mse = 10., max_v = 0.;
1263  for (size_t t = 0; t < candidates.size(); t++)
1264  if (candidates[t].IsGood() && (candidates[t].Track()->Nodes().size() > 1) &&
1265  candidates[t].Track()->HasTwoViews()) {
1266  f = fProjectionMatchingAlg.twoViewFraction(*(candidates[t].Track()));
1267 
1268  if ((f > max_f) || ((f == max_f) && ((candidates[t].Validation() > max_v) ||
1269  (candidates[t].Mse() < min_mse)))) {
1270  max_f = f;
1271  min_mse = candidates[t].Mse();
1272  max_v = candidates[t].Validation();
1273  best_trk = t;
1274  }
1275  }
1276 
1277  if ((best_trk > -1) && candidates[best_trk].IsGood() && (max_f > fMinTwoViewFraction)) {
1278  candidates[best_trk].Track()->ShiftEndsToHits();
1279 
1280  for (auto c : candidates[best_trk].Clusters())
1281  fUsedClusters.push_back(c);
1282 
1283  result = candidates[best_trk];
1284  }
1285 
1286  for (size_t t = 0; t < candidates.size(); t++) {
1287  if (int(t) != best_trk) candidates[t].DeleteTrack();
1288  }
1289  }
1290 
1291  return result;
1292 }
1293 // ------------------------------------------------------
1294 
1296  pma::TrkCandidate& candidate,
1298  unsigned int testView,
1299  bool add_nodes)
1300 {
1301  double m_max = 2.0 * candidate.Mse(); // max acceptable MSE value
1302  if (m_max < 0.05) m_max = 0.05; // this is still good, low MSE value
1303 
1304  double v_min1 = 0.98 * candidate.Validation();
1305  double v_min2 = 0.9 * candidate.Validation();
1306 
1307  pma::Track3D* copy =
1308  fProjectionMatchingAlg.extendTrack(detProp, *(candidate.Track()), hits, add_nodes);
1309  double m1 = copy->GetMse();
1310  double v1 = validate(detProp, *copy, testView);
1311 
1312  if (((m1 < candidate.Mse()) && (v1 >= v_min2)) ||
1313  ((m1 < 0.5) && (m1 <= m_max) && (v1 >= v_min1))) {
1314  mf::LogVerbatim("PMAlgTracker") << " track EXTENDED, MSE = " << m1 << ", v = " << v1;
1315  candidate.SetTrack(copy); // replace with the new track (deletes old one)
1316  copy->SortHits(); // sort hits in the new track
1317 
1318  candidate.SetMse(m1); // save info
1319  candidate.SetValidation(v1);
1320 
1321  return true;
1322  }
1323  else {
1324  mf::LogVerbatim("PMAlgTracker") << " track NOT extended, MSE = " << m1 << ", v = " << v1;
1325  delete copy;
1326  return false;
1327  }
1328 }
1329 // ------------------------------------------------------
1330 
1332  const pma::TrkCandidate& trk,
1333  size_t minSize,
1334  double fraction,
1335  unsigned int preferedView,
1336  unsigned int testView) const
1337 {
1338  double f, fmax = 0.0;
1339  unsigned int n, max = 0;
1340  int idx = -1;
1341  for (size_t i = 0; i < fCluHits.size(); ++i) {
1342  if (fCluHits[i].empty()) continue;
1343 
1344  unsigned int view = fCluHits[i].front()->View();
1345  unsigned int nhits = fCluHits[i].size();
1346 
1347  if (has(fUsedClusters, i) || // don't try already used clusters
1348  has(trk.Clusters(), i) || // don't try clusters from this candidate
1349  (view == testView) || // don't use clusters from validation view
1350  ((preferedView != geo::kUnknown) &&
1351  (view != preferedView)) || // only prefered view if specified
1352  (nhits < minSize)) // skip small clusters
1353  continue;
1354 
1355  n = fProjectionMatchingAlg.testHits(detProp, *(trk.Track()), fCluHits[i]);
1356  f = n / (double)nhits;
1357  if ((f > fraction) && (n > max)) {
1358  max = n;
1359  fmax = f;
1360  idx = i;
1361  }
1362  }
1363 
1364  if (idx >= 0)
1365  mf::LogVerbatim("PMAlgTracker") << "max matching hits: " << max << " (" << fmax << ")";
1366  else
1367  mf::LogVerbatim("PMAlgTracker") << "no clusters to extend the track";
1368 
1369  return idx;
1370 }
1371 // ------------------------------------------------------
1372 
1374  int first_idx_tag,
1375  const pma::TrkCandidateColl& candidates,
1376  float xmin,
1377  float xmax,
1378  size_t min_clu_size,
1379  geo::View_t view,
1380  unsigned int tpc,
1381  unsigned int cryo) const
1382 {
1383  int idx = -1;
1384  size_t s_max = 0, s;
1385  double fraction = 0.0;
1386  float x;
1387 
1388  size_t first_idx = 0;
1389  bool has_first = false;
1390  if (first_idx_tag >= 0) {
1391  first_idx = (size_t)first_idx_tag;
1392  has_first = true;
1393  }
1394 
1395  for (size_t i = 0; i < fCluHits.size(); ++i) {
1396  if ((fCluHits[i].size() < min_clu_size) || (fCluHits[i].front()->View() != view) ||
1397  has(fUsedClusters, i) || has(fInitialClusters, i) || has(fTriedClusters[view], i))
1398  continue;
1399 
1400  bool pair_checked = false;
1401  for (auto const& c : candidates.tracks())
1402  if (has_first && has(c.Clusters(), first_idx) && has(c.Clusters(), i)) {
1403  pair_checked = true;
1404  break;
1405  }
1406  if (pair_checked) continue;
1407 
1408  const auto& v = fCluHits[i];
1409 
1410  if ((v.front()->WireID().TPC == tpc) && (v.front()->WireID().Cryostat == cryo)) {
1411  s = 0;
1412  for (size_t j = 0; j < v.size(); ++j) {
1413  x = detProp.ConvertTicksToX(v[j]->PeakTime(), v[j]->WireID().Plane, tpc, cryo);
1414  if ((x >= xmin) && (x <= xmax)) s++;
1415  }
1416 
1417  if (s > s_max) {
1418  s_max = s;
1419  idx = i;
1420  fraction = s / (double)v.size();
1421  }
1422  }
1423  }
1424  if (fraction > 0.4) return idx;
1425 
1426  return -1;
1427 }
1428 // ------------------------------------------------------
1429 
1430 int pma::PMAlgTracker::maxCluster(size_t min_clu_size,
1431  geo::View_t view,
1432  unsigned int tpc,
1433  unsigned int cryo) const
1434 {
1435  int idx = -1;
1436  size_t s_max = 0;
1437 
1438  for (size_t i = 0; i < fCluHits.size(); ++i) {
1439  const auto& v = fCluHits[i];
1440 
1441  if (v.empty() || (fCluWeights[i] < fTrackLikeThreshold) || has(fUsedClusters, i) ||
1442  has(fInitialClusters, i) || has(fTriedClusters[view], i) ||
1443  ((view != geo::kUnknown) && (v.front()->View() != view)))
1444  continue;
1445 
1446  if ((v.front()->WireID().TPC == tpc) && (v.front()->WireID().Cryostat == cryo)) {
1447  size_t s = v.size();
1448  if ((s >= min_clu_size) && (s > s_max)) {
1449  s_max = s;
1450  idx = i;
1451  }
1452  }
1453  }
1454  return idx;
1455 }
1456 // ------------------------------------------------------
1457 // ------------------------------------------------------
1458 
1460 {
1461  mf::LogVerbatim("PMAlgTracker") << std::endl << "----------- matched clusters: -----------";
1462  for (size_t i = 0; i < fCluHits.size(); ++i) {
1463  if (!fCluHits[i].empty() && has(fUsedClusters, i)) {
1464  mf::LogVerbatim("PMAlgTracker")
1465  << " tpc: " << fCluHits[i].front()->WireID().TPC
1466  << ";\tview: " << fCluHits[i].front()->View() << ";\tsize: " << fCluHits[i].size()
1467  << ";\tweight: " << fCluWeights[i];
1468  }
1469  }
1470 
1471  mf::LogVerbatim("PMAlgTracker") << "--------- not matched clusters: ---------";
1472  size_t nsingles = 0;
1473  for (size_t i = 0; i < fCluHits.size(); ++i) {
1474  if (!fCluHits[i].empty() && !has(fUsedClusters, i)) {
1475  if (fCluHits[i].size() == 1) { nsingles++; }
1476  else {
1477  mf::LogVerbatim("PMAlgTracker")
1478  << " tpc: " << fCluHits[i].front()->WireID().TPC
1479  << ";\tview: " << fCluHits[i].front()->View() << ";\tsize: " << fCluHits[i].size()
1480  << ";\tweight: " << fCluWeights[i]
1481  << ";\tmatch: " << matchTrack(detProp, fResult, fCluHits[i]);
1482  }
1483  }
1484  }
1485  mf::LogVerbatim("PMAlgTracker") << " single hits: " << nsingles;
1486  mf::LogVerbatim("PMAlgTracker") << "-----------------------------------------";
1487 }
1488 // ------------------------------------------------------
1489 // ------------------------------------------------------
Float_t x
Definition: compare.C:6
TRandom r
Definition: spectrum.C:23
bool SelectHits(float fraction=1.0F)
details::range_type< T > Iterate() const
Initializes the specified ID with the ID of the first cryostat.
Definition: GeometryCore.h:541
pma::Track3D * buildTrack(const detinfo::DetectorPropertiesData &detProp, const std::vector< art::Ptr< recob::Hit >> &hits_1, const std::vector< art::Ptr< recob::Hit >> &hits_2={}) const
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
bool HasPlane(unsigned int iplane) const
Returns whether a plane with index iplane is present in this TPC.
Definition: TPCGeo.h:147
pma::TrkCandidate matchCluster(detinfo::DetectorPropertiesData const &detProp, int first_clu_idx, const std::vector< art::Ptr< recob::Hit >> &first_hits, size_t minSizeCompl, unsigned int tpc, unsigned int cryo, geo::View_t first_view)
std::map< int, pma::Vector3D > fPfpVtx
void guideEndpoints(detinfo::DetectorPropertiesData const &detProp, pma::TrkCandidateColl &tracks)
size_t size() const
bool IsValid() const
bool areCoLinear(pma::Track3D *trk1, pma::Track3D *trk2, double &dist, double &cos3d, bool &reverseOrder, double distThr, double distThrMin, double distProjThr, double cosThr) const
double GetMse(unsigned int view=geo::kUnknown) const
MSE of hits weighted with hit amplidudes and wire plane coefficients.
size_t run(const detinfo::DetectorPropertiesData &detProp, pma::TrkCandidateColl &trk_input)
static constexpr Mask_t makeMask(Flags...flags)
Returns a bit mask with only the specified bit set.
void SetKey(int key)
Set key of an external object associated to this track candidate.
recob::Track convertFrom(const pma::Track3D &src, unsigned int tidx, int pdg=0)
geo::GeometryCore const * fGeom
size_t matchTrack(detinfo::DetectorPropertiesData const &detProp, const pma::TrkCandidateColl &tracks, const std::vector< art::Ptr< recob::Hit >> &hits) const
double Dist2(const TVector2 &v1, const TVector2 &v2)
Definition: Utilities.cxx:39
void buildTracks(detinfo::DetectorPropertiesData const &detProp)
pma::Track3D * extendTrack(const detinfo::DetectorPropertiesData &clockData, const pma::Track3D &trk, const std::vector< art::Ptr< recob::Hit >> &hits, bool add_nodes) const
Add more hits to an existing track, reoptimize, optionally add more nodes.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
void ApplyDriftShiftInTree(const detinfo::DetectorClocksData &clockData, detinfo::DetectorPropertiesData const &detProp, double dx, bool skipFirst=false)
size_t fMinSeedSize2ndPass
Unknown view.
Definition: geo_types.h:142
double validate(detinfo::DetectorPropertiesData const &detProp, pma::Track3D &trk, unsigned int testView)
bool IsGood() const
pma::Hit3D const * front() const
Definition: PmaTrack3D.h:87
bool reassignHits_1(detinfo::DetectorPropertiesData const &detProp, const std::vector< art::Ptr< recob::Hit >> &hits, pma::TrkCandidateColl &tracks, size_t trk_idx, double dist2)
void erase_at(size_t pos)
Implementation of the Projection Matching Algorithm.
Geometry information for a single TPC.
Definition: TPCGeo.h:36
double fMinTwoViewFraction
bool reassignSingleViewEnds_1(detinfo::DetectorPropertiesData const &detProp, pma::TrkCandidateColl &tracks)
::fhicl::TupleAs< Point(::geo::Length_t,::geo::Length_t,::geo::Length_t)> Point3D
Atom object for reading a 3D point or vector (centimeters).
std::map< size_t, pma::TrkCandidateColl > tpc_track_map
Definition: PMAlgTracking.h:54
fhicl::Atom< std::string > Validation
void SetGood(bool b)
TVector3 const & Point3D() const
Definition: PmaHit3D.h:50
std::vector< size_t > fInitialClusters
ROOT::Math::SMatrix< Double32_t, 5, 5, ROOT::Math::MatRepSym< Double32_t, 5 >> SMatrixSym55
PMAlgTracker(const std::vector< art::Ptr< recob::Hit >> &allhitlist, const std::vector< recob::Wire > &wires, const pma::ProjectionMatchingAlg::Config &pmalgConfig, const pma::PMAlgTracker::Config &pmalgTrackerConfig, const pma::PMAlgVertexing::Config &pmvtxConfig, const pma::PMAlgStitching::Config &pmstitchConfig, const pma::PMAlgCosmicTagger::Config &pmtaggerConfig, const std::vector< TH1F * > &hpassing, const std::vector< TH1F * > &hrejected)
Float_t tmp
Definition: plot.C:35
pma::PMAlgCosmicTagger fCosmicTagger
void SetValidation(double v)
void SetTrack(pma::Track3D *trk)
std::map< int, std::vector< art::Ptr< recob::Cluster > > > fPfpClusters
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
double Validation() const
double fStitchTransverseShift
std::map< unsigned int, std::vector< size_t > > fTriedClusters
int maxCluster(detinfo::DetectorPropertiesData const &detProp, int first_idx_tag, const pma::TrkCandidateColl &candidates, float xmin, float xmax, size_t min_clu_size, geo::View_t view, unsigned int tpc, unsigned int cryo) const
recob::tracking::Vector_t Vector3D
Definition: Utilities.h:34
pma::Vector3D GetDirection3D(size_t index) const
Get trajectory direction at given hit index.
Definition: PmaTrack3D.cxx:380
void flipTreesToCoordinate(detinfo::DetectorPropertiesData const &detProp, size_t coordinate)
recob::tracking::Point_t Point_t
TPCGeo const & TPC(TPCID const &tpcid=tpc_zero) const
Returns the specified TPC.
Definition: GeometryCore.h:722
TFile f
Definition: plotHisto.C:6
std::vector< double > fAdcValidationThr
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
std::vector< int > fTrackingOnlyPdg
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
int build(detinfo::DetectorPropertiesData const &detProp)
pma::PMAlgStitching fStitcher
double GetDistToWall() const
Definition: PmaNode3D.cxx:81
fhicl::Sequence< double > AdcValidationThr
double collectSingleViewEnd(pma::Track3D &trk, std::vector< art::Ptr< recob::Hit >> &hits) const
void hits()
Definition: readHits.C:15
unsigned int MaxPlanes() const
Returns the largest number of planes among all TPCs in this detector.
pma::Node3D * FirstElement() const
Definition: PmaTrack3D.h:275
unsigned int testHits(detinfo::DetectorPropertiesData const &detProp, const pma::Track3D &trk, const std::vector< art::Ptr< recob::Hit >> &hits, double eps=1.0) const
Count the number of hits that are closer than eps * fHitTestingDist2D to the track 2D projection...
std::map< int, int > fPfpPdgCodes
pma::Node3D * LastElement() const
Definition: PmaTrack3D.h:276
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
bool isContained(const pma::Track3D &trk, float margin=0.0F) const
TVector2 GetProjectionToSegment(const TVector2 &p, const TVector2 &p0, const TVector2 &p1)
Definition: Utilities.cxx:144
A trajectory in space reconstructed from hits.
std::vector< int > fTrackingSkipPdg
std::vector< pma::Segment3D * > const & Segments() const noexcept
Definition: PmaTrack3D.h:269
double validate_on_adc_test(const detinfo::DetectorPropertiesData &detProp, const lariov::ChannelStatusProvider &channelStatus, const pma::Track3D &trk, const img::DataProviderAlg &adcImage, const std::vector< art::Ptr< recob::Hit >> &hits, TH1F *histoPassing, TH1F *histoRejected) const
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space. See recob::tracking::Coord_t for more details on the ...
Definition: TrackingTypes.h:31
const std::vector< recob::Wire > & fWires
bool has(const std::vector< size_t > &v, size_t idx) const
Float_t d
Definition: plot.C:235
pma::ProjectionMatchingAlg fProjectionMatchingAlg
Definition: PMAlgTracking.h:90
double fMergeTransverseShift
PMAlgTrackingBase(const std::vector< art::Ptr< recob::Hit >> &allhitlist, const pma::ProjectionMatchingAlg::Config &pmalgConfig, const pma::PMAlgVertexing::Config &pmvtxConfig)
bool mergeCoLinear(detinfo::DetectorPropertiesData const &detProp, pma::TrkCandidateColl &tracks) const
void SetMse(double m)
void RemoveHits(const std::vector< art::Ptr< recob::Hit >> &hits)
Remove hits; removes also hit->node/seg assignments.
Definition: PmaTrack3D.cxx:412
void fromMaxCluster_tpc(detinfo::DetectorPropertiesData const &detProp, pma::TrkCandidateColl &result, size_t minBuildSize, unsigned int tpc, unsigned int cryo)
unsigned int FrontTPC() const
Definition: PmaTrack3D.h:118
unsigned int FrontCryo() const
Definition: PmaTrack3D.h:119
The data type to uniquely identify a TPC.
Definition: geo_types.h:381
unsigned int DisableSingleViewEnds()
std::vector< size_t > fUsedClusters
const pma::TrkCandidateColl & result()
Definition: PMAlgTracking.h:66
PMAlgFitter(const std::vector< art::Ptr< recob::Hit >> &allhitlist, const std::vector< recob::Cluster > &clusters, const std::vector< recob::PFParticle > &pfparticles, const art::FindManyP< recob::Hit > &hitsFromClusters, const art::FindManyP< recob::Cluster > &clusFromPfps, const art::FindManyP< recob::Vertex > &vtxFromPfps, const pma::ProjectionMatchingAlg::Config &pmalgConfig, const pma::PMAlgFitter::Config &pmalgFitterConfig, const pma::PMAlgVertexing::Config &pmvtxConfig)
void tag(detinfo::DetectorClocksData const &clockData, pma::TrkCandidateColl &tracks)
bool has(const std::vector< int > &v, int i) const
std::vector< std::vector< art::Ptr< recob::Hit > > > fCluHits
std::vector< std::vector< art::Ptr< recob::Hit > > > fCluHits
double ConvertTicksToX(double ticks, int p, int t, int c) const
std::vector< float > fCluWeights
fhicl::Table< img::DataProviderAlg::Config > AdcImageAlg
bool HasTwoViews(size_t nmin=1) const
Definition: PmaTrack3D.cxx:439
recob::tracking::SMatrixSym55 SMatrixSym55
void CleanupTails()
Cut out tails with no hits assigned.
Implementation of the Projection Matching Algorithm.
double Length(size_t step=1) const
Definition: PmaTrack3D.h:94
double validate(const detinfo::DetectorPropertiesData &detProp, const lariov::ChannelStatusProvider &channelStatus, const pma::Track3D &trk, const std::vector< art::Ptr< recob::Hit >> &hits) const
void freezeBranchingNodes(pma::TrkCandidateColl &tracks) const
Contains all timing reference information for the detector.
const std::vector< TH1F * > & fAdcInPassingPoints
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
void init(const art::FindManyP< recob::Hit > &hitsFromClusters)
pma::Track3D * buildShowerSeg(const detinfo::DetectorPropertiesData &detProp, const std::vector< art::Ptr< recob::Hit >> &hits, const pma::Vector3D &vtx) const
short int DetectDriftDirection() const
Returns the expected drift direction based on geometry.
Definition: TPCGeo.cxx:149
void mergeTracks(const detinfo::DetectorPropertiesData &detProp, pma::Track3D &dst, pma::Track3D &src, bool reopt) const
double collectSingleViewFront(pma::Track3D &trk, std::vector< art::Ptr< recob::Hit >> &hits) const
void StitchTracksAPA(const detinfo::DetectorClocksData &clockData, const detinfo::DetectorPropertiesData &detProp, pma::TrkCandidateColl &tracks)
const std::vector< size_t > & Clusters() const
const std::vector< TH1F * > & fAdcInRejectedPoints
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
void guideEndpoints(const detinfo::DetectorPropertiesData &clockData, pma::Track3D &trk, const std::map< unsigned int, std::vector< art::Ptr< recob::Hit >>> &hits) const
pma::Hit3D const * back() const
Definition: PmaTrack3D.h:88
double validate_on_adc(const detinfo::DetectorPropertiesData &detProp, const lariov::ChannelStatusProvider &channelStatus, const pma::Track3D &trk, const img::DataProviderAlg &adcImage, float thr) const
void listUsedClusters(detinfo::DetectorPropertiesData const &detProp) const
int build(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp)
std::set< View_t > const & Views() const
Returns a list of possible views in the detector.
Definition: MVAAlg.h:12
std::vector< geo::View_t > fAvailableViews
void releaseAllNodes(pma::TrkCandidateColl &tracks) const
Char_t n[5]
TrackCollectionProxyElement< TrackCollProxy > Track
Proxy to an element of a proxy collection of recob::Track objects.
Definition: Track.h:992
std::vector< pma::Node3D * > const & Nodes() const noexcept
Definition: PmaTrack3D.h:274
size_t fMinSeedSize1stPass
pma::TrkCandidateColl fResult
Definition: PMAlgTracking.h:93
bool extendTrack(detinfo::DetectorPropertiesData const &detProp, pma::TrkCandidate &candidate, const std::vector< art::Ptr< recob::Hit >> &hits, unsigned int testView, bool add_nodes)
bool Flip(const detinfo::DetectorPropertiesData &detProp, std::vector< pma::Track3D * > &allTracks)
Definition: PmaTrack3D.cxx:527
void StitchTracksCPA(const detinfo::DetectorClocksData &clockData, const detinfo::DetectorPropertiesData &detProp, pma::TrkCandidateColl &tracks)
EValidationMode fValidation
size_t size() const
Definition: PmaTrack3D.h:89
recob::tracking::Plane Plane
Definition: TrackState.h:17
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space. See recob::tracking::Coord_t for more detai...
Definition: TrackingTypes.h:27
pma::Track3D * Track() const
Namespace collecting geometry-related classes utilities.
double twoViewFraction(pma::Track3D &trk) const
bool ShiftEndsToHits()
recob::tracking::Vector_t Vector_t
void push_back(const TrkCandidate &trk)
pma::PMAlgVertexing fPMAlgVertexing
Definition: PMAlgTracking.h:91
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
Definition: Track.h:49
std::vector< TrkCandidate > const & tracks() const
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109
double Mse() const
pma::Track3D * buildMultiTPCTrack(const detinfo::DetectorPropertiesData &clockData, const std::vector< art::Ptr< recob::Hit >> &hits) const
pma::cryo_tpc_view_hitmap fHitMap
Definition: PMAlgTracking.h:88
std::vector< img::DataProviderAlg > fAdcImages
void buildShowers(detinfo::DetectorPropertiesData const &detProp)