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