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