LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
PmaTrack3D.cxx
Go to the documentation of this file.
1 
15 
20 
23 
24 #include <array>
25 
26 #include "range/v3/algorithm.hpp"
27 #include "range/v3/view.hpp"
28 
29 pma::Track3D::Track3D() = default;
30 
32  : fMaxHitsPerSeg(src.fMaxHitsPerSeg)
33  , fPenaltyFactor(src.fPenaltyFactor)
34  , fMaxSegStopFactor(src.fMaxSegStopFactor)
35  , fSegStopValue(src.fSegStopValue)
36  , fMinSegStop(src.fMinSegStop)
37  , fMaxSegStop(src.fMaxSegStop)
38  , fSegStopFactor(src.fSegStopFactor)
39  , fPenaltyValue(src.fPenaltyValue)
40  , fEndSegWeight(src.fEndSegWeight)
41  , fHitsRadius(src.fHitsRadius)
42  , fT0(src.fT0)
43  , fT0Flag(src.fT0Flag)
44  , fTag(src.fTag)
45 {
46  fHits.reserve(src.fHits.size());
47  for (auto const* hit : src.fHits) {
48  pma::Hit3D* h3d = new pma::Hit3D(*hit);
49  h3d->fParent = this;
50  fHits.push_back(h3d);
51  }
52 
53  fNodes.reserve(src.fNodes.size());
54  for (auto const* node : src.fNodes)
55  fNodes.push_back(new pma::Node3D(*node));
56 
57  for (auto const* point : src.fAssignedPoints)
58  fAssignedPoints.push_back(new TVector3(*point));
59 
62 }
63 
65 {
66  for (size_t i = 0; i < fHits.size(); i++)
67  delete fHits[i];
68  for (size_t i = 0; i < fAssignedPoints.size(); i++)
69  delete fAssignedPoints[i];
70 
71  for (size_t i = 0; i < fSegments.size(); i++)
72  delete fSegments[i];
73  for (size_t i = 0; i < fNodes.size(); i++)
74  if (!fNodes[i]->NextCount() && !fNodes[i]->Prev()) delete fNodes[i];
75 }
76 
77 bool pma::Track3D::Initialize(detinfo::DetectorPropertiesData const& detProp, float initEndSegW)
78 {
79  if (!HasTwoViews(2)) {
80  mf::LogError("pma::Track3D") << "Need min. 2 hits per view, at least two views.";
81  return false;
82  }
83 
84  auto cryos = Cryos();
85  if (cryos.size() > 1) {
86  mf::LogError("pma::Track3D") << "Only one cryostat for now, please.";
87  return false;
88  }
89  int cryo = cryos.front();
90 
91  auto tpcs = TPCs();
92  if (tpcs.size() > 1) {
93  mf::LogError("pma::Track3D") << "Only one TPC, please.";
94  return false;
95  }
96  // single tpc, many tpc's are ok, but need to be handled from ProjectionMatchingAlg::buildMultiTPCTrack()
97  int tpc = tpcs.front();
98 
99  if (InitFromRefPoints(detProp, tpc, cryo))
100  mf::LogVerbatim("pma::Track3D") << "Track initialized with 3D reference points.";
101  else if (InitFromHits(detProp, tpc, cryo, initEndSegW))
102  mf::LogVerbatim("pma::Track3D") << "Track initialized with hit positions.";
103  else {
104  InitFromMiddle(detProp, tpc, cryo);
105  mf::LogVerbatim("pma::Track3D") << "Track initialized in the module center.";
106  }
107 
109  return true;
110 }
111 
113 {
114  for (size_t i = 0; i < fNodes.size(); i++)
115  delete fNodes[i];
116  fNodes.clear();
117 }
118 
120  int tpc,
121  int cryo,
122  float initEndSegW)
123 {
125  geo::TPCID const tpcid(cryo, tpc);
126 
127  float wtmp = fEndSegWeight;
128  fEndSegWeight = initEndSegW;
129 
130  // endpoints for the first combination:
131  TVector3 v3d_1(0., 0., 0.), v3d_2(0., 0., 0.);
132 
133  assert(!fHits.empty());
134 
135  pma::Hit3D* hit0_a = fHits.front();
136  pma::Hit3D* hit1_a = fHits.front();
137 
138  geo::PlaneID const hit0_a_planeid{tpcid, hit0_a->View2D()};
139  geo::PlaneID const hit1_a_planeid{tpcid, hit1_a->View2D()};
140 
141  float minX = detProp.ConvertTicksToX(hit0_a->PeakTime(), hit0_a_planeid);
142  float maxX = detProp.ConvertTicksToX(hit1_a->PeakTime(), hit1_a_planeid);
143  for (auto hit : fHits) {
144  double const x = detProp.ConvertTicksToX(hit->PeakTime(), geo::PlaneID{tpcid, hit->View2D()});
145  if (x < minX) {
146  minX = x;
147  hit0_a = hit;
148  }
149  if (x > maxX) {
150  maxX = x;
151  hit1_a = hit;
152  }
153  }
154 
155  pma::Hit3D* hit0_b = nullptr;
156  pma::Hit3D* hit1_b = nullptr;
157 
158  float minDiff0 = 5000, minDiff1 = 5000;
159  for (auto hit : fHits) {
160  double const x = detProp.ConvertTicksToX(hit->PeakTime(), geo::PlaneID{tpcid, hit->View2D()});
161  double diff = fabs(x - minX);
162  if ((diff < minDiff0) && (hit->View2D() != hit0_a->View2D())) {
163  minDiff0 = diff;
164  hit0_b = hit;
165  }
166  diff = fabs(x - maxX);
167  if ((diff < minDiff1) && (hit->View2D() != hit1_a->View2D())) {
168  minDiff1 = diff;
169  hit1_b = hit;
170  }
171  }
172 
173  if (hit0_a && hit0_b && hit1_a && hit1_b) {
174  geo::PlaneID const hit0_b_planeid{tpcid, hit0_b->View2D()};
175  geo::PlaneID const hit1_b_planeid{tpcid, hit1_b->View2D()};
176  double x = 0.5 * (detProp.ConvertTicksToX(hit0_a->PeakTime(), hit0_a_planeid) +
177  detProp.ConvertTicksToX(hit0_b->PeakTime(), hit0_b_planeid));
178  double y, z;
179  geom->IntersectionPoint(geo::WireID{hit0_a_planeid, hit0_a->Wire()},
180  geo::WireID{hit0_b_planeid, hit0_b->Wire()},
181  y,
182  z);
183  v3d_1.SetXYZ(x, y, z);
184 
185  x = 0.5 * (detProp.ConvertTicksToX(hit1_a->PeakTime(), hit1_a_planeid) +
186  detProp.ConvertTicksToX(hit1_b->PeakTime(), hit1_b_planeid));
187  geom->IntersectionPoint(geo::WireID{hit1_a_planeid, hit1_a->Wire()},
188  geo::WireID{hit1_b_planeid, hit1_b->Wire()},
189  y,
190  z);
191  v3d_2.SetXYZ(x, y, z);
192 
193  ClearNodes();
194  AddNode(detProp, v3d_1, tpc, cryo);
195  AddNode(detProp, v3d_2, tpc, cryo);
196 
197  MakeProjection();
199  Optimize(detProp, 0, 0.01F, false, true, 100);
200  SelectAllHits();
201  }
202  else {
203  mf::LogVerbatim("pma::Track3D") << "Good hits not found.";
204  fEndSegWeight = wtmp;
205  return false;
206  }
207 
208  if (pma::Dist2(fNodes.front()->Point3D(), fNodes.back()->Point3D()) < (0.3 * 0.3)) {
209  mf::LogVerbatim("pma::Track3D") << "Short initial segment.";
210  fEndSegWeight = wtmp;
211  return false;
212  }
213 
214  fEndSegWeight = wtmp;
215  return true;
216 }
217 
219  int tpc,
220  int cryo)
221 {
222  if (fAssignedPoints.size() < 2) return false;
223 
224  ClearNodes();
225 
226  TVector3 mean(0., 0., 0.), stdev(0., 0., 0.), p(0., 0., 0.);
227  for (size_t i = 0; i < fAssignedPoints.size(); i++) {
228  p = *(fAssignedPoints[i]);
229  mean += p;
230  p.SetXYZ(p.X() * p.X(), p.Y() * p.Y(), p.Z() * p.Z());
231  stdev += p;
232  }
233  stdev *= 1.0 / fAssignedPoints.size();
234  mean *= 1.0 / fAssignedPoints.size();
235  p = mean;
236  p.SetXYZ(p.X() * p.X(), p.Y() * p.Y(), p.Z() * p.Z());
237  stdev -= p;
238 
239  double sx = stdev.X(), sy = stdev.Y(), sz = stdev.Z();
240  if (sx >= 0.0)
241  sx = sqrt(sx);
242  else
243  sx = 0.0;
244  if (sy >= 0.0)
245  sy = sqrt(sy);
246  else
247  sy = 0.0;
248  if (sz >= 0.0)
249  sz = sqrt(sz);
250  else
251  sz = 0.0;
252  stdev.SetXYZ(sx, sy, sz);
253 
254  double scale = 2.0 * stdev.Mag();
255  double iscale = 1.0 / scale;
256 
257  size_t max_index = 0;
258  double norm2, max_norm2 = 0.0;
259  std::vector<TVector3> data;
260  for (size_t i = 0; i < fAssignedPoints.size(); i++) {
261  p = *(fAssignedPoints[i]);
262  p -= mean;
263  p *= iscale;
264  norm2 = p.Mag2();
265  if (norm2 > max_norm2) {
266  max_norm2 = norm2;
267  max_index = i;
268  }
269  data.push_back(p);
270  }
271 
272  double y = 0.0, kappa = 1.0, prev_kappa, kchg = 1.0;
273  TVector3 w(data[max_index]);
274 
275  while (kchg > 0.0001)
276  for (size_t i = 0; i < data.size(); i++) {
277  y = (data[i] * w);
278  w += (y / kappa) * (data[i] - y * w);
279 
280  prev_kappa = kappa;
281  kappa += y * y;
282  kchg = fabs((kappa - prev_kappa) / prev_kappa);
283  }
284  w *= 1.0 / w.Mag();
285 
286  TVector3 v1(w), v2(w);
287  v1 *= scale;
288  v1 += mean;
289  v2 *= -scale;
290  v2 += mean;
291  std::sort(fAssignedPoints.begin(), fAssignedPoints.end(), pma::bSegmentProjLess(v1, v2));
292  for (size_t i = 0; i < fAssignedPoints.size(); i++) {
293  AddNode(detProp, *(fAssignedPoints[i]), tpc, cryo);
294  }
295 
296  RebuildSegments();
297  MakeProjection();
298 
299  if (size()) UpdateHitsRadius();
300 
301  Optimize(detProp, 0, 0.01F, false, true, 100);
302  SelectAllHits();
303 
304  return true;
305 }
306 
307 void pma::Track3D::InitFromMiddle(detinfo::DetectorPropertiesData const& detProp, int tpc, int cryo)
308 {
310 
311  const auto& tpcGeo = geom->TPC(geo::TPCID(cryo, tpc));
312 
313  double minX = tpcGeo.MinX(), maxX = tpcGeo.MaxX();
314  double minY = tpcGeo.MinY(), maxY = tpcGeo.MaxY();
315  double minZ = tpcGeo.MinZ(), maxZ = tpcGeo.MaxZ();
316 
317  TVector3 v3d_1(0.5 * (minX + maxX), 0.5 * (minY + maxY), 0.5 * (minZ + maxZ));
318  TVector3 v3d_2(v3d_1);
319 
320  TVector3 shift(5.0, 5.0, 5.0);
321  v3d_1 += shift;
322  v3d_2 -= shift;
323 
324  ClearNodes();
325  AddNode(detProp, v3d_1, tpc, cryo);
326  AddNode(detProp, v3d_2, tpc, cryo);
327 
328  MakeProjection();
330 
331  Optimize(detProp, 0, 0.01F);
332 }
333 
335 {
336  for (size_t i = 0; i < fNodes.size(); ++i)
337  if (fNodes[i] == n) return (int)i;
338  return -1;
339 }
340 
342 {
343  for (size_t i = 0; i < size(); i++)
344  if (fHits[i] == hit) return (int)i;
345  return -1;
346 }
347 
349 {
350  pma::Hit3D* h3d = fHits[index];
351  fHits.erase(fHits.begin() + index);
352  return h3d;
353 }
354 
356  const art::Ptr<recob::Hit>& hit)
357 {
358  for (auto const& trk_hit : fHits) {
359  if (trk_hit->fHit == hit) return false;
360  }
361  pma::Hit3D* h3d = new pma::Hit3D(detProp, hit);
362  h3d->fParent = this;
363  fHits.push_back(h3d);
364  return true;
365 }
366 
368 {
369  for (size_t i = 0; i < size(); i++) {
370  if (hit == fHits[i]->fHit) {
371  pma::Hit3D* h3d = fHits[i];
372  fHits.erase(fHits.begin() + i);
373  delete h3d;
374  return true;
375  }
376  }
377  return false;
378 }
379 
381 {
382  pma::Hit3D* h = fHits[index];
383 
384  for (auto s : fSegments) {
385  if (s->HasHit(h)) return s->GetDirection3D();
386  }
387  for (auto n : fNodes) {
388  if (n->HasHit(h)) return n->GetDirection3D();
389  }
390 
391  auto pe = GetNearestElement(h->Point2D(), h->View2D(), h->TPC());
392  if (pe) {
393  mf::LogWarning("pma::Track3D")
394  << "GetDirection3D(): had to update hit assignment to segment/node.";
395  pe->AddHit(h);
396  return pe->GetDirection3D();
397  }
398  else {
399  throw cet::exception("pma::Track3D") << "GetDirection3D(): direction of a not assigned hit "
400  << index << " (size: " << fHits.size() << ")" << std::endl;
401  }
402 }
403 
406 {
407  fHits.reserve(fHits.size() + hits.size());
408  for (auto const& hit : hits)
409  push_back(detProp, hit);
410 }
411 
413 {
414  unsigned int n = 0;
415  for (auto const& hit : hits) {
416  if (erase(hit)) n++;
417  }
418  if (n) MakeProjection();
419 }
420 
421 unsigned int pma::Track3D::NHits(unsigned int view) const
422 {
423  unsigned int n = 0;
424  for (auto hit : fHits) {
425  if (hit->View2D() == view) n++;
426  }
427  return n;
428 }
429 
430 unsigned int pma::Track3D::NEnabledHits(unsigned int view) const
431 {
432  unsigned int n = 0;
433  for (auto hit : fHits) {
434  if (hit->IsEnabled() && ((view == geo::kUnknown) || (view == hit->View2D()))) n++;
435  }
436  return n;
437 }
438 
439 bool pma::Track3D::HasTwoViews(size_t const nmin) const
440 {
441  unsigned int nviews = 0;
442  if (NHits(geo::kU) >= nmin) nviews++;
443  if (NHits(geo::kV) >= nmin) nviews++;
444  if (NHits(geo::kZ) >= nmin) nviews++;
445  return nviews > 1;
446 }
447 
448 std::vector<unsigned int> pma::Track3D::TPCs() const
449 {
450  std::vector<unsigned int> tpc_idxs;
451  for (auto hit : fHits) {
452  unsigned int tpc = hit->TPC();
453 
454  bool found = false;
455  for (unsigned int const tpc_idx : tpc_idxs)
456  if (tpc_idx == tpc) {
457  found = true;
458  break;
459  }
460 
461  if (!found) tpc_idxs.push_back(tpc);
462  }
463  return tpc_idxs;
464 }
465 
466 std::vector<unsigned int> pma::Track3D::Cryos() const
467 {
468  std::vector<unsigned int> cryo_idxs;
469  for (auto hit : fHits) {
470  unsigned int cryo = hit->Cryo();
471 
472  bool found = false;
473  for (size_t j = 0; j < cryo_idxs.size(); j++)
474  if (cryo_idxs[j] == cryo) {
475  found = true;
476  break;
477  }
478 
479  if (!found) cryo_idxs.push_back(cryo);
480  }
481  return cryo_idxs;
482 }
483 
484 std::pair<TVector2, TVector2> pma::Track3D::WireDriftRange(
485  detinfo::DetectorPropertiesData const& detProp,
486  unsigned int view,
487  unsigned int tpc,
488  unsigned int cryo) const
489 {
490  std::pair<TVector2, TVector2> range(TVector2(0., 0.), TVector2(0., 0.));
491 
492  size_t n0 = 0;
493  while ((n0 < fNodes.size()) && (fNodes[n0]->TPC() != (int)tpc))
494  n0++;
495 
496  if (n0 < fNodes.size()) {
497  size_t n1 = n0;
498  while ((n1 < fNodes.size()) && (fNodes[n1]->TPC() == (int)tpc))
499  n1++;
500 
501  if (n0 > 0) n0--;
502  if (n1 == fNodes.size()) n1--;
503 
504  TVector2 p0 = fNodes[n0]->Projection2D(view);
505  p0 = pma::CmToWireDrift(detProp, p0.X(), p0.Y(), view, tpc, cryo);
506 
507  TVector2 p1 = fNodes[n1]->Projection2D(view);
508  p1 = pma::CmToWireDrift(detProp, p1.X(), p1.Y(), view, tpc, cryo);
509 
510  if (p0.X() > p1.X()) {
511  double tmp = p0.X();
512  p0.Set(p1.X(), p0.Y());
513  p1.Set(tmp, p1.Y());
514  }
515  if (p0.Y() > p1.Y()) {
516  double tmp = p0.Y();
517  p0.Set(p0.X(), p1.Y());
518  p1.Set(p1.X(), tmp);
519  }
520 
521  range.first = p0;
522  range.second = p1;
523  }
524  return range;
525 }
526 
528  std::vector<pma::Track3D*>& allTracks)
529 {
530  if (fNodes.size() < 2) { return true; }
531 
532  std::vector<pma::Track3D*> toSort;
533 
534  pma::Node3D* n = fNodes.front();
535  if (n->Prev()) {
536  pma::Segment3D* s = static_cast<pma::Segment3D*>(n->Prev());
537  pma::Track3D* t = s->Parent();
538 
539  if (t->NextSegment(n)) // starts from middle of another track: need to break that one first
540  {
541  int idx = t->index_of(n);
542  if (idx >= 0) {
543  pma::Track3D* u = t->Split(detProp, idx, false); // u is in front of t
544  if (u) {
545  allTracks.push_back(u);
546  if (u->Flip(detProp, allTracks)) {
547  InternalFlip(toSort);
548  toSort.push_back(this);
549  }
550  else {
551  mf::LogWarning("pma::Track3D")
552  << "Flip(): Could not flip after split (but new track is preserved!!).";
553  return false;
554  }
555  }
556  else {
557  return false;
558  } // could not flip/break associated tracks, so give up on this one
559  }
560  else {
561  throw cet::exception("pma::Track3D") << "Node not found." << std::endl;
562  }
563  }
564  else // flip root
565  {
566  if (t->Flip(detProp, allTracks)) // all ok, so can flip this track
567  {
568  InternalFlip(toSort);
569  toSort.push_back(this);
570  }
571  else {
572  return false;
573  } // could not flip/break associated tracks, so give up on this one
574  }
575  }
576  else // simply flip
577  {
578  InternalFlip(toSort);
579  toSort.push_back(this);
580  }
581 
582  for (size_t t = 0; t < toSort.size(); t++) {
583  bool sorted = false;
584  for (size_t u = 0; u < t; u++)
585  if (toSort[u] == toSort[t]) {
586  sorted = true;
587  break;
588  }
589  if (!sorted) {
590  toSort[t]->MakeProjection();
591  toSort[t]->SortHits();
592  }
593  }
594  return true;
595 }
596 
597 void pma::Track3D::InternalFlip(std::vector<pma::Track3D*>& toSort)
598 {
599  for (size_t i = 0; i < fNodes.size() - 1; i++)
600  if (fNodes[i]->NextCount() > 1) {
601  for (size_t j = 0; j < fNodes[i]->NextCount(); j++) {
602  pma::Segment3D* s = static_cast<pma::Segment3D*>(fNodes[i]->Next(j));
603  if (s->Parent() != this) toSort.push_back(s->Parent());
604  }
605  }
606 
607  if (fNodes.back()->NextCount())
608  for (size_t j = 0; j < fNodes.back()->NextCount(); j++) {
609  pma::Segment3D* s = static_cast<pma::Segment3D*>(fNodes.back()->Next(j));
610  toSort.push_back(s->Parent());
611  }
612 
613  if (fNodes.front()->Prev()) {
614  pma::Segment3D* s = static_cast<pma::Segment3D*>(fNodes.front()->Prev());
615  toSort.push_back(s->Parent());
616  s->Parent()->InternalFlip(toSort);
617  }
618 
619  std::reverse(fNodes.begin(), fNodes.end());
620  toSort.push_back(this);
621  RebuildSegments();
622 }
623 
625 {
626  std::vector<pma::Track3D*> toSort;
627  InternalFlip(toSort);
628  toSort.push_back(this);
629 
630  for (size_t t = 0; t < toSort.size(); t++) {
631  bool sorted = false;
632  for (size_t u = 0; u < t; u++)
633  if (toSort[u] == toSort[t]) {
634  sorted = true;
635  break;
636  }
637  if (!sorted) {
638  toSort[t]->MakeProjection();
639  toSort[t]->SortHits();
640  }
641  }
642 }
643 
645 {
646  if (!fNodes.size()) { return false; }
647 
648  pma::Node3D* n = fNodes.front();
649  if (n->Prev()) {
650  pma::Segment3D* s = static_cast<pma::Segment3D*>(n->Prev());
651  pma::Track3D* t = s->Parent();
652  if (t->NextSegment(n)) { return false; } // cannot flip if starts from middle of another track
653  else {
654  return t->CanFlip();
655  } // check root
656  }
657  else {
658  return true;
659  }
660 }
661 
662 void pma::Track3D::AutoFlip(pma::Track3D::EDirection dir, double thr, unsigned int n)
663 {
664  unsigned int nViews = 3;
665  pma::dedx_map dedxInViews[3];
666  for (unsigned int i = 0; i < nViews; i++) {
667  GetRawdEdxSequence(dedxInViews[i], i, 1);
668  }
669  unsigned int bestView = 2;
670  if (dedxInViews[0].size() > 2 * dedxInViews[2].size()) bestView = 0;
671  if (dedxInViews[1].size() > 2 * dedxInViews[2].size()) bestView = 1;
672 
673  std::vector<std::vector<double>> dedx;
674  for (size_t i = 0; i < size(); i++) {
675  auto it = dedxInViews[bestView].find(i);
676  if (it != dedxInViews[bestView].end()) { dedx.push_back(it->second); }
677  }
678  if (!dedx.empty()) dedx.pop_back();
679 
680  float dEdxStart = 0.0F, dEdxStop = 0.0F;
681  float dEStart = 0.0F, dxStart = 0.0F;
682  float dEStop = 0.0F, dxStop = 0.0F;
683  if (dedx.size() > 4) {
684  if (!n) // use default options
685  {
686  if (dedx.size() > 30)
687  n = 12;
688  else if (dedx.size() > 20)
689  n = 8;
690  else if (dedx.size() > 10)
691  n = 4;
692  else
693  n = 3;
694  }
695 
696  size_t k = (dedx.size() - 2) >> 1;
697  if (n > k) n = k;
698 
699  for (size_t i = 1, j = 0; j < n; i++, j++) {
700  dEStart += dedx[i][5];
701  dxStart += dedx[i][6];
702  }
703  if (dxStart > 0.0F) dEdxStart = dEStart / dxStart;
704 
705  for (size_t i = dedx.size() - 2, j = 0; j < n; i--, j++) {
706  dEStop += dedx[i][5];
707  dxStop += dedx[i][6];
708  }
709  if (dxStop > 0.0F) dEdxStop = dEStop / dxStop;
710  }
711  else if (dedx.size() == 4) {
712  dEStart = dedx[0][5] + dedx[1][5];
713  dxStart = dedx[0][6] + dedx[1][6];
714  dEStop = dedx[2][5] + dedx[3][5];
715  dxStop = dedx[2][6] + dedx[3][6];
716  if (dxStart > 0.0F) dEdxStart = dEStart / dxStart;
717  if (dxStop > 0.0F) dEdxStop = dEStop / dxStop;
718  }
719  else if (dedx.size() > 1) {
720  if (dedx.front()[2] > 0.0F) dEdxStart = dedx.front()[5] / dedx.front()[6];
721  if (dedx.back()[2] > 0.0F) dEdxStop = dedx.back()[5] / dedx.back()[6];
722  }
723  else
724  return;
725 
726  if ((dir == pma::Track3D::kForward) && ((1.0 + thr) * dEdxStop < dEdxStart)) {
727  mf::LogVerbatim("pma::Track3D")
728  << "Auto-flip fired (1), thr: " << (1.0 + thr) << ", value: " << dEdxStart / dEdxStop;
729  Flip(); // particle stops at the end of the track
730  }
731  if ((dir == pma::Track3D::kBackward) && (dEdxStop > (1.0 + thr) * dEdxStart)) {
732  mf::LogVerbatim("pma::Track3D")
733  << "Auto-flip fired (2), thr: " << (1.0 + thr) << ", value: " << dEdxStop / dEdxStart;
734  Flip(); // particle stops at the front of the track
735  }
736 }
737 
739  std::vector<pma::Track3D*>& allTracks,
741  double thr,
742  unsigned int n)
743 {
744  unsigned int nViews = 3;
745  pma::dedx_map dedxInViews[3];
746  for (unsigned int i = 0; i < nViews; i++) {
747  GetRawdEdxSequence(dedxInViews[i], i, 1);
748  }
749  unsigned int bestView = 2;
750  if (dedxInViews[0].size() > 2 * dedxInViews[2].size()) bestView = 0;
751  if (dedxInViews[1].size() > 2 * dedxInViews[2].size()) bestView = 1;
752 
753  std::vector<std::vector<double>> dedx;
754  for (size_t i = 0; i < size(); i++) {
755  auto it = dedxInViews[bestView].find(i);
756  if (it != dedxInViews[bestView].end()) { dedx.push_back(it->second); }
757  }
758  if (!dedx.empty()) dedx.pop_back();
759 
760  float dEdxStart = 0.0F, dEdxStop = 0.0F;
761  float dEStart = 0.0F, dxStart = 0.0F;
762  float dEStop = 0.0F, dxStop = 0.0F;
763  if (dedx.size() > 4) {
764  if (!n) // use default options
765  {
766  if (dedx.size() > 30)
767  n = 12;
768  else if (dedx.size() > 20)
769  n = 8;
770  else if (dedx.size() > 10)
771  n = 4;
772  else
773  n = 3;
774  }
775 
776  size_t k = (dedx.size() - 2) >> 1;
777  if (n > k) n = k;
778 
779  for (size_t i = 1, j = 0; j < n; i++, j++) {
780  dEStart += dedx[i][5];
781  dxStart += dedx[i][6];
782  }
783  if (dxStart > 0.0F) dEdxStart = dEStart / dxStart;
784 
785  for (size_t i = dedx.size() - 2, j = 0; j < n; i--, j++) {
786  dEStop += dedx[i][5];
787  dxStop += dedx[i][6];
788  }
789  if (dxStop > 0.0F) dEdxStop = dEStop / dxStop;
790  }
791  else if (dedx.size() == 4) {
792  dEStart = dedx[0][5] + dedx[1][5];
793  dxStart = dedx[0][6] + dedx[1][6];
794  dEStop = dedx[2][5] + dedx[3][5];
795  dxStop = dedx[2][6] + dedx[3][6];
796  if (dxStart > 0.0F) dEdxStart = dEStart / dxStart;
797  if (dxStop > 0.0F) dEdxStop = dEStop / dxStop;
798  }
799  else if (dedx.size() > 1) {
800  if (dedx.front()[2] > 0.0F) dEdxStart = dedx.front()[5] / dedx.front()[6];
801  if (dedx.back()[2] > 0.0F) dEdxStop = dedx.back()[5] / dedx.back()[6];
802  }
803  else
804  return false;
805 
806  bool done = false;
807  if ((dir == pma::Track3D::kForward) && ((1.0 + thr) * dEdxStop < dEdxStart)) {
808  mf::LogVerbatim("pma::Track3D")
809  << "Auto-flip fired (1), thr: " << (1.0 + thr) << ", value: " << dEdxStart / dEdxStop;
810  done = Flip(detProp, allTracks); // particle stops at the end of the track
811  }
812  if ((dir == pma::Track3D::kBackward) && (dEdxStop > (1.0 + thr) * dEdxStart)) {
813  mf::LogVerbatim("pma::Track3D")
814  << "Auto-flip fired (2), thr: " << (1.0 + thr) << ", value: " << dEdxStop / dEdxStart;
815  done = Flip(detProp, allTracks); // particle stops at the front of the track
816  }
817  return done;
818 }
819 
822  bool normalized) const
823 {
824  if (hits.empty()) {
825  mf::LogWarning("pma::Track3D") << "TestHitsMse(): Empty cluster.";
826  return -1.0;
827  }
828 
829  double mse = 0.0;
830  for (auto const& h : hits) {
831  unsigned int cryo = h->WireID().Cryostat;
832  unsigned int tpc = h->WireID().TPC;
833  unsigned int view = h->WireID().Plane;
834  unsigned int wire = h->WireID().Wire;
835  float drift = h->PeakTime();
836 
837  mse += Dist2(pma::WireDriftToCm(detProp, wire, drift, view, tpc, cryo), view, tpc, cryo);
838  }
839  if (normalized)
840  return mse / hits.size();
841  else
842  return mse;
843 }
844 
847  double dist) const
848 {
849  if (hits.empty()) {
850  mf::LogWarning("pma::Track3D") << "TestHits(): Empty cluster.";
851  return 0;
852  }
853 
854  TVector3 p3d;
855  double tst, d2 = dist * dist;
856  unsigned int nhits = 0;
857  for (auto const& h : hits)
858  if (GetUnconstrainedProj3D(detProp, h, p3d, tst) && tst < d2) ++nhits;
859 
860  return nhits;
861 }
862 
863 double pma::Track3D::Length(size_t start, size_t stop, size_t step) const
864 {
865  auto const nHits = size();
866  if (nHits < 2) return 0.0;
867 
868  if (start > stop) {
869  size_t tmp = stop;
870  stop = start;
871  start = tmp;
872  }
873  if (start >= nHits - 1) return 0.0;
874  if (stop >= nHits) stop = nHits - 1;
875 
876  double result = 0.0;
877  pma::Hit3D *h1 = nullptr, *h0 = fHits[start];
878 
879  if (!step) step = 1;
880  size_t i = start + step;
881  while (i <= stop) {
882  h1 = fHits[i];
883  result += sqrt(pma::Dist2(h1->Point3D(), h0->Point3D()));
884  h0 = h1;
885  i += step;
886  }
887  if (i - step < stop) // last step jumped beyond the stop point
888  { // so need to add the last short segment
889  result += sqrt(pma::Dist2(h0->Point3D(), back()->Point3D()));
890  }
891  return result;
892 }
893 
894 int pma::Track3D::NextHit(int index, unsigned int view, bool inclDisabled) const
895 {
896  pma::Hit3D* hit = nullptr;
897  if (index < -1) index = -1;
898  while (++index < (int)size()) // look for the next index of hit from the view
899  {
900  hit = fHits[index];
901  if (hit->View2D() == view) {
902  if (inclDisabled)
903  break;
904  else if (hit->IsEnabled())
905  break;
906  }
907  }
908  return index;
909 }
910 
911 int pma::Track3D::PrevHit(int index, unsigned int view, bool inclDisabled) const
912 {
913  pma::Hit3D* hit = nullptr;
914  if (index > (int)size()) index = (int)size();
915  while (--index >= 0) // look for the prev index of hit from the view
916  {
917  hit = fHits[index];
918  if (hit->View2D() == view) {
919  if (inclDisabled)
920  break;
921  else if (hit->IsEnabled())
922  break;
923  }
924  }
925  return index;
926 }
927 
928 double pma::Track3D::HitDxByView(size_t index,
929  unsigned int view,
931  bool secondDir) const
932 {
933  pma::Hit3D* nexthit = nullptr;
934  pma::Hit3D* hit = fHits[index];
935 
936  if (hit->View2D() != view) {
937  mf::LogWarning("pma::Track3D") << "Function used with the hit not matching specified view.";
938  }
939 
940  double dx = 0.0; // [cm]
941  bool hitFound = false;
942  int i = index;
943  switch (dir) {
945  while (!hitFound && (++i < (int)size())) {
946  nexthit = fHits[i];
947  dx += sqrt(pma::Dist2(hit->Point3D(), nexthit->Point3D()));
948 
949  if (nexthit->View2D() == view)
950  hitFound = true;
951  else
952  hitFound = false;
953 
954  hit = nexthit;
955  }
956  if (!hitFound) {
957  if (!secondDir)
958  dx = 0.5 * HitDxByView(index, view, pma::Track3D::kBackward, true);
959  else {
960  dx = Length();
961  mf::LogWarning("pma::Track3D") << "Single hit in this view.";
962  }
963  }
964  break;
965 
967  while (!hitFound && (--i >= 0)) {
968  nexthit = fHits[i];
969  dx += sqrt(pma::Dist2(hit->Point3D(), nexthit->Point3D()));
970 
971  if (nexthit->View2D() == view)
972  hitFound = true;
973  else
974  hitFound = false;
975 
976  hit = nexthit;
977  }
978  if (!hitFound) {
979  if (!secondDir)
980  dx = 0.5 * HitDxByView(index, view, pma::Track3D::kForward, true);
981  else {
982  dx = Length();
983  mf::LogWarning("pma::Track3D") << "Single hit in this view.";
984  }
985  }
986  break;
987 
988  default: mf::LogError("pma::Track3D") << "Direction undefined."; break;
989  }
990  return dx;
991 }
992 
993 double pma::Track3D::HitDxByView(size_t index, unsigned int view) const
994 {
995  if (index < size()) {
996  return 0.5 * (HitDxByView(index, view, pma::Track3D::kForward) +
997  HitDxByView(index, view, pma::Track3D::kBackward));
998  }
999  else {
1000  mf::LogError("pma::Track3D") << "Hit index out of range.";
1001  return 0.0;
1002  }
1003 }
1004 
1006 {
1007  pma::Segment3D* seg = nullptr;
1008  unsigned int nCount = vtx->NextCount();
1009  unsigned int k = 0;
1010  while (k < nCount) {
1011  seg = static_cast<pma::Segment3D*>(vtx->Next(k));
1012  if (seg && (seg->Parent() == this)) return seg;
1013  k++;
1014  }
1015  return 0;
1016 }
1017 
1019 {
1020  if (vtx->Prev()) {
1021  auto seg = static_cast<pma::Segment3D*>(vtx->Prev());
1022  if (seg->Parent() == this) return seg;
1023  }
1024  return nullptr;
1025 }
1026 
1027 double pma::Track3D::GetRawdEdxSequence(std::map<size_t, std::vector<double>>& dedx,
1028  unsigned int view,
1029  unsigned int skip,
1030  bool inclDisabled) const
1031 {
1032  dedx.clear();
1033 
1034  if (!size()) return 0.0;
1035 
1036  size_t step = 1;
1037 
1038  pma::Hit3D* hit = nullptr;
1039 
1040  double rv, dr, dR, dq, dEq, qSkipped = 0.0;
1041 
1042  size_t j = NextHit(-1, view, inclDisabled), s = skip;
1043  if (j >= size()) return 0.0F; // no charged hits at all
1044  while (j < size()) // look for the first hit index
1045  {
1046  hit = fHits[j];
1047  dq = hit->SummedADC();
1048  if (s) {
1049  qSkipped += dq;
1050  s--;
1051  }
1052  else
1053  break;
1054 
1055  j = NextHit(j, view, inclDisabled);
1056  }
1057 
1058  size_t jmax = PrevHit(size(), view, inclDisabled);
1059 
1060  std::vector<size_t> indexes;
1061  TVector3 p0(0., 0., 0.), p1(0., 0., 0.);
1062  TVector2 c0(0., 0.), c1(0., 0.);
1063  while (j <= jmax) {
1064  indexes.clear(); // prepare to collect hit indexes used for this dE/dx entry
1065 
1066  indexes.push_back(j);
1067  hit = fHits[j];
1068 
1069  p0 = hit->Point3D();
1070  p1 = hit->Point3D();
1071 
1072  c0.Set(hit->Wire(), hit->PeakTime());
1073  c1.Set(hit->Wire(), hit->PeakTime());
1074 
1075  dEq = hit->SummedADC(); // [now it is ADC sum]
1076 
1077  dr = HitDxByView(j,
1078  view,
1079  pma::Track3D::kForward); // protection against hits on the same position
1080  rv = HitDxByView(j, view); // dx seen by j-th hit
1081  fHits[j]->fDx = rv;
1082  dR = rv;
1083 
1084  size_t m = 1; // number of hits with charge > 0
1085  while (((m < step) || (dR < 0.1) || (dr == 0.0)) && (j <= jmax)) {
1086  j = NextHit(j, view); // just next, even if tagged as outlier
1087  if (j > jmax) break; // no more hits in this view
1088 
1089  hit = fHits[j];
1090  if (!inclDisabled && !hit->IsEnabled()) {
1091  if (dr == 0.0)
1092  continue;
1093  else
1094  break;
1095  }
1096  indexes.push_back(j);
1097 
1098  p1 = hit->Point3D();
1099 
1100  c1.Set(hit->Wire(), hit->PeakTime());
1101 
1102  dq = hit->SummedADC();
1103 
1104  dEq += dq;
1105 
1106  dr = HitDxByView(j, view, pma::Track3D::kForward);
1107  rv = HitDxByView(j, view);
1108  fHits[j]->fDx = rv;
1109  dR += rv;
1110  m++;
1111  }
1112  p0 += p1;
1113  p0 *= 0.5;
1114  c0 += c1;
1115  c0 *= 0.5;
1116 
1117  double range = Length(0, j);
1118 
1119  std::vector<double> trk_section;
1120  trk_section.push_back(c0.X());
1121  trk_section.push_back(c0.Y());
1122  trk_section.push_back(p0.X());
1123  trk_section.push_back(p0.Y());
1124  trk_section.push_back(p0.Z());
1125  trk_section.push_back(dEq);
1126  trk_section.push_back(dR);
1127  trk_section.push_back(range);
1128 
1129  for (auto const idx : indexes)
1130  dedx[idx] = trk_section;
1131 
1132  j = NextHit(j, view, inclDisabled);
1133  }
1134 
1135  return qSkipped;
1136 }
1137 
1139  detinfo::DetectorPropertiesData const& detProp,
1140  unsigned int wire,
1141  unsigned int view) const
1142 {
1143  std::vector<float> drifts;
1144  for (size_t i = 0; i < fNodes.size() - 1; i++) {
1145  int tpc = fNodes[i]->TPC(), cryo = fNodes[i]->Cryo();
1146  if ((tpc != fNodes[i + 1]->TPC()) || (cryo != fNodes[i + 1]->Cryo())) continue;
1147 
1148  TVector2 p0 = pma::CmToWireDrift(detProp,
1149  fNodes[i]->Projection2D(view).X(),
1150  fNodes[i]->Projection2D(view).Y(),
1151  view,
1152  fNodes[i]->TPC(),
1153  fNodes[i]->Cryo());
1154  TVector2 p1 = pma::CmToWireDrift(detProp,
1155  fNodes[i + 1]->Projection2D(view).X(),
1156  fNodes[i + 1]->Projection2D(view).Y(),
1157  view,
1158  fNodes[i + 1]->TPC(),
1159  fNodes[i + 1]->Cryo());
1160 
1161  if ((p0.X() - wire) * (p1.X() - wire) <= 0.0) {
1162  double frac_w = (wire - p0.X()) / (p1.X() - p0.X());
1163  double d = p0.Y() + frac_w * (p1.Y() - p0.Y());
1164  drifts.push_back((float)d);
1165  }
1166  }
1167  return drifts;
1168 }
1169 
1171  unsigned int view)
1172 {
1173  int dPrev, dw, w, wx, wPrev, i = NextHit(-1, view);
1174 
1175  pma::Hit3D* hitPrev = nullptr;
1176  pma::Hit3D* hit = nullptr;
1177 
1178  std::vector<pma::Hit3D*> missHits;
1179 
1180  while (i < (int)size()) {
1181  hitPrev = hit;
1182  hit = fHits[i];
1183 
1184  if (hit->View2D() == view) {
1185  w = hit->Wire();
1186  if (hitPrev) {
1187  wPrev = hitPrev->Wire();
1188  dPrev = (int)hitPrev->PeakTime();
1189  if (abs(w - wPrev) > 1) {
1190  if (w > wPrev)
1191  dw = 1;
1192  else
1193  dw = -1;
1194  wx = wPrev + dw;
1195  int k = 1;
1196  while (wx != w) {
1197  int peakTime = 0;
1198  unsigned int iWire = wx;
1199  std::vector<float> drifts = DriftsOfWireIntersection(detProp, wx, view);
1200  if (drifts.size()) {
1201  peakTime = drifts[0];
1202  for (size_t d = 1; d < drifts.size(); d++)
1203  if (fabs(drifts[d] - dPrev) < fabs(peakTime - dPrev)) peakTime = drifts[d];
1204  }
1205  else {
1206  mf::LogVerbatim("pma::Track3D") << "Track does not intersect with the wire " << wx;
1207  break;
1208  }
1209  pma::Hit3D* hmiss =
1210  new pma::Hit3D(detProp, iWire, view, hit->TPC(), hit->Cryo(), peakTime, 1.0, 1.0);
1211  missHits.push_back(hmiss);
1212  wx += dw;
1213  k++;
1214  }
1215  }
1216  }
1217  }
1218  else
1219  hit = hitPrev;
1220 
1221  i = NextHit(i, view, true);
1222  while ((i < (int)size()) && (hit->TPC() != fHits[i]->TPC())) {
1223  hitPrev = hit;
1224  hit = fHits[i];
1225  i = NextHit(i, view, true);
1226  }
1227  }
1228 
1229  if (missHits.size()) {
1230  for (size_t hi = 0; hi < missHits.size(); hi++) {
1231  push_back(missHits[hi]);
1232  }
1233 
1234  MakeProjection();
1235  SortHits();
1236  }
1237 
1238  return missHits.size();
1239 }
1240 
1242 {
1243  fNodes.push_back(node);
1244  if (fNodes.size() > 1) RebuildSegments();
1245 }
1246 
1248 {
1249  pma::Segment3D* seg;
1250  pma::Segment3D* maxSeg = nullptr;
1251 
1252  size_t si = 0;
1253  while (si < fSegments.size()) {
1254  if (!fSegments[si]->IsFrozen()) {
1255  maxSeg = fSegments[si];
1256  break;
1257  }
1258  else
1259  si++;
1260  }
1261  if (!maxSeg) return false;
1262 
1263  unsigned int nHitsByView[3];
1264  unsigned int nHits, maxHits = 0;
1265  unsigned int vIndex = 0, segHits, maxSegHits = 0;
1266  float segLength, maxLength = maxSeg->Length();
1267  for (unsigned int i = si + 1; i < fNodes.size(); i++) {
1268  seg = static_cast<pma::Segment3D*>(fNodes[i]->Prev());
1269  if (seg->IsFrozen()) continue;
1270 
1271  nHitsByView[0] = seg->NEnabledHits(geo::kU);
1272  nHitsByView[1] = seg->NEnabledHits(geo::kV);
1273  nHitsByView[2] = seg->NEnabledHits(geo::kZ);
1274  segHits = nHitsByView[0] + nHitsByView[1] + nHitsByView[2];
1275 
1276  if (segHits < 15) {
1277  if ((nHitsByView[0] == 0) && ((nHitsByView[1] < 4) || (nHitsByView[2] < 4))) continue;
1278  if ((nHitsByView[1] == 0) && ((nHitsByView[0] < 4) || (nHitsByView[2] < 4))) continue;
1279  if ((nHitsByView[2] == 0) && ((nHitsByView[0] < 4) || (nHitsByView[1] < 4))) continue;
1280  }
1281 
1282  nHits = fNodes[i]->NEnabledHits() + seg->NEnabledHits() + fNodes[i - 1]->NEnabledHits();
1283 
1284  if (nHits > maxHits) {
1285  maxHits = nHits;
1286  maxLength = seg->Length();
1287  maxSegHits = segHits;
1288  maxSeg = seg;
1289  vIndex = i;
1290  }
1291  else if (nHits == maxHits) {
1292  segLength = seg->Length();
1293  if (segLength > maxLength) {
1294  maxLength = segLength;
1295  maxSegHits = segHits;
1296  maxSeg = seg;
1297  vIndex = i;
1298  }
1299  }
1300  }
1301 
1302  if (maxSegHits > 1) {
1303  maxSeg->SortHits();
1304 
1305  nHitsByView[0] = maxSeg->NEnabledHits(geo::kU);
1306  nHitsByView[1] = maxSeg->NEnabledHits(geo::kV);
1307  nHitsByView[2] = maxSeg->NEnabledHits(geo::kZ);
1308 
1309  unsigned int maxViewIdx = 2, midViewIdx = 2;
1310  if ((nHitsByView[2] >= nHitsByView[1]) && (nHitsByView[1] >= nHitsByView[0])) {
1311  maxViewIdx = 2;
1312  midViewIdx = 1;
1313  }
1314  else if ((nHitsByView[1] >= nHitsByView[2]) && (nHitsByView[2] >= nHitsByView[0])) {
1315  maxViewIdx = 1;
1316  midViewIdx = 2;
1317  }
1318  else if ((nHitsByView[0] >= nHitsByView[2]) && (nHitsByView[2] >= nHitsByView[1])) {
1319  maxViewIdx = 0;
1320  midViewIdx = 2;
1321  }
1322  else if ((nHitsByView[2] >= nHitsByView[0]) && (nHitsByView[0] >= nHitsByView[1])) {
1323  maxViewIdx = 2;
1324  midViewIdx = 0;
1325  }
1326  else if ((nHitsByView[0] >= nHitsByView[1]) && (nHitsByView[1] >= nHitsByView[2])) {
1327  maxViewIdx = 0;
1328  midViewIdx = 1;
1329  }
1330  else if ((nHitsByView[1] >= nHitsByView[0]) && (nHitsByView[0] >= nHitsByView[2])) {
1331  maxViewIdx = 1;
1332  midViewIdx = 0;
1333  }
1334  if (nHitsByView[midViewIdx] < 2) midViewIdx = maxViewIdx;
1335 
1336  if (nHitsByView[midViewIdx] < 2) {
1337  mf::LogVerbatim("pma::Track3D") << "AddNode(): too few hits.";
1338  return false;
1339  }
1340 
1341  unsigned int mHits[3] = {0, 0, 0};
1342  unsigned int halfIndex = (nHitsByView[midViewIdx] >> 1) - 1;
1343  unsigned int n = 0, i = 0, i0 = 0, i1 = 0;
1344  while (i < maxSeg->NHits() - 1) {
1345  if (maxSeg->Hit(i).IsEnabled()) {
1346  mHits[maxSeg->Hit(i).View2D()]++;
1347  if (maxSeg->Hit(i).View2D() == midViewIdx) {
1348  if (n == halfIndex) break;
1349  n++;
1350  }
1351  }
1352  i++;
1353  }
1354 
1355  i0 = i;
1356  i++;
1357  while ((i < maxSeg->NHits()) &&
1358  !((maxSeg->Hit(i).View2D() == midViewIdx) && maxSeg->Hit(i).IsEnabled())) {
1359  i++;
1360  }
1361  i1 = i;
1362 
1363  if (!nHitsByView[0]) {
1364  if (nHitsByView[1] && (mHits[1] < 2)) {
1365  mf::LogVerbatim("pma::Track3D") << "AddNode(): low Ind2 hits.";
1366  return false;
1367  }
1368  if (nHitsByView[2] && (mHits[2] < 2)) {
1369  mf::LogVerbatim("pma::Track3D") << "AddNode(): low Coll hits.";
1370  return false;
1371  }
1372  }
1373 
1374  maxSeg->SetProjection(maxSeg->Hit(i0));
1375  maxSeg->SetProjection(maxSeg->Hit(i1));
1376 
1377  unsigned int tpc = maxSeg->Hit(i0).TPC();
1378  unsigned int cryo = maxSeg->Hit(i0).Cryo();
1379 
1380  pma::Node3D* p = new pma::Node3D(detProp,
1381  (maxSeg->Hit(i0).Point3D() + maxSeg->Hit(i1).Point3D()) * 0.5,
1382  tpc,
1383  cryo,
1384  false,
1385  fNodes[vIndex]->GetDriftShift());
1386 
1387  fNodes.insert(fNodes.begin() + vIndex, p);
1388 
1389  maxSeg->AddNext(fNodes[vIndex]);
1390 
1391  seg = new pma::Segment3D(this, fNodes[vIndex], fNodes[vIndex + 1]);
1392  fSegments.insert(fSegments.begin() + vIndex, seg);
1393 
1394  return true;
1395  }
1396  else
1397  return false;
1398 }
1399 
1401  TVector3 const& p3d,
1402  size_t at_idx,
1403  unsigned int tpc,
1404  unsigned int cryo)
1405 {
1406  pma::Node3D* vtx =
1407  new pma::Node3D(detProp, p3d, tpc, cryo, false, fNodes[at_idx]->GetDriftShift());
1408  fNodes.insert(fNodes.begin() + at_idx, vtx);
1409 
1410  if (fNodes.size() > 1) RebuildSegments();
1411 }
1412 
1414 {
1415  if ((fNodes.size() > 1) && (idx < fNodes.size())) {
1416  pma::Node3D* vtx = fNodes[idx];
1417  fNodes.erase(fNodes.begin() + idx);
1418  RebuildSegments();
1419 
1420  if (!vtx->NextCount() && !vtx->Prev()) { delete vtx; }
1421 
1422  return true;
1423  }
1424  else
1425  return false;
1426 }
1427 
1429  size_t idx,
1430  bool try_start_at_idx)
1431 {
1432  if (!idx || (idx + 1 >= fNodes.size())) return 0;
1433 
1434  pma::Node3D* n = nullptr;
1435  pma::Track3D* t0 = new pma::Track3D();
1436  t0->fT0 = fT0;
1437  t0->fT0Flag = fT0Flag;
1438  t0->fTag = fTag;
1439 
1440  for (size_t i = 0; i < idx; ++i) {
1441  n = fNodes.front();
1442  n->ClearAssigned();
1443 
1444  pma::Segment3D* s = static_cast<pma::Segment3D*>(n->Prev());
1445  if (s && (s->Parent() == this)) s->RemoveNext(n);
1446 
1447  size_t k = 0;
1448  while (k < n->NextCount()) {
1449  s = static_cast<pma::Segment3D*>(n->Next(k));
1450  if (s->Parent() == this)
1451  n->RemoveNext(s);
1452  else
1453  k++;
1454  }
1455 
1456  fNodes.erase(fNodes.begin());
1457  t0->fNodes.push_back(n);
1458  }
1459 
1460  n = fNodes.front();
1461  t0->fNodes.push_back(
1462  new pma::Node3D(detProp, n->Point3D(), n->TPC(), n->Cryo(), false, n->GetDriftShift()));
1463  t0->RebuildSegments();
1464  RebuildSegments();
1465 
1466  size_t h = 0;
1467  while (h < size()) {
1468  pma::Hit3D* h3d = fHits[h];
1469  unsigned int view = h3d->View2D(), tpc = h3d->TPC(), cryo = h3d->Cryo();
1470  double dist2D_old = Dist2(h3d->Point2D(), view, tpc, cryo);
1471  double dist2D_new = t0->Dist2(h3d->Point2D(), view, tpc, cryo);
1472 
1473  if ((dist2D_new < dist2D_old) && t0->HasTPC(tpc))
1474  t0->push_back(release_at(h));
1475  else if (!HasTPC(tpc) && t0->HasTPC(tpc))
1476  t0->push_back(release_at(h));
1477  else
1478  h++;
1479  }
1480 
1481  bool passed = true;
1482  if (HasTwoViews() && t0->HasTwoViews()) {
1483  if (try_start_at_idx && t0->CanFlip()) {
1484  mf::LogVerbatim("pma::Track3D") << " attach new t0 and this trk to a common start node";
1485  t0->Flip();
1486  passed = t0->AttachTo(fNodes.front());
1487  }
1488  else {
1489  mf::LogVerbatim("pma::Track3D") << " attach this trk to the new t0 end node";
1490  passed = AttachTo(t0->fNodes.back());
1491  }
1492  }
1493  else {
1494  mf::LogVerbatim("pma::Track3D") << " single-view track";
1495  passed = false;
1496  }
1497 
1498  if (!passed) {
1499  mf::LogVerbatim("pma::Track3D") << " undo split";
1500  while (t0->size())
1501  push_back(t0->release_at(0));
1502 
1503  for (size_t i = 0; i < idx; ++i) {
1504  fNodes.insert(fNodes.begin() + i, t0->fNodes.front());
1505  t0->fNodes.erase(t0->fNodes.begin());
1506  }
1507 
1508  RebuildSegments();
1509  delete t0;
1510  t0 = 0;
1511  }
1512 
1513  return t0;
1514 }
1515 
1516 bool pma::Track3D::AttachTo(pma::Node3D* vStart, bool noFlip)
1517 {
1518  pma::Node3D* vtx = fNodes.front();
1519 
1520  if (vtx == vStart) return true; // already connected!
1521 
1522  pma::Track3D* rootThis = GetRoot();
1523  if (vStart->Prev()) {
1524  pma::Track3D* rootPrev = static_cast<pma::Segment3D*>(vStart->Prev())->Parent()->GetRoot();
1525  if (rootPrev->IsAttachedTo(rootThis)) { return false; }
1526  }
1527  else if (vStart->NextCount()) {
1528  pma::Track3D* rootNext = static_cast<pma::Segment3D*>(vStart->Next(0))->Parent()->GetRoot();
1529  if (rootNext->IsAttachedTo(rootThis)) { return false; }
1530  }
1531  else {
1532  return false;
1533  }
1534 
1535  for (auto n : fNodes)
1536  if (n == vStart) {
1537  mf::LogError("pma::Track3D") << "Don't create loops!";
1538  return false;
1539  }
1540 
1541  if (!noFlip && CanFlip() && (vStart->TPC() == fNodes.back()->TPC()) &&
1542  (pma::Dist2(vtx->Point3D(), vStart->Point3D()) >
1543  pma::Dist2(fNodes.back()->Point3D(), vStart->Point3D())) &&
1544  (fNodes.back()->NextCount() == 0)) {
1545  mf::LogError("pma::Track3D") << "Flip, endpoint closer to vStart.";
1546  Flip();
1547  }
1548 
1549  if (vStart->TPC() == vtx->TPC())
1550  return AttachToSameTPC(vStart);
1551  else
1552  return AttachToOtherTPC(vStart);
1553 }
1554 
1556 {
1557  if (fNodes.front()->Prev()) return false;
1558 
1559  mf::LogVerbatim("pma::Track3D") << "Attach to track in another TPC.";
1560 
1561  fNodes.insert(fNodes.begin(), vStart);
1562 
1563  fSegments.insert(fSegments.begin(), new pma::Segment3D(this, fNodes[0], fNodes[1]));
1564 
1565  return true;
1566 }
1567 
1569 {
1570  pma::Node3D* vtx = fNodes.front();
1571 
1572  if (vtx->Prev()) {
1573  pma::Segment3D* segPrev = static_cast<pma::Segment3D*>(vtx->Prev());
1574  pma::Track3D* tpPrev = segPrev->Parent();
1575  if (tpPrev->NextSegment(vtx)) { return false; }
1576  else if (tpPrev->CanFlip()) {
1577  tpPrev->Flip();
1578  } // flip in local vtx, no problem
1579  else {
1580  if (vStart->Prev()) {
1581  pma::Segment3D* segNew = static_cast<pma::Segment3D*>(vStart->Prev());
1582  pma::Track3D* tpNew = segNew->Parent();
1583  if (tpNew->NextSegment(vStart)) { return false; }
1584  else if (tpNew->CanFlip()) // flip in remote vStart, no problem
1585  {
1586  tpNew->Flip();
1587 
1588  mf::LogVerbatim("pma::Track3D") << "Reconnect prev to vStart.";
1589  tpPrev->fNodes[tpPrev->fNodes.size() - 1] = vStart;
1590  segPrev->AddNext(vStart);
1591  }
1592  else {
1593  mf::LogError("pma::Track3D") << "Flips in vtx and vStart not possible, cannot attach.";
1594  return false;
1595  }
1596  }
1597  else {
1598  mf::LogVerbatim("pma::Track3D") << "Reconnect prev to vStart.";
1599  tpPrev->fNodes[tpPrev->fNodes.size() - 1] = vStart;
1600  segPrev->AddNext(vStart);
1601  }
1602  }
1603  }
1604 
1605  while (vtx->NextCount()) // reconnect nexts to vStart
1606  {
1607  pma::Segment3D* seg = static_cast<pma::Segment3D*>(vtx->Next(0));
1608  pma::Track3D* trk = seg->Parent();
1609 
1610  vtx->RemoveNext(seg);
1611  trk->fNodes[0] = vStart;
1612  vStart->AddNext(seg);
1613  }
1614 
1615  if (vtx->NextCount() || vtx->Prev()) // better throw here
1616  {
1617  throw cet::exception("pma::Track3D") << "Something is still using disconnected vertex.";
1618  }
1619  else
1620  delete vtx; // ok
1621  return true;
1622 }
1623 
1625 {
1626  pma::Node3D* vtx = fNodes.back();
1627 
1628  if (vtx == vStart) return true; // already connected!
1629 
1630  pma::Track3D* rootThis = GetRoot();
1631  if (vStart->Prev()) {
1632  pma::Track3D* rootPrev = static_cast<pma::Segment3D*>(vStart->Prev())->Parent()->GetRoot();
1633  if (rootPrev->IsAttachedTo(rootThis)) { return false; }
1634  }
1635  else if (vStart->NextCount()) {
1636  pma::Track3D* rootNext = static_cast<pma::Segment3D*>(vStart->Next(0))->Parent()->GetRoot();
1637  if (rootNext->IsAttachedTo(rootThis)) { return false; }
1638  }
1639  else {
1640  return false;
1641  }
1642 
1643  for (auto n : fNodes)
1644  if (n == vStart) {
1645  mf::LogError("pma::Track3D") << "Don't create loops!";
1646  return false;
1647  }
1648 
1649  if (vStart->TPC() == vtx->TPC())
1650  return AttachBackToSameTPC(vStart);
1651  else
1652  return AttachBackToOtherTPC(vStart);
1653 }
1654 
1656 {
1657  if (vStart->Prev()) return false;
1658 
1659  mf::LogVerbatim("pma::Track3D") << "Attach to track in another TPC.";
1660 
1661  fNodes.push_back(vStart);
1662 
1663  size_t idx = fNodes.size() - 1;
1664  fSegments.push_back(new pma::Segment3D(this, fNodes[idx - 1], fNodes[idx]));
1665 
1666  return true;
1667 }
1668 
1670 {
1671  pma::Node3D* vtx = fNodes.back();
1672 
1673  if (vStart->Prev()) {
1674  pma::Segment3D* seg = static_cast<pma::Segment3D*>(vStart->Prev());
1675  pma::Track3D* tp = seg->Parent();
1676  if (tp->NextSegment(vStart)) {
1677  mf::LogError("pma::Track3D") << "Cannot attach back to inner node of other track.";
1678  return false;
1679  }
1680 
1681  if (tp->CanFlip())
1682  tp->Flip(); // flip in remote vStart, no problem
1683  else {
1684  mf::LogError("pma::Track3D") << "Flip not possible, cannot attach.";
1685  return false;
1686  }
1687  }
1688  fNodes[fNodes.size() - 1] = vStart;
1689  fSegments[fSegments.size() - 1]->AddNext(vStart);
1690 
1691  while (vtx->NextCount()) // reconnect nexts to vStart
1692  {
1693  pma::Segment3D* seg = static_cast<pma::Segment3D*>(vtx->Next(0));
1694  pma::Track3D* trk = seg->Parent();
1695 
1696  vtx->RemoveNext(seg);
1697  trk->fNodes[0] = vStart;
1698  vStart->AddNext(seg);
1699  }
1700 
1701  if (vtx->NextCount() || vtx->Prev()) {
1702  throw cet::exception("pma::Track3D")
1703  << "Something is still using disconnected vertex." << std::endl;
1704  }
1705  else
1706  delete vtx; // ok
1707 
1708  return true;
1709 }
1710 
1712 {
1713  if (src->fNodes.front()->Prev()) {
1714  throw cet::exception("pma::Track3D")
1715  << "Cant extend with a track being a daughter of another track." << std::endl;
1716  }
1717 
1718  src->DeleteSegments(); // disconnect from vertices and delete
1719  for (size_t i = 0; i < src->fNodes.size(); ++i) {
1720  fNodes.push_back(src->fNodes[i]);
1721 
1722  size_t idx = fNodes.size() - 1;
1723  fSegments.push_back(new pma::Segment3D(this, fNodes[idx - 1], fNodes[idx]));
1724  }
1725  src->fNodes.clear(); // just empty the node collection
1726 
1727  while (src->size()) {
1728  push_back(src->release_at(0));
1729  } // move hits
1730 
1731  for (auto p : src->fAssignedPoints) {
1732  fAssignedPoints.push_back(p);
1733  } // move 3D reference points
1734  src->fAssignedPoints.clear();
1735 
1736  MakeProjection();
1737  SortHits();
1738 
1739  delete src;
1740 }
1741 
1743 {
1744  pma::Track3D* trk = nullptr;
1745 
1746  if (fNodes.size()) {
1747  pma::Segment3D* seg = static_cast<pma::Segment3D*>(fNodes.front()->Prev());
1748  if (seg) trk = seg->Parent()->GetRoot();
1749  if (!trk) trk = this;
1750  }
1751  else
1752  throw cet::exception("pma::Track3D") << "Broken track, no nodes.";
1753 
1754  return trk;
1755 }
1756 
1757 bool pma::Track3D::GetBranches(std::vector<pma::Track3D const*>& branches, bool skipFirst) const
1758 {
1759  for (auto trk : branches)
1760  if (trk == this) { throw cet::exception("pma::Track3D") << "Track tree has loop."; }
1761 
1762  branches.push_back(this);
1763 
1764  size_t i0 = 0;
1765  if (skipFirst) i0 = 1;
1766 
1767  for (size_t i = i0; i < fNodes.size(); ++i)
1768  for (size_t n = 0; n < fNodes[i]->NextCount(); n++) {
1769  pma::Segment3D* seg = static_cast<pma::Segment3D*>(fNodes[i]->Next(n));
1770  if (seg && (seg->Parent() != this)) seg->Parent()->GetBranches(branches, true);
1771  }
1772 
1773  return true;
1774 }
1775 
1777 {
1778  if (trk == this) return true;
1779 
1780  std::vector<pma::Track3D const*> branchesThis, branchesTrk;
1781 
1782  if (!trk->GetBranches(branchesTrk)) return true; // has loop - better check the reason
1783  if (!GetBranches(branchesThis)) return true; // has loop - better check the reason
1784 
1785  for (auto bThis : branchesThis)
1786  for (auto bTrk : branchesTrk)
1787  if (bThis == bTrk) return true;
1788  return false;
1789 }
1790 
1791 bool pma::Track3D::HasRefPoint(TVector3* p) const
1792 {
1793  for (auto point : fAssignedPoints)
1794  if (point == p) return true;
1795  return false;
1796 }
1797 
1798 double pma::Track3D::GetMse(unsigned int view) const
1799 {
1800  double sumMse = 0.0;
1801  unsigned int nEnabledHits = 0;
1802  for (auto n : fNodes) {
1803  sumMse += n->SumDist2(view);
1804  nEnabledHits += n->NEnabledHits(view);
1805  }
1806  for (auto s : fSegments) {
1807  sumMse += s->SumDist2(view);
1808  nEnabledHits += s->NEnabledHits(view);
1809  }
1810 
1811  if (nEnabledHits)
1812  return sumMse / nEnabledHits;
1813  else
1814  return 0.0;
1815 }
1816 
1817 double pma::Track3D::GetObjFunction(float penaltyFactor) const
1818 {
1819  double sum = 0.0;
1820  float p = penaltyFactor * fPenaltyValue;
1821  for (size_t i = 0; i < fNodes.size(); i++) {
1822  sum += fNodes[i]->GetObjFunction(p, fEndSegWeight);
1823  }
1824  return sum / fNodes.size();
1825 }
1826 
1828  int nNodes,
1829  double eps,
1830  bool selAllHits,
1831  bool setAllNodes,
1832  size_t selSegHits,
1833  size_t selVtxHits)
1834 {
1835  if (!fNodes.size()) {
1836  mf::LogError("pma::Track3D") << "Track not initialized.";
1837  return 0.0;
1838  }
1839 
1840  if (!UpdateParams()) {
1841  mf::LogError("pma::Track3D") << "Track empty.";
1842  return 1.0e10;
1843  }
1844  double g0 = GetObjFunction(), g1 = 0.0;
1845  if (g0 == 0.0) return g0;
1846 
1847  // set branching flag only at the beginning, optimization is not changing
1848  // that and new nodes are not branching
1849  for (auto n : fNodes)
1850  n->SetVertexToBranching(setAllNodes);
1851 
1852  bool stop = false;
1853  fMinSegStop = fSegments.size();
1854  fMaxSegStop = (int)(size() / fMaxSegStopFactor) + 1;
1855  do {
1856  if (selSegHits || selVtxHits) SelectRndHits(selSegHits, selVtxHits);
1857 
1858  bool stepDone = true;
1859  unsigned int stepIter = 0;
1860  do {
1861  double gstep = 1.0;
1862  unsigned int iter = 0;
1863  while ((gstep > eps) && (iter < 1000)) {
1864  if ((fNodes.size() < 4) || (iter % 10 == 0))
1865  MakeProjection();
1866  else
1868 
1869  if (!UpdateParams()) {
1870  mf::LogError("pma::Track3D") << "Track empty.";
1871  return 0.0;
1872  }
1873 
1874  for (auto n : fNodes)
1875  n->Optimize(fPenaltyValue, fEndSegWeight);
1876 
1877  g1 = g0;
1878  g0 = GetObjFunction();
1879 
1880  if (g0 == 0.0F) {
1881  MakeProjection();
1882  break;
1883  }
1884  gstep = fabs(g0 - g1) / g0;
1885  iter++;
1886  }
1887 
1888  stepIter++;
1889  if (fNodes.size() > 2) {
1891  }
1892  } while (!stepDone && (stepIter < 5));
1893 
1894  if (selAllHits) {
1895  selAllHits = false;
1896  selSegHits = 0;
1897  selVtxHits = 0;
1898  if (SelectAllHits()) continue;
1899  }
1900 
1901  switch (nNodes) {
1902  case 0: stop = true; break; // just optimize existing vertices
1903 
1904  case -1: // grow and optimize until automatic stop condition
1905  mf::LogVerbatim("pma::Track3D") << "optimized segments: " << fSegments.size();
1906  if ((fSegments.size() >= fSegStopValue) || (fSegments.size() >= fMaxSegStop)) { stop = true; }
1907  else {
1908  if (!AddNode(detProp)) stop = true;
1909  }
1910  break;
1911 
1912  default: // grow and optimize until fixed number of vertices is added
1913  if (nNodes > 12) {
1914  if (AddNode(detProp)) {
1915  MakeProjection();
1916  nNodes--;
1917  }
1918  else {
1919  mf::LogVerbatim("pma::Track3D") << "stop (3)";
1920  stop = true;
1921  break;
1922  }
1923 
1924  if (AddNode(detProp)) {
1925  MakeProjection();
1926  nNodes--;
1927  if (AddNode(detProp)) nNodes--;
1928  }
1929  }
1930  else if (nNodes > 4) {
1931  if (AddNode(detProp)) {
1932  MakeProjection();
1933  nNodes--;
1934  }
1935  else {
1936  mf::LogVerbatim("pma::Track3D") << "stop (2)";
1937  stop = true;
1938  break;
1939  }
1940 
1941  if (AddNode(detProp)) nNodes--;
1942  }
1943  else {
1944  if (AddNode(detProp)) { nNodes--; }
1945  else {
1946  mf::LogVerbatim("pma::Track3D") << "stop (1)";
1947  stop = true;
1948  break;
1949  }
1950  }
1951  break;
1952  }
1953 
1954  } while (!stop);
1955 
1956  MakeProjection();
1957  return GetObjFunction();
1958 }
1959 
1960 bool pma::Track3D::UpdateParamsInTree(bool skipFirst, size_t& depth)
1961 {
1962  constexpr size_t maxTreeDepth = 100; // really big tree...
1963 
1964  pma::Node3D* vtx = fNodes.front();
1965 
1966  if (skipFirst) {
1967  if (auto segThis = NextSegment(vtx)) vtx = static_cast<pma::Node3D*>(segThis->Next());
1968 
1969  if (++depth > maxTreeDepth) { mf::LogError("pma::Track3D") << "Tree depth above allowed max."; }
1970  }
1971 
1972  bool isOK = true;
1973 
1974  while (vtx) {
1975  auto segThis = NextSegment(vtx);
1976 
1977  for (size_t i = 0; i < vtx->NextCount(); i++) {
1978  auto seg = static_cast<pma::Segment3D*>(vtx->Next(i));
1979  if (seg != segThis) { isOK &= seg->Parent()->UpdateParamsInTree(true, depth); }
1980  }
1981 
1982  if (segThis)
1983  vtx = static_cast<pma::Node3D*>(segThis->Next());
1984  else
1985  break;
1986  }
1987 
1988  if (!UpdateParams()) {
1989  mf::LogError("pma::Track3D") << "Track empty.";
1990  isOK = false;
1991  }
1992 
1993  --depth;
1994 
1995  return isOK;
1996 }
1997 
1998 double pma::Track3D::TuneSinglePass(bool skipFirst)
1999 {
2000  pma::Node3D* vtx = fNodes.front();
2001 
2002  if (skipFirst) {
2003  if (auto segThis = NextSegment(vtx)) vtx = static_cast<pma::Node3D*>(segThis->Next());
2004  }
2005 
2006  double g = 0.0;
2007  while (vtx) {
2009  auto segThis = NextSegment(vtx);
2010 
2011  for (size_t i = 0; i < vtx->NextCount(); i++) {
2012  auto seg = static_cast<pma::Segment3D*>(vtx->Next(i));
2013  if (seg != segThis) g += seg->Parent()->TuneSinglePass(true);
2014  }
2015 
2016  if (segThis)
2017  vtx = static_cast<pma::Node3D*>(segThis->Next());
2018  else
2019  break;
2020  }
2021 
2022  return g + GetObjFunction();
2023 }
2024 
2026  double& dist,
2027  bool skipFirst)
2028 {
2029  pma::Node3D* vtx = fNodes.front();
2030 
2031  if (skipFirst) {
2032  if (auto segThis = NextSegment(vtx)) vtx = static_cast<pma::Node3D*>(segThis->Next());
2033  }
2034 
2035  pma::Track3D* result = this;
2036  dist = sqrt(Dist2(p3d_cm));
2037 
2038  pma::Track3D* candidate = nullptr;
2039  while (vtx) {
2040  auto segThis = NextSegment(vtx);
2041 
2042  double d;
2043  for (size_t i = 0; i < vtx->NextCount(); i++) {
2044  auto seg = static_cast<pma::Segment3D*>(vtx->Next(i));
2045  if (seg != segThis) {
2046  candidate = seg->Parent()->GetNearestTrkInTree(p3d_cm, d, true);
2047  if (d < dist) {
2048  dist = d;
2049  result = candidate;
2050  }
2051  }
2052  }
2053 
2054  if (segThis)
2055  vtx = static_cast<pma::Node3D*>(segThis->Next());
2056  else
2057  break;
2058  }
2059 
2060  return result;
2061 }
2062 
2063 pma::Track3D* pma::Track3D::GetNearestTrkInTree(const TVector2& p2d_cm,
2064  unsigned view,
2065  unsigned int tpc,
2066  unsigned int cryo,
2067  double& dist,
2068  bool skipFirst)
2069 {
2070  pma::Node3D* vtx = fNodes.front();
2071 
2072  if (skipFirst) {
2073  if (auto segThis = NextSegment(vtx)) vtx = static_cast<pma::Node3D*>(segThis->Next());
2074  }
2075 
2076  pma::Track3D* result = this;
2077  dist = Dist2(p2d_cm, view, tpc, cryo);
2078 
2079  pma::Track3D* candidate = nullptr;
2080  while (vtx) {
2081  auto segThis = NextSegment(vtx);
2082 
2083  double d;
2084  for (size_t i = 0; i < vtx->NextCount(); i++) {
2085  auto seg = static_cast<pma::Segment3D*>(vtx->Next(i));
2086  if (seg != segThis) {
2087  candidate = seg->Parent()->GetNearestTrkInTree(p2d_cm, view, tpc, cryo, d, true);
2088  if (d < dist) {
2089  dist = d;
2090  result = candidate;
2091  }
2092  }
2093  }
2094 
2095  if (segThis)
2096  vtx = static_cast<pma::Node3D*>(segThis->Next());
2097  else
2098  break;
2099  }
2100 
2101  dist = sqrt(dist);
2102  return result;
2103 }
2104 
2106 {
2107  bool skipFirst;
2108  if (trkRoot)
2109  skipFirst = true;
2110  else {
2111  trkRoot = this;
2112  skipFirst = false;
2113  }
2114 
2115  pma::Node3D* vtx = fNodes.front();
2116 
2117  if (skipFirst) {
2118  if (auto segThis = NextSegment(vtx)) vtx = static_cast<pma::Node3D*>(segThis->Next());
2119  }
2120 
2121  while (vtx) {
2122  auto segThis = NextSegment(vtx);
2123 
2124  for (size_t i = 0; i < vtx->NextCount(); i++) {
2125  auto seg = static_cast<pma::Segment3D*>(vtx->Next(i));
2126  if (seg != segThis) seg->Parent()->ReassignHitsInTree(trkRoot);
2127  }
2128 
2129  if (segThis)
2130  vtx = static_cast<pma::Node3D*>(segThis->Next());
2131  else
2132  break;
2133  }
2134 
2135  double d0, dmin;
2136  pma::Hit3D* hit = nullptr;
2137  pma::Track3D* nearestTrk = nullptr;
2138  size_t i = 0;
2139  while (HasTwoViews(2) && (i < size())) {
2140  hit = fHits[i];
2141  d0 = hit->GetDistToProj();
2142 
2143  nearestTrk = GetNearestTrkInTree(hit->Point2D(), hit->View2D(), hit->TPC(), hit->Cryo(), dmin);
2144  if ((nearestTrk != this) && (dmin < 0.5 * d0)) {
2145  nearestTrk->push_back(release_at(i));
2146  mf::LogVerbatim("pma::Track3D") << "*** hit moved to another track ***";
2147  }
2148  else
2149  i++;
2150  }
2151  if (!size()) { mf::LogError("pma::Track3D") << "ALL hits moved to other tracks."; }
2152 }
2153 
2155 {
2156  pma::Node3D* vtx = fNodes.front();
2157 
2158  if (skipFirst) {
2159  if (auto segThis = NextSegment(vtx)) vtx = static_cast<pma::Node3D*>(segThis->Next());
2160  }
2161 
2162  while (vtx) {
2163  auto segThis = NextSegment(vtx);
2164 
2165  for (size_t i = 0; i < vtx->NextCount(); i++) {
2166  auto seg = static_cast<pma::Segment3D*>(vtx->Next(i));
2167  if (seg != segThis) seg->Parent()->MakeProjectionInTree(true);
2168  }
2169 
2170  if (segThis)
2171  vtx = static_cast<pma::Node3D*>(segThis->Next());
2172  else
2173  break;
2174  }
2175 
2176  MakeProjection();
2177 }
2178 
2179 void pma::Track3D::SortHitsInTree(bool skipFirst)
2180 {
2181  pma::Node3D* vtx = fNodes.front();
2182 
2183  if (skipFirst) {
2184  if (auto segThis = NextSegment(vtx)) vtx = static_cast<pma::Node3D*>(segThis->Next());
2185  }
2186 
2187  while (vtx) {
2188  auto segThis = NextSegment(vtx);
2189 
2190  for (size_t i = 0; i < vtx->NextCount(); i++) {
2191  auto seg = static_cast<pma::Segment3D*>(vtx->Next(i));
2192  if (seg != segThis) seg->Parent()->SortHitsInTree(true);
2193  }
2194 
2195  if (segThis)
2196  vtx = static_cast<pma::Node3D*>(segThis->Next());
2197  else
2198  break;
2199  }
2200 
2201  SortHits();
2202 }
2203 
2204 double pma::Track3D::GetObjFnInTree(bool skipFirst)
2205 {
2206  pma::Node3D* vtx = fNodes.front();
2207 
2208  if (skipFirst) {
2209  if (auto segThis = NextSegment(vtx)) vtx = static_cast<pma::Node3D*>(segThis->Next());
2210  }
2211 
2212  double g = 0.0;
2213  while (vtx) {
2214  auto segThis = NextSegment(vtx);
2215 
2216  for (size_t i = 0; i < vtx->NextCount(); i++) {
2217  auto seg = static_cast<pma::Segment3D*>(vtx->Next(i));
2218  if (seg != segThis) g += seg->Parent()->GetObjFnInTree(true);
2219  }
2220 
2221  if (segThis)
2222  vtx = static_cast<pma::Node3D*>(segThis->Next());
2223  else
2224  break;
2225  }
2226 
2227  return g + GetObjFunction();
2228 }
2229 
2230 double pma::Track3D::TuneFullTree(double eps, double gmax)
2231 {
2232  if (size_t depth = 1; !UpdateParamsInTree(false, depth)) {
2233  mf::LogError("pma::Track3D") << "TuneFullTree failed.";
2234  return -2; // negetive to tag destroyed tree
2235  }
2236 
2237  double g0 = GetObjFnInTree(), g1 = 0.0;
2238  if (!std::isfinite(g0)) {
2239  mf::LogError("pma::Track3D") << "Infinifte value of g.";
2240  return -2; // negetive to tag destroyed tree
2241  }
2242  if (g0 > gmax) {
2243  mf::LogWarning("pma::Track3D") << "Too high value of g: " << g0;
2244  return -1; // negetive to tag bad tree
2245  }
2246  if (g0 == 0.0) return g0;
2247 
2248  mf::LogVerbatim("pma::Track3D") << "Tune tree, g = " << g0;
2249  unsigned int stepIter = 0;
2250  do {
2251  double gstep = 1.0;
2252  unsigned int iter = 0;
2253  while ((gstep > eps) && (iter < 60)) {
2254  g1 = g0;
2255  g0 = TuneSinglePass();
2256 
2258 
2259  if (size_t depth = 1; !UpdateParamsInTree(false, depth)) {
2260  g0 = -2;
2261  break;
2262  } // negetive to tag destroyed tree
2263 
2264  if (g0 == 0.0F) break;
2265 
2266  gstep = fabs(g0 - g1) / g0;
2267  iter++;
2268  }
2269 
2270  stepIter++;
2271 
2272  } while (stepIter < 5);
2273 
2275  SortHitsInTree();
2276 
2277  if (g0 >= 0) { mf::LogVerbatim("pma::Track3D") << " done, g = " << g0; }
2278  else {
2279  mf::LogError("pma::Track3D") << "TuneFullTree failed.";
2280  }
2281  return g0;
2282 }
2283 
2285  const detinfo::DetectorPropertiesData& detProp,
2286  double dx,
2287  bool skipFirst)
2288 {
2289  pma::Node3D* node = fNodes.front();
2290 
2291  if (skipFirst) {
2292  if (auto segThis = NextSegment(node)) node = static_cast<pma::Node3D*>(segThis->Next());
2293  }
2294 
2295  while (node) {
2296  node->ApplyDriftShift(dx);
2297 
2298  auto segThis = NextSegment(node);
2299  for (size_t i = 0; i < node->NextCount(); i++) {
2300  auto seg = static_cast<pma::Segment3D*>(node->Next(i));
2301  if (seg != segThis) seg->Parent()->ApplyDriftShiftInTree(clockData, detProp, dx, true);
2302  }
2303 
2304  if (segThis)
2305  node = static_cast<pma::Node3D*>(segThis->Next());
2306  else
2307  break;
2308  }
2309 
2310  for (auto h : fHits) {
2311  h->fPoint3D[0] += dx;
2312  }
2313 
2314  for (auto p : fAssignedPoints) {
2315  (*p)[0] += dx;
2316  }
2317 
2318  // For T0 we need to make sure we use the total shift, not just this current
2319  // one in case of multiple shifts
2320  double newdx = fNodes.front()->GetDriftShift();
2321 
2322  // Now convert this newdx into T0 and store in fT0
2323  SetT0FromDx(clockData, detProp, newdx);
2324 }
2325 
2327  detinfo::DetectorPropertiesData const& detProp,
2328  double dx)
2329 {
2330  auto const* geom = lar::providerFrom<geo::Geometry>();
2331  const geo::TPCGeo& tpcGeo = geom->TPC(geo::TPCID(fNodes.front()->Cryo(), fNodes.front()->TPC()));
2332 
2333  // GetXTicksCoefficient has a sign that we don't care about. We need to decide
2334  // the sign for ourselves based on the drift direction of the TPC
2335  double correctedSign = 0;
2336  if (tpcGeo.DetectDriftDirection() > 0) {
2337  if (dx > 0) { correctedSign = 1.0; }
2338  else {
2339  correctedSign = -1.0;
2340  }
2341  }
2342  else {
2343  if (dx > 0) { correctedSign = -1.0; }
2344  else {
2345  correctedSign = 1.0;
2346  }
2347  }
2348 
2349  // The magnitude of x in ticks is fine
2350  double dxInTicks = fabs(dx / detProp.GetXTicksCoefficient());
2351  // Now correct the sign
2352  dxInTicks = dxInTicks * correctedSign;
2353  // At this stage, we have xInTicks relative to the trigger time
2354  double dxInTime = dxInTicks * clockData.TPCClock().TickPeriod();
2355  // Reconstructed times are relative to the trigger (t=0), so this is our T0
2356  fT0 = dxInTime;
2357 
2358  mf::LogDebug("pma::Track3D") << dx << ", " << dxInTicks << ", " << correctedSign << ", " << fT0
2359  << ", " << tpcGeo.DetectDriftDirection()
2360  << " :: " << clockData.TriggerTime() << ", "
2361  << clockData.TriggerOffsetTPC() << std::endl;
2362 
2363  // Mark this track as having a measured T0
2364  fT0Flag = true;
2365 }
2366 
2368 {
2369  for (size_t i = 0; i < fSegments.size(); i++)
2370  delete fSegments[i];
2371  fSegments.clear();
2372 }
2373 
2375 {
2376  DeleteSegments();
2377 
2378  fSegments.reserve(fNodes.size() - 1);
2379  for (size_t i = 1; i < fNodes.size(); i++) {
2380  fSegments.push_back(new pma::Segment3D(this, fNodes[i - 1], fNodes[i]));
2381  }
2382 }
2383 
2385 {
2386  unsigned int nhits = 0;
2387  while (!nhits && (fNodes.size() > 2) && !fNodes.front()->IsBranching()) {
2388  pma::Node3D* vtx = fNodes.front();
2389  nhits = vtx->NHits();
2390 
2391  pma::Segment3D* seg = NextSegment(vtx);
2392  nhits += seg->NHits();
2393 
2394  if (!nhits) {
2395  if (vtx->NextCount() < 2) delete vtx;
2396  fNodes.erase(fNodes.begin());
2397 
2398  delete seg;
2399  fSegments.erase(fSegments.begin());
2400 
2401  MakeProjection();
2402  }
2403  }
2404 
2405  nhits = 0;
2406  while (!nhits && (fNodes.size() > 2) && !fNodes.back()->IsBranching()) {
2407  pma::Node3D* vtx = fNodes.back();
2408  nhits = vtx->NHits();
2409 
2410  pma::Segment3D* seg = PrevSegment(vtx);
2411  nhits += seg->NHits();
2412 
2413  if (!nhits) {
2414  if (vtx->NextCount() < 1) delete fNodes.back();
2415  fNodes.pop_back();
2416 
2417  delete seg;
2418  fSegments.pop_back();
2419 
2420  MakeProjection();
2421  }
2422  }
2423 }
2424 
2426 {
2427  pma::Element3D* el;
2428  pma::Node3D* vtx;
2429 
2430  if (!(fNodes.front()->Prev())) {
2431  el = GetNearestElement(front()->Point3D());
2432  vtx = dynamic_cast<pma::Node3D*>(el);
2433  if (vtx) {
2434  if (vtx == fNodes.front())
2435  fNodes.front()->SetPoint3D(front()->Point3D());
2436  else {
2437  mf::LogWarning("pma::Track3D") << "First hit is projected to inner node.";
2438  return false;
2439  }
2440  }
2441  else {
2442  pma::Segment3D* seg = dynamic_cast<pma::Segment3D*>(el);
2443  if (seg) {
2444  if (seg->Prev() == fNodes.front()) {
2445  double l0 = seg->Length();
2446  fNodes.front()->SetPoint3D(front()->Point3D());
2447  if ((seg->Length() < 0.2 * l0) && (fNodes.size() > 2)) {
2448  pma::Node3D* toRemove = fNodes[1];
2449  if (toRemove->NextCount() == 1) {
2450  mf::LogWarning("pma::Track3D")
2451  << "ShiftEndsToHits(): Short start segment, node removed.";
2452  fNodes.erase(fNodes.begin() + 1);
2453 
2454  RebuildSegments();
2455  MakeProjection();
2456 
2457  delete toRemove;
2458  }
2459  else {
2460  mf::LogWarning("pma::Track3D") << "Branching node, not removed.";
2461  return false;
2462  }
2463  }
2464  }
2465  else {
2466  mf::LogWarning("pma::Track3D") << "First hit is projected to inner segment.";
2467  return false;
2468  }
2469  }
2470  }
2471  }
2472 
2473  if (!(fNodes.back()->NextCount())) {
2474  el = GetNearestElement(back()->Point3D());
2475  vtx = dynamic_cast<pma::Node3D*>(el);
2476  if (vtx) {
2477  if (vtx == fNodes.back())
2478  fNodes.back()->SetPoint3D(back()->Point3D());
2479  else {
2480  mf::LogWarning("pma::Track3D") << "First hit is projected to inner node.";
2481  return false;
2482  }
2483  }
2484  else {
2485  pma::Segment3D* seg = dynamic_cast<pma::Segment3D*>(el);
2486  if (seg) {
2487  if (seg->Next() == fNodes.back()) {
2488  double l0 = seg->Length();
2489  fNodes.back()->SetPoint3D(back()->Point3D());
2490  if ((seg->Length() < 0.2 * l0) && (fNodes.size() > 2)) {
2491  size_t idx = fNodes.size() - 2;
2492  pma::Node3D* toRemove = fNodes[idx];
2493  if (toRemove->NextCount() == 1) {
2494  mf::LogWarning("pma::Track3D")
2495  << "ShiftEndsToHits(): Short end segment, node removed.";
2496  fNodes.erase(fNodes.begin() + idx);
2497 
2498  RebuildSegments();
2499  MakeProjection();
2500 
2501  delete toRemove;
2502  }
2503  else {
2504  mf::LogWarning("pma::Track3D") << "Branching node, not removed.";
2505  return false;
2506  }
2507  }
2508  }
2509  else {
2510  mf::LogWarning("pma::Track3D") << "First hit is projected to inner segment.";
2511  return false;
2512  }
2513  }
2514  }
2515  }
2516 
2517  return true;
2518 }
2519 
2520 double pma::Track3D::Dist2(const TVector2& p2d,
2521  unsigned int view,
2522  unsigned int tpc,
2523  unsigned int cryo) const
2524 {
2525  double dist, min_dist = 1.0e12;
2526 
2527  int t = (int)tpc, c = (int)cryo;
2528  auto n0 = fNodes.front();
2529  if ((n0->TPC() == t) && (n0->Cryo() == c)) {
2530  dist = n0->GetDistance2To(p2d, view);
2531  if (dist < min_dist) min_dist = dist;
2532  }
2533  auto n1 = fNodes.back();
2534  if ((n1->TPC() == t) && (n1->Cryo() == c)) {
2535  dist = n1->GetDistance2To(p2d, view);
2536  if (dist < min_dist) min_dist = dist;
2537  }
2538 
2539  for (auto s : fSegments)
2540  if ((s->TPC() == t) && (s->Cryo() == c)) {
2541  dist = s->GetDistance2To(p2d, view);
2542  if (dist < min_dist) min_dist = dist;
2543  }
2544  return min_dist;
2545 }
2546 
2547 double pma::Track3D::Dist2(const TVector3& p3d) const
2548 {
2549  using namespace ranges;
2550  auto to_distance2 = [&p3d](auto seg) { return seg->GetDistance2To(p3d); };
2551  return min(fSegments | views::transform(to_distance2));
2552 }
2553 
2555  unsigned int view,
2556  int tpc,
2557  bool skipFrontVtx,
2558  bool skipBackVtx) const
2559 {
2560  if (fSegments.front()->TPC() < 0) skipFrontVtx = false;
2561  if (fSegments.back()->TPC() < 0) skipBackVtx = false;
2562 
2563  if (skipFrontVtx && skipBackVtx && (fSegments.size() == 1))
2564  return fSegments.front(); // no need for searching...
2565 
2566  size_t v0 = 0, v1 = fNodes.size();
2567  if (skipFrontVtx) v0 = 1;
2568  if (skipBackVtx) --v1;
2569 
2570  pma::Element3D* pe_min = nullptr;
2571  auto min_dist = std::numeric_limits<double>::max();
2572  for (size_t i = v0; i < v1; i++)
2573  if (fNodes[i]->TPC() == tpc) {
2574  double dist = fNodes[i]->GetDistance2To(p2d, view);
2575  if (dist < min_dist) {
2576  min_dist = dist;
2577  pe_min = fNodes[i];
2578  }
2579  }
2580  for (auto segment : fSegments)
2581  if (segment->TPC() == tpc) {
2582  if (segment->TPC() < 0) continue; // segment between TPC's
2583 
2584  double const dist = segment->GetDistance2To(p2d, view);
2585  if (dist < min_dist) {
2586  min_dist = dist;
2587  pe_min = segment;
2588  }
2589  }
2590  if (!pe_min) throw cet::exception("pma::Track3D") << "Nearest element not found." << std::endl;
2591  return pe_min;
2592 }
2593 
2595 {
2596  pma::Element3D* pe_min = fNodes.front();
2597  double dist, min_dist = pe_min->GetDistance2To(p3d);
2598  for (size_t i = 1; i < fNodes.size(); i++) {
2599  dist = fNodes[i]->GetDistance2To(p3d);
2600  if (dist < min_dist) {
2601  min_dist = dist;
2602  pe_min = fNodes[i];
2603  }
2604  }
2605  for (size_t i = 0; i < fSegments.size(); i++) {
2606  dist = fSegments[i]->GetDistance2To(p3d);
2607  if (dist < min_dist) {
2608  min_dist = dist;
2609  pe_min = fSegments[i];
2610  }
2611  }
2612  return pe_min;
2613 }
2614 
2617  TVector3& p3d,
2618  double& dist2) const
2619 {
2620  TVector2 p2d = pma::WireDriftToCm(detProp,
2621  hit->WireID().Wire,
2622  hit->PeakTime(),
2623  hit->WireID().Plane,
2624  hit->WireID().TPC,
2625  hit->WireID().Cryostat);
2626 
2627  pma::Segment3D* seg = nullptr;
2628  double d2, min_d2 = 1.0e100;
2629  int tpc = (int)hit->WireID().TPC;
2630  int view = hit->WireID().Plane;
2631  for (size_t i = 0; i < fSegments.size(); i++) {
2632  if (fSegments[i]->TPC() != tpc) continue;
2633 
2634  d2 = fSegments[i]->GetDistance2To(p2d, view);
2635  if (d2 < min_d2) {
2636  min_d2 = d2;
2637  seg = fSegments[i];
2638  }
2639  }
2640  if (seg) {
2641  p3d = seg->GetUnconstrainedProj3D(p2d, view);
2642  dist2 = min_d2;
2643 
2644  pma::Node3D* prev = static_cast<pma::Node3D*>(seg->Prev());
2645  return prev->SameTPC(p3d); // 3D can be beyond the segment endpoints => in other TPC
2646  }
2647 
2648  return false;
2649 }
2650 
2652 {
2653  std::vector<pma::Hit3D*> hits_tmp;
2654  hits_tmp.reserve(size());
2655 
2656  pma::Node3D* vtx = fNodes.front();
2657  pma::Segment3D* seg = NextSegment(vtx);
2658  while (vtx) {
2659  vtx->SortHits();
2660  for (size_t i = 0; i < vtx->NHits(); i++) {
2661  pma::Hit3D* h3d = &(vtx->Hit(i));
2662  if (h3d->fParent == this) hits_tmp.push_back(h3d);
2663  }
2664 
2665  if (seg) {
2666  seg->SortHits();
2667  for (size_t i = 0; i < seg->NHits(); i++) {
2668  pma::Hit3D* h3d = &(seg->Hit(i));
2669  if (h3d->fParent == this) hits_tmp.push_back(h3d);
2670  }
2671 
2672  vtx = static_cast<pma::Node3D*>(seg->Next());
2673  seg = NextSegment(vtx);
2674  }
2675  else
2676  break;
2677  }
2678 
2679  if (size() == hits_tmp.size()) {
2680  for (size_t i = 0; i < size(); i++) {
2681  fHits[i] = hits_tmp[i];
2682  }
2683  }
2684  else
2685  mf::LogError("pma::Track3D") << "Hit sorting problem.";
2686 }
2687 
2689 {
2690  SortHits();
2691 
2692  unsigned int nDisabled = 0;
2693 
2694  std::array<int, 4> hasHits{{}};
2695 
2696  pma::Hit3D* nextHit = nullptr;
2697  int hitIndex = -1;
2698 
2699  bool rebuild = false, stop = false;
2700  int nViews = 0;
2701 
2702  do {
2703  pma::Node3D* vtx = fNodes.front();
2704  pma::Segment3D* seg = NextSegment(vtx);
2705  if (!seg) break;
2706 
2707  if (vtx->NPoints() + seg->NPoints() > 0) hasHits[3] = 1;
2708 
2709  for (size_t i = 0; i < vtx->NHits(); i++) {
2710  hitIndex = index_of(&(vtx->Hit(i)));
2711  if ((hitIndex >= 0) && (hitIndex + 1 < (int)size()))
2712  nextHit = fHits[hitIndex + 1];
2713  else
2714  nextHit = 0;
2715 
2716  if (vtx->Hit(i).IsEnabled()) hasHits[vtx->Hit(i).View2D()] = 1;
2717  if (nextHit && nextHit->IsEnabled()) hasHits[nextHit->View2D()] = 1;
2718  nViews = hasHits[0] + hasHits[1] + hasHits[2] + hasHits[3];
2719  if (nViews < 2) {
2720  if (vtx->Hit(i).IsEnabled()) {
2721  vtx->Hit(i).SetEnabled(false);
2722  nDisabled++;
2723  }
2724  }
2725  }
2726  for (size_t i = 0; i < seg->NHits(); i++) {
2727  hitIndex = index_of(&(seg->Hit(i)));
2728  if ((hitIndex >= 0) && (hitIndex + 1 < (int)size()))
2729  nextHit = fHits[hitIndex + 1];
2730  else
2731  nextHit = 0;
2732 
2733  if (seg->Hit(i).IsEnabled()) hasHits[seg->Hit(i).View2D()] = 1;
2734  if (nextHit && nextHit->IsEnabled()) hasHits[nextHit->View2D()] = 1;
2735  nViews = hasHits[0] + hasHits[1] + hasHits[2] + hasHits[3];
2736  if (nViews < 2) {
2737  if (seg->Hit(i).IsEnabled()) {
2738  seg->Hit(i).SetEnabled(false);
2739  nDisabled++;
2740  }
2741  }
2742  }
2743 
2744  if (fNodes.size() < 3) break;
2745 
2746  nViews = hasHits[1] + hasHits[2] + hasHits[3];
2747  if (hasHits[0] || (nViews > 1))
2748  stop = true;
2749  else if (!fNodes.front()->IsBranching()) {
2750  pma::Node3D* vtx_front = fNodes.front();
2751  fNodes.erase(fNodes.begin());
2752  delete vtx_front;
2753  rebuild = true;
2754  }
2755 
2756  } while (!stop);
2757 
2758  stop = false;
2759  nViews = 0;
2760  hasHits.fill(0);
2761 
2762  do {
2763  pma::Node3D* vtx = fNodes.back();
2764  pma::Segment3D* seg = PrevSegment(vtx);
2765  if (!seg) break;
2766 
2767  if (vtx->NPoints() || seg->NPoints()) hasHits[3] = 1;
2768 
2769  for (int i = vtx->NHits() - 1; i >= 0; i--) {
2770  hitIndex = index_of(&(vtx->Hit(i)));
2771  if ((hitIndex >= 0) && (hitIndex - 1 >= 0))
2772  nextHit = fHits[hitIndex - 1];
2773  else
2774  nextHit = 0;
2775 
2776  if (vtx->Hit(i).IsEnabled()) hasHits[vtx->Hit(i).View2D()] = 1;
2777  if (nextHit && nextHit->IsEnabled()) hasHits[nextHit->View2D()] = 1;
2778  nViews = hasHits[0] + hasHits[1] + hasHits[2] + hasHits[3];
2779  if (nViews < 2) {
2780  if (vtx->Hit(i).IsEnabled()) {
2781  vtx->Hit(i).SetEnabled(false);
2782  nDisabled++;
2783  }
2784  }
2785  }
2786  for (int i = seg->NHits() - 1; i >= 0; i--) {
2787  hitIndex = index_of(&(seg->Hit(i)));
2788  if ((hitIndex >= 0) && (hitIndex - 1 >= 0))
2789  nextHit = fHits[hitIndex - 1];
2790  else
2791  nextHit = 0;
2792 
2793  if (seg->Hit(i).IsEnabled()) hasHits[seg->Hit(i).View2D()] = 1;
2794  if (nextHit && nextHit->IsEnabled()) hasHits[nextHit->View2D()] = 1;
2795  nViews = hasHits[0] + hasHits[1] + hasHits[2] + hasHits[3];
2796  if (nViews < 2) {
2797  if (seg->Hit(i).IsEnabled()) {
2798  seg->Hit(i).SetEnabled(false);
2799  nDisabled++;
2800  }
2801  }
2802  }
2803 
2804  if (fNodes.size() < 3) break;
2805 
2806  nViews = hasHits[1] + hasHits[2] + hasHits[3];
2807  if (hasHits[0] || (nViews > 1))
2808  stop = true;
2809  else if (!fNodes.back()->IsBranching()) {
2810  pma::Node3D* vtx_back = fNodes.back();
2811  fNodes.pop_back();
2812  delete vtx_back;
2813  rebuild = true;
2814  }
2815 
2816  } while (!stop);
2817 
2818  if (rebuild) {
2819  RebuildSegments();
2820  MakeProjection();
2821  }
2822 
2823  return nDisabled;
2824 }
2825 
2826 bool pma::Track3D::SelectHits(float fraction)
2827 {
2828  if (fraction < 0.0F) fraction = 0.0F;
2829  if (fraction > 1.0F) fraction = 1.0F;
2830  if (fraction < 1.0F) std::sort(fHits.begin(), fHits.end(), pma::bTrajectory3DDistLess());
2831 
2832  size_t nHitsColl = (size_t)(fraction * NHits(geo::kZ));
2833  size_t nHitsInd2 = (size_t)(fraction * NHits(geo::kV));
2834  size_t nHitsInd1 = (size_t)(fraction * NHits(geo::kU));
2835  size_t coll = 0, ind2 = 0, ind1 = 0;
2836 
2837  bool b, changed = false;
2838  for (auto h : fHits) {
2839  b = h->IsEnabled();
2840  if (fraction < 1.0F) {
2841  h->SetEnabled(false);
2842  switch (h->View2D()) {
2843  case geo::kZ:
2844  if (coll++ < nHitsColl) h->SetEnabled(true);
2845  break;
2846  case geo::kV:
2847  if (ind2++ < nHitsInd2) h->SetEnabled(true);
2848  break;
2849  case geo::kU:
2850  if (ind1++ < nHitsInd1) h->SetEnabled(true);
2851  break;
2852  }
2853  }
2854  else
2855  h->SetEnabled(true);
2856 
2857  changed |= (b != h->IsEnabled());
2858  }
2859 
2860  if (fraction < 1.0F) {
2863  }
2864  return changed;
2865 }
2866 
2867 bool pma::Track3D::SelectRndHits(size_t segmax, size_t vtxmax)
2868 {
2869  bool changed = false;
2870  for (auto n : fNodes)
2871  changed |= n->SelectRndHits(vtxmax);
2872  for (auto s : fSegments)
2873  changed |= s->SelectRndHits(segmax);
2874  return changed;
2875 }
2876 
2878 {
2879  bool changed = false;
2880  for (auto h : fHits) {
2881  changed |= !(h->IsEnabled());
2882  h->SetEnabled(true);
2883  }
2884  return changed;
2885 }
2886 
2888 {
2889  for (auto n : fNodes)
2890  n->ClearAssigned(this);
2891  for (auto s : fSegments)
2892  s->ClearAssigned(this);
2893 
2894  pma::Element3D* pe = nullptr;
2895 
2896  bool skipFrontVtx = false, skipBackVtx = false;
2897 
2898  // skip outermost vertices if not branching
2899  if (!(fNodes.front()->IsFrozen()) && !(fNodes.front()->Prev()) &&
2900  (fNodes.front()->NextCount() == 1)) {
2901  skipFrontVtx = true;
2902  }
2903  if (!(fNodes.front()->IsFrozen()) && (fNodes.back()->NextCount() == 0)) { skipBackVtx = true; }
2904 
2905  for (auto h : fHits) // assign hits to nodes/segments
2906  {
2907  pe = GetNearestElement(h->Point2D(), h->View2D(), h->TPC(), skipFrontVtx, skipBackVtx);
2908  pe->AddHit(h);
2909  }
2910 
2911  for (auto p : fAssignedPoints) // assign ref points to nodes/segments
2912  {
2913  pe = GetNearestElement(*p);
2914  pe->AddPoint(p);
2915  }
2916 
2917  for (auto n : fNodes)
2918  n->UpdateHitParams();
2919  for (auto s : fSegments)
2920  s->UpdateHitParams();
2921 }
2922 
2924 {
2925  std::vector<std::pair<pma::Hit3D*, pma::Element3D*>> assignments;
2926  assignments.reserve(fHits.size());
2927 
2928  for (auto hi : fHits) {
2929  pma::Element3D* pe = nullptr;
2930 
2931  for (auto s : fSegments) {
2932  for (size_t j = 0; j < s->NHits(); ++j)
2933  if (hi == s->Hits()[j]) // look at next/prev vtx,seg,vtx
2934  {
2935  pe = s;
2936  double min_d2 = s->GetDistance2To(hi->Point2D(), hi->View2D());
2937  int const tpc = hi->TPC();
2938 
2939  pma::Node3D* nnext = static_cast<pma::Node3D*>(s->Next());
2940  if (nnext->TPC() == tpc) {
2941  double const d2 = nnext->GetDistance2To(hi->Point2D(), hi->View2D());
2942  if (d2 < min_d2) {
2943  min_d2 = d2;
2944  pe = nnext;
2945  }
2946 
2947  pma::Segment3D* snext = NextSegment(nnext);
2948  if (snext && (snext->TPC() == tpc)) {
2949  double const d2 = snext->GetDistance2To(hi->Point2D(), hi->View2D());
2950  if (d2 < min_d2) {
2951  min_d2 = d2;
2952  pe = snext;
2953  }
2954 
2955  nnext = static_cast<pma::Node3D*>(snext->Next());
2956  if (nnext->TPC() == tpc) {
2957  double const d2 = nnext->GetDistance2To(hi->Point2D(), hi->View2D());
2958  if (d2 < min_d2) {
2959  min_d2 = d2;
2960  pe = nnext;
2961  }
2962  }
2963  }
2964  }
2965 
2966  pma::Node3D* nprev = static_cast<pma::Node3D*>(s->Prev());
2967  if (nprev->TPC() == tpc) {
2968  double const d2 = nprev->GetDistance2To(hi->Point2D(), hi->View2D());
2969  if (d2 < min_d2) {
2970  min_d2 = d2;
2971  pe = nprev;
2972  }
2973 
2974  pma::Segment3D* sprev = PrevSegment(nprev);
2975  if (sprev && (sprev->TPC() == tpc)) {
2976  double const d2 = sprev->GetDistance2To(hi->Point2D(), hi->View2D());
2977  if (d2 < min_d2) {
2978  min_d2 = d2;
2979  pe = sprev;
2980  }
2981 
2982  nprev = static_cast<pma::Node3D*>(sprev->Prev());
2983  if (nprev->TPC() == tpc) {
2984  double const d2 = nprev->GetDistance2To(hi->Point2D(), hi->View2D());
2985  if (d2 < min_d2) {
2986  min_d2 = d2;
2987  pe = nprev;
2988  }
2989  }
2990  }
2991  }
2992 
2993  s->RemoveHitAt(j);
2994  break;
2995  }
2996  if (pe) break;
2997  }
2998 
2999  if (!pe)
3000  for (auto n : fNodes) {
3001  for (size_t j = 0; j < n->NHits(); ++j)
3002  if (hi == n->Hits()[j]) // look at next/prev seg,vtx,seg
3003  {
3004  pe = n;
3005  double d2, min_d2 = n->GetDistance2To(hi->Point2D(), hi->View2D());
3006  int tpc = hi->TPC();
3007 
3008  pma::Segment3D* snext = NextSegment(n);
3009  if (snext && (snext->TPC() == tpc)) {
3010  d2 = snext->GetDistance2To(hi->Point2D(), hi->View2D());
3011  if (d2 < min_d2) {
3012  min_d2 = d2;
3013  pe = snext;
3014  }
3015 
3016  pma::Node3D* nnext = static_cast<pma::Node3D*>(snext->Next());
3017  if (nnext->TPC() == tpc) {
3018  d2 = nnext->GetDistance2To(hi->Point2D(), hi->View2D());
3019  if (d2 < min_d2) {
3020  min_d2 = d2;
3021  pe = nnext;
3022  }
3023 
3024  snext = NextSegment(nnext);
3025  if (snext && (snext->TPC() == tpc)) {
3026  d2 = snext->GetDistance2To(hi->Point2D(), hi->View2D());
3027  if (d2 < min_d2) {
3028  min_d2 = d2;
3029  pe = snext;
3030  }
3031  }
3032  }
3033  }
3034 
3035  pma::Segment3D* sprev = PrevSegment(n);
3036  if (sprev && (sprev->TPC() == tpc)) {
3037  d2 = sprev->GetDistance2To(hi->Point2D(), hi->View2D());
3038  if (d2 < min_d2) {
3039  min_d2 = d2;
3040  pe = sprev;
3041  }
3042 
3043  pma::Node3D* nprev = static_cast<pma::Node3D*>(sprev->Prev());
3044  if (nprev->TPC() == tpc) {
3045  d2 = nprev->GetDistance2To(hi->Point2D(), hi->View2D());
3046  if (d2 < min_d2) {
3047  min_d2 = d2;
3048  pe = nprev;
3049  }
3050 
3051  sprev = PrevSegment(nprev);
3052  if (sprev && (sprev->TPC() == tpc)) {
3053  d2 = sprev->GetDistance2To(hi->Point2D(), hi->View2D());
3054  if (d2 < min_d2) {
3055  min_d2 = d2;
3056  pe = sprev;
3057  }
3058  }
3059  }
3060  }
3061 
3062  n->RemoveHitAt(j);
3063  break;
3064  }
3065  if (pe) break;
3066  }
3067 
3068  if (pe)
3069  assignments.emplace_back(hi, pe);
3070  else
3071  mf::LogWarning("pma::Track3D") << "Hit was not assigned to any element.";
3072  }
3073 
3074  for (auto const& a : assignments)
3075  a.second->AddHit(a.first);
3076 
3077  for (auto n : fNodes)
3078  n->UpdateHitParams();
3079  for (auto s : fSegments)
3080  s->UpdateHitParams();
3081 }
3082 
3084 {
3085  for (auto n : fNodes)
3086  n->UpdateProjection();
3087  for (auto s : fSegments)
3088  s->UpdateProjection();
3089 }
3090 
3092 {
3093  double sum = 0.0;
3094  unsigned int count = 0;
3095 
3096  for (auto n : fNodes) {
3097  sum += n->SumDist2();
3098  count += n->NEnabledHits();
3099  }
3100 
3101  for (auto s : fSegments) {
3102  sum += s->SumDist2();
3103  count += s->NEnabledHits();
3104  }
3105 
3106  if (count) { return sum / count; }
3107  else {
3108  mf::LogError("pma::Track3D") << "0 enabled hits in AverageDist2 calculation.";
3109  return 0;
3110  }
3111 }
3112 
3114 {
3115  size_t n = size();
3116  if (n == 0) {
3117  fPenaltyValue = 1;
3118  fSegStopValue = 1;
3119  return false;
3120  }
3121 
3122  float nCubeRoot = pow((double)n, 1.0 / 3.0);
3123  float avgDist2Root = sqrt(AverageDist2());
3124  if (avgDist2Root > 0) {
3125  fPenaltyValue = fPenaltyFactor * pow((double)fSegments.size(), 1.8) * avgDist2Root /
3126  (fHitsRadius * nCubeRoot);
3127 
3128  fSegStopValue = (int)(fSegStopFactor * nCubeRoot * fHitsRadius / avgDist2Root);
3130  return true;
3131  }
3132  else {
3133  fPenaltyValue = 1;
3134  fSegStopValue = 1;
3135  return false;
3136  }
3137 }
3138 
3139 bool pma::Track3D::SwapVertices(size_t v0, size_t v1)
3140 {
3141  if (v0 == v1) return false;
3142 
3143  if (v0 > v1) {
3144  size_t vx = v0;
3145  v0 = v1;
3146  v1 = vx;
3147  }
3148 
3149  pma::Node3D* vtmp;
3150  if (v1 - v0 == 1) {
3151  pma::Segment3D* midSeg = NextSegment(fNodes[v0]);
3152  pma::Segment3D* prevSeg = PrevSegment(fNodes[v0]);
3153  pma::Segment3D* nextSeg = NextSegment(fNodes[v1]);
3154 
3155  fNodes[v1]->RemoveNext(nextSeg);
3156  midSeg->Disconnect();
3157 
3158  vtmp = fNodes[v0];
3159  fNodes[v0] = fNodes[v1];
3160  fNodes[v1] = vtmp;
3161 
3162  if (prevSeg) prevSeg->AddNext(fNodes[v0]);
3163  fNodes[v0]->AddNext(midSeg);
3164  midSeg->AddNext(fNodes[v1]);
3165  if (nextSeg) fNodes[v1]->AddNext(nextSeg);
3166 
3167  return false;
3168  }
3169  else {
3170  vtmp = fNodes[v0];
3171  fNodes[v0] = fNodes[v1];
3172  fNodes[v1] = vtmp;
3173  return true;
3174  }
3175 }
3176 
3178 {
3179  unsigned int v1, v2;
3180  switch (endCode) {
3181  case pma::Track3D::kBegin:
3182  if (fSegments.front()->IsFrozen()) return false;
3183  if (fNodes.front()->NextCount() > 1) return false;
3184  v1 = 0;
3185  v2 = 1;
3186  break;
3187  case pma::Track3D::kEnd:
3188  if (fSegments.back()->IsFrozen()) return false;
3189  if (fNodes.back()->NextCount() > 1) return false;
3190  v1 = fNodes.size() - 1;
3191  v2 = fNodes.size() - 2;
3192  break;
3193  default: return false;
3194  }
3195  if (fNodes[v1]->TPC() != fNodes[v2]->TPC()) return false;
3196 
3197  double g1, g0 = GetObjFunction();
3198 
3199  if (SwapVertices(v1, v2)) RebuildSegments();
3200  MakeProjection();
3201  g1 = GetObjFunction();
3202 
3203  if (g1 >= g0) {
3204  if (SwapVertices(v1, v2)) RebuildSegments();
3205  MakeProjection();
3206  return false;
3207  }
3208  else
3209  return true;
3210 }
3211 
3213 {
3214  std::vector<pma::Hit3D*> hitsColl, hitsInd1, hitsInd2;
3215  for (auto hit : fHits) {
3216  switch (hit->View2D()) {
3217  case geo::kZ: hitsColl.push_back(hit); break;
3218  case geo::kV: hitsInd2.push_back(hit); break;
3219  case geo::kU: hitsInd1.push_back(hit); break;
3220  }
3221  }
3222  fHitsRadius = std::max({pma::GetHitsRadius2D(hitsColl, true),
3223  pma::GetHitsRadius2D(hitsInd2, true),
3224  pma::GetHitsRadius2D(hitsInd1, true)});
3225 }
Float_t x
Definition: compare.C:6
void MakeProjection()
bool SelectHits(float fraction=1.0F)
void ApplyDriftShift(double dx)
Definition: PmaNode3D.h:116
code to link reconstructed objects back to the MC truth information
void AddHits(detinfo::DetectorPropertiesData const &detProp, const std::vector< art::Ptr< recob::Hit >> &hits)
Definition: PmaTrack3D.cxx:404
void MakeFastProjection()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
TVector3 const & Point3D() const
Definition: PmaNode3D.h:44
void AutoFlip(pma::Track3D::EDirection dir, double thr=0.0, unsigned int n=0)
Definition: PmaTrack3D.cxx:662
bool HasTPC(int tpc) const
Definition: PmaTrack3D.h:124
virtual bool AddNext(pma::SortedObjectBase *nextElement)
double minY
Definition: plot_hist.C:9
Utilities related to art service access.
double GetMse(unsigned int view=geo::kUnknown) const
MSE of hits weighted with hit amplidudes and wire plane coefficients.
void RemoveHitAt(size_t index)
Definition: PmaElement3D.h:66
void SortHitsInTree(bool skipFirst=false)
bool AttachTo(pma::Node3D *vStart, bool noFlip=false)
double GetHitsRadius2D(const std::vector< pma::Hit3D * > &hits, bool exact=false)
Definition: Utilities.cxx:94
double Dist2(const TVector2 &p2d, unsigned int view, unsigned int tpc, unsigned int cryo) const
Implementation of the Projection Matching Algorithm.
TVector2 const & Point2D() const noexcept
Definition: PmaHit3D.h:55
bool IsAttachedTo(pma::Track3D const *trk) const
bool SelectAllHits()
pma::Track3D * fParent
Definition: PmaHit3D.h:109
double Dist2(const TVector2 &v1, const TVector2 &v2)
Definition: Utilities.cxx:39
void ClearNodes()
Definition: PmaTrack3D.cxx:112
int PrevHit(int index, unsigned int view=geo::kZ, bool inclDisabled=false) const
Definition: PmaTrack3D.cxx:911
double GetXTicksCoefficient(int t, int c) const
void ApplyDriftShiftInTree(const detinfo::DetectorClocksData &clockData, detinfo::DetectorPropertiesData const &detProp, double dx, bool skipFirst=false)
Planes which measure V.
Definition: geo_types.h:136
Unknown view.
Definition: geo_types.h:142
void ClearAssigned(pma::Track3D *trk=0) override
Definition: PmaNode3D.cxx:825
void AddPoint(TVector3 *p)
Definition: PmaElement3D.h:82
virtual int RemoveNext(pma::SortedObjectBase *nextElement)
Float_t y
Definition: compare.C:6
pma::Hit3D const * front() const
Definition: PmaTrack3D.h:87
bool IsEnabled() const noexcept
Definition: PmaHit3D.h:86
Implementation of the Projection Matching Algorithm.
unsigned int TestHits(detinfo::DetectorPropertiesData const &detProp, const std::vector< art::Ptr< recob::Hit >> &hits, double dist=0.4) const
Count close 2D hits.
Definition: PmaTrack3D.cxx:845
Double_t z
Definition: plot.C:276
Float_t Y
Definition: plot.C:37
unsigned int Cryo() const noexcept
Definition: PmaHit3D.h:58
double MinX() const
Returns the world x coordinate of the start of the box.
Definition: BoxBoundedGeo.h:90
The data type to uniquely identify a Plane.
Definition: geo_types.h:463
Geometry information for a single TPC.
Definition: TPCGeo.h:36
void ReassignHitsInTree(pma::Track3D *plRoot=nullptr)
int index_of(const pma::Hit3D *hit) const
Definition: PmaTrack3D.cxx:341
void RebuildSegments()
double GetDistance2To(const TVector3 &p3d) const override
Distance [cm] from the 3D point to the point 3D.
Definition: PmaNode3D.cxx:172
bool AttachBackToSameTPC(pma::Node3D *vStart)
::fhicl::TupleAs< Point(::geo::Length_t,::geo::Length_t,::geo::Length_t)> Point3D
Atom object for reading a 3D point or vector (centimeters).
bool GetBranches(std::vector< pma::Track3D const * > &branches, bool skipFirst=false) const
virtual unsigned int NextCount(void) const
Definition: SortedObjects.h:84
bool AttachToOtherTPC(pma::Node3D *vStart)
bool CheckEndSegment(pma::Track3D::ETrackEnd endCode)
constexpr auto abs(T v)
Returns the absolute value of the argument.
bool InitFromHits(detinfo::DetectorPropertiesData const &detProp, int tpc, int cryo, float initEndSegW=0.05F)
Definition: PmaTrack3D.cxx:119
double GetObjFunction(float penaltyFactor=1.0F) const
Objective function optimized in track reconstruction.
TVector3 const & Point3D() const
Definition: PmaHit3D.h:50
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:211
bool Initialize(detinfo::DetectorPropertiesData const &detProp, float initEndSegW=0.05F)
Definition: PmaTrack3D.cxx:77
void Optimize(float penaltyValue, float endSegWeight)
Definition: PmaNode3D.cxx:816
Planes which measure Z direction.
Definition: geo_types.h:138
TVector2 WireDriftToCm(detinfo::DetectorPropertiesData const &detProp, unsigned int wire, float drift, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:286
std::vector< unsigned int > TPCs() const
Definition: PmaTrack3D.cxx:448
double maxY
Definition: plot_hist.C:10
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:563
geo::WireID const & WireID() const
Initial tdc tick for hit.
Definition: Hit.h:280
Float_t tmp
Definition: plot.C:35
virtual pma::SortedObjectBase * Next(unsigned int=0) const
Definition: SortedObjects.h:43
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< pma::Segment3D * > fSegments
Definition: PmaTrack3D.h:397
bool AttachBackToOtherTPC(pma::Node3D *vStart)
float fPenaltyValue
Definition: PmaTrack3D.h:408
unsigned int Wire() const noexcept
Definition: PmaHit3D.h:61
recob::tracking::Vector_t Vector3D
Definition: Utilities.h:34
double TuneFullTree(double eps=0.001, double gmax=50.0)
pma::Vector3D GetDirection3D(size_t index) const
Get trajectory direction at given hit index.
Definition: PmaTrack3D.cxx:380
double Optimize(const detinfo::DetectorPropertiesData &detProp, int nNodes=-1, double eps=0.01, bool selAllHits=true, bool setAllNodes=true, size_t selSegHits=0, size_t selVtxHits=0)
Main optimization method.
double TuneSinglePass(bool skipFirst=false)
float fEndSegWeight
Definition: PmaTrack3D.h:409
constexpr double TickPeriod() const noexcept
A single tick period in microseconds.
Definition: ElecClock.h:310
TPCGeo const & TPC(TPCID const &tpcid=tpc_zero) const
Returns the specified TPC.
Definition: GeometryCore.h:722
unsigned int NEnabledHits(unsigned int view=geo::kUnknown) const
Definition: PmaTrack3D.cxx:430
int TPC(void) const
TPC index or -1 if out of any TPC.
Definition: PmaElement3D.h:35
std::vector< unsigned int > Cryos() const
Definition: PmaTrack3D.cxx:466
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
pma::Track3D * Split(detinfo::DetectorPropertiesData const &detProp, size_t idx, bool try_start_at_idx=true)
double TestHitsMse(detinfo::DetectorPropertiesData const &detProp, const std::vector< art::Ptr< recob::Hit >> &hits, bool normalized=true) const
MSE of 2D hits.
Definition: PmaTrack3D.cxx:820
bool UpdateParamsInTree(bool skipFirst, size_t &depth)
Planes which measure U.
Definition: geo_types.h:135
Double_t scale
Definition: plot.C:24
bool CanFlip() const
Check if the track can be flipped without breaking any other track.
Definition: PmaTrack3D.cxx:644
size_t NPoints(void) const
Definition: PmaElement3D.h:81
unsigned int fSegStopValue
Definition: PmaTrack3D.h:403
void ExtendWith(pma::Track3D *src)
Extend the track with everything from src, delete the src;.
void hits()
Definition: readHits.C:15
void AddNode(pma::Node3D *node)
pma::Hit3D * release_at(size_t index)
Definition: PmaTrack3D.cxx:348
bool isfinite(Vector const &v)
Returns whether all components of the vector are finite.
TCanvas * c1
Definition: plotHisto.C:7
unsigned int NHits(unsigned int view) const
Definition: PmaTrack3D.cxx:421
pma::Node3D * FirstElement() const
Definition: PmaTrack3D.h:275
pma::Node3D * LastElement() const
Definition: PmaTrack3D.h:276
float PeakTime() const noexcept
Definition: PmaHit3D.h:62
pma::Track3D * GetRoot()
virtual int RemoveNext(pma::SortedObjectBase *nextElement)
double fT0
Definition: PmaTrack3D.h:412
bool GetUnconstrainedProj3D(detinfo::DetectorPropertiesData const &detProp, art::Ptr< recob::Hit > hit, TVector3 &p3d, double &dist2) const
double GetDriftShift() const
Definition: PmaNode3D.h:121
bool HasRefPoint(TVector3 *p) const
bool InitFromRefPoints(detinfo::DetectorPropertiesData const &detProp, int tpc, int cryo)
Definition: PmaTrack3D.cxx:218
std::vector< float > DriftsOfWireIntersection(detinfo::DetectorPropertiesData const &detProp, unsigned int wire, unsigned int view) const
void SetT0FromDx(const detinfo::DetectorClocksData &clockData, detinfo::DetectorPropertiesData const &detProp, double dx)
Function to convert dx into dT0.
Float_t d
Definition: plot.C:235
ElecClock const & TPCClock() const noexcept
Borrow a const TPC clock with time set to Trigger time [us].
float SummedADC() const noexcept
Definition: PmaHit3D.h:64
pma::Hit3D & Hit(size_t index)
Definition: PmaElement3D.h:65
void SetEnabled(bool state) noexcept
Definition: PmaHit3D.h:87
void RemoveHits(const std::vector< art::Ptr< recob::Hit >> &hits)
Remove hits; removes also hit->node/seg assignments.
Definition: PmaTrack3D.cxx:412
float fPenaltyFactor
Definition: PmaTrack3D.h:400
bool SameTPC(const TVector3 &p3d, float margin=0.0F) const
Check if p3d is in the same TPC as the node.
Definition: PmaNode3D.cxx:100
double GetObjFnInTree(bool skipFirst=false)
void InternalFlip(std::vector< pma::Track3D * > &toSort)
Definition: PmaTrack3D.cxx:597
bool erase(const art::Ptr< recob::Hit > &hit)
Definition: PmaTrack3D.cxx:367
void UpdateHitsRadius()
The data type to uniquely identify a TPC.
Definition: geo_types.h:381
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:481
unsigned int DisableSingleViewEnds()
bool AttachToSameTPC(pma::Node3D *vStart)
void InsertNode(detinfo::DetectorPropertiesData const &detProp, TVector3 const &p3d, size_t at_idx, unsigned int tpc, unsigned int cryo)
double TriggerTime() const
Trigger electronics clock time in [us].
std::vector< pma::Node3D * > fNodes
Definition: PmaTrack3D.h:396
Detector simulation of raw signals on wires.
bool SelectRndHits(size_t segmax, size_t vtxmax)
size_t CompleteMissingWires(detinfo::DetectorPropertiesData const &detProp, unsigned int view)
double ConvertTicksToX(double ticks, int p, int t, int c) const
void InitFromMiddle(detinfo::DetectorPropertiesData const &detProp, int tpc, int cryo)
Definition: PmaTrack3D.cxx:307
void DeleteSegments()
void push_back(pma::Hit3D *hit)
Definition: PmaTrack3D.h:77
bool UpdateParams()
double AverageDist2() const
unsigned int View2D() const noexcept
Definition: PmaHit3D.h:60
bool HasTwoViews(size_t nmin=1) const
Definition: PmaTrack3D.cxx:439
int Cryo(void) const
Cryostat index or -1 if out of any cryostat.
Definition: PmaElement3D.h:37
void CleanupTails()
Cut out tails with no hits assigned.
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
Implementation of the Projection Matching Algorithm.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:220
void MakeProjectionInTree(bool skipFirst=false)
std::map< size_t, std::vector< double > > dedx_map
Definition: Utilities.h:36
void SortHits(void)
virtual pma::SortedObjectBase * Next(unsigned int index=0) const
Definition: SortedObjects.h:77
double Length(size_t step=1) const
Definition: PmaTrack3D.h:94
bool IsFrozen(void) const
Check if the vertex 3D position is fixed.
Definition: PmaElement3D.h:105
double GetRawdEdxSequence(std::map< size_t, std::vector< double >> &dedx, unsigned int view=geo::kZ, unsigned int skip=0, bool inclDisabled=false) const
Contains all timing reference information for the detector.
TDirectory * dir
Definition: macro.C:5
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
std::vector< TVector3 * > fAssignedPoints
Definition: PmaTrack3D.h:387
pma::Segment3D * PrevSegment(pma::Node3D *vtx) const
bool RemoveNode(size_t idx)
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
float fSegStopFactor
Definition: PmaTrack3D.h:407
double GetDistToProj() const
Definition: PmaHit3D.h:71
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
int NextHit(int index, unsigned int view=geo::kZ, bool inclDisabled=false) const
Definition: PmaTrack3D.cxx:894
virtual double GetDistance2To(const TVector3 &p3d) const =0
Distance [cm] from the 3D point to the object 3D.
pma::Hit3D const * back() const
Definition: PmaTrack3D.h:88
TVector2 CmToWireDrift(detinfo::DetectorPropertiesData const &detProp, float xw, float yd, unsigned int plane, unsigned int tpc, unsigned int cryo)
Definition: Utilities.cxx:298
TH1F * h1
Definition: plot.C:41
double HitDxByView(size_t index, unsigned int view) const
Definition: PmaTrack3D.cxx:993
double GetDistance2To(const TVector3 &p3d) const override
Distance [cm] from the 3D segment to the point 3D.
void AddHit(pma::Hit3D *h)
Definition: PmaElement3D.h:70
Char_t n[5]
bool SwapVertices(size_t v0, size_t v1)
TVector3 fPoint3D
Definition: PmaNode3D.h:152
virtual void Disconnect(void)
pma::Track3D * GetNearestTrkInTree(const TVector3 &p3d_cm, double &dist, bool skipFirst=false)
virtual bool AddNext(pma::SortedObjectBase *nextElement)
float fMaxSegStopFactor
Definition: PmaTrack3D.h:401
bool IntersectionPoint(WireID const &wid1, WireID const &wid2, double &y, double &z) const
Returns the intersection point of two wires.
bool SelectAllHits(void)
virtual pma::SortedObjectBase * Prev(void) const
Definition: SortedObjects.h:42
bool Flip(const detinfo::DetectorPropertiesData &detProp, std::vector< pma::Track3D * > &allTracks)
Definition: PmaTrack3D.cxx:527
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:399
unsigned int TPC() const noexcept
Definition: PmaHit3D.h:59
unsigned int fMinSegStop
Definition: PmaTrack3D.h:404
Double_t sum
Definition: plot.C:31
float fHitsRadius
Definition: PmaTrack3D.h:410
size_t size() const
Definition: PmaTrack3D.h:89
Float_t X
Definition: plot.C:37
Float_t w
Definition: plot.C:20
pma::Track3D * Parent(void) const
Definition: PmaSegment3D.h:66
size_t NHits(void) const
Definition: PmaElement3D.h:76
bool ShiftEndsToHits()
bool AttachBackTo(pma::Node3D *vStart)
unsigned int fMaxSegStop
Definition: PmaTrack3D.h:405
void SetProjection(pma::Hit3D &h) const override
Set hit 3D position and its 2D projection to the vertex.
pma::Element3D * GetNearestElement(const TVector2 &p2d, unsigned int view, int tpc=-1, bool skipFrontVtx=false, bool skipBackVtx=false) const
pma::Segment3D * NextSegment(pma::Node3D *vtx) const
double Length(void) const
Definition: PmaElement3D.h:53
art framework interface to geometry description
size_t NEnabledHits(unsigned int view=geo::kUnknown) const
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
std::pair< TVector2, TVector2 > WireDriftRange(detinfo::DetectorPropertiesData const &detProp, unsigned int view, unsigned int tpc, unsigned int cryo) const
Definition: PmaTrack3D.cxx:484
std::vector< pma::Hit3D * > fHits
Definition: PmaTrack3D.h:385
void UpdateProjection()