21 #include "art/Framework/Services/Registry/ServiceHandle.h"
22 #include "messagefacility/MessageLogger/MessageLogger.h"
26 #include "range/v3/algorithm.hpp"
27 #include "range/v3/view.hpp"
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)
43 , fT0Flag(src.fT0Flag)
54 for (
auto const* node : src.
fNodes)
66 for (
size_t i = 0; i < fHits.size(); i++)
68 for (
size_t i = 0; i < fAssignedPoints.size(); i++)
69 delete fAssignedPoints[i];
71 for (
size_t i = 0; i < fSegments.size(); i++)
73 for (
size_t i = 0; i < fNodes.size(); i++)
74 if (!fNodes[i]->NextCount() && !fNodes[i]->Prev())
delete fNodes[i];
80 if (!HasTwoViews(2)) {
81 mf::LogError(
"pma::Track3D") <<
"Need min. 2 hits per view, at least two views.";
86 if (cryos.size() > 1) {
87 mf::LogError(
"pma::Track3D") <<
"Only one cryostat for now, please.";
90 int cryo = cryos.front();
93 if (tpcs.size() > 1) {
94 mf::LogError(
"pma::Track3D") <<
"Only one TPC, please.";
98 int tpc = tpcs.front();
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.";
105 InitFromMiddle(detProp, tpc, cryo);
106 mf::LogVerbatim(
"pma::Track3D") <<
"Track initialized in the module center.";
116 for (
size_t i = 0; i < fNodes.size(); i++)
127 art::ServiceHandle<geo::Geometry const> geom;
129 float wtmp = fEndSegWeight;
130 fEndSegWeight = initEndSegW;
133 TVector3 v3d_1(0., 0., 0.), v3d_2(0., 0., 0.);
135 assert(!fHits.empty());
140 float minX = detProp.
ConvertTicksToX(hit0_a->PeakTime(), hit0_a->View2D(), tpc, cryo);
142 for (
auto hit : fHits) {
157 float minDiff0 = 5000, minDiff1 = 5000;
158 for (
auto hit : fHits) {
160 double diff = fabs(x - minX);
161 if ((diff < minDiff0) && (
hit->View2D() != hit0_a->View2D())) {
165 diff = fabs(x - maxX);
166 if ((diff < minDiff1) && (
hit->View2D() != hit1_a->
View2D())) {
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) +
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);
182 geom->IntersectionPoint(
184 v3d_2.SetXYZ(x, y, z);
187 AddNode(detProp, v3d_1, tpc, cryo);
188 AddNode(detProp, v3d_2, tpc, cryo);
192 Optimize(detProp, 0, 0.01
F,
false,
true, 100);
196 mf::LogVerbatim(
"pma::Track3D") <<
"Good hits not found.";
197 fEndSegWeight = wtmp;
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;
207 fEndSegWeight = wtmp;
214 if (fAssignedPoints.size() < 2)
return false;
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]);
222 p.SetXYZ(p.X() * p.X(), p.Y() * p.Y(), p.Z() * p.Z());
225 stdev *= 1.0 / fAssignedPoints.size();
226 mean *= 1.0 / fAssignedPoints.size();
228 p.SetXYZ(p.X() * p.X(), p.Y() * p.Y(), p.Z() * p.Z());
231 double sx = stdev.X(), sy = stdev.Y(), sz = stdev.Z();
244 stdev.SetXYZ(sx, sy, sz);
246 double scale = 2.0 * stdev.Mag();
247 double iscale = 1.0 / scale;
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]);
257 if (norm2 > max_norm2) {
264 double y = 0.0, kappa = 1.0, prev_kappa, kchg = 1.0;
265 TVector3
w(data[max_index]);
267 while (kchg > 0.0001)
268 for (
size_t i = 0; i < data.size(); i++) {
270 w += (y / kappa) * (data[i] - y * w);
274 kchg = fabs((kappa - prev_kappa) / prev_kappa);
278 TVector3 v1(w), v2(w);
284 for (
size_t i = 0; i < fAssignedPoints.size(); i++) {
285 AddNode(detProp, *(fAssignedPoints[i]), tpc, cryo);
291 if (
size()) UpdateHitsRadius();
293 Optimize(detProp, 0, 0.01
F,
false,
true, 100);
302 art::ServiceHandle<geo::Geometry const> geom;
304 const auto& tpcGeo = geom->TPC(tpc, cryo);
306 double minX = tpcGeo.MinX(), maxX = tpcGeo.MaxX();
307 double minY = tpcGeo.MinY(), maxY = tpcGeo.MaxY();
308 double minZ = tpcGeo.MinZ(), maxZ = tpcGeo.MaxZ();
310 TVector3 v3d_1(0.5 * (minX + maxX), 0.5 * (minY + maxY), 0.5 * (minZ + maxZ));
311 TVector3 v3d_2(v3d_1);
313 TVector3
shift(5.0, 5.0, 5.0);
318 AddNode(detProp, v3d_1, tpc, cryo);
319 AddNode(detProp, v3d_2, tpc, cryo);
324 Optimize(detProp, 0, 0.01
F);
330 for (
size_t i = 0; i < fNodes.size(); ++i)
331 if (fNodes[i] == n)
return (
int)i;
338 for (
size_t i = 0; i <
size(); i++)
339 if (fHits[i] == hit)
return (
int)i;
347 fHits.erase(fHits.begin() + index);
353 const art::Ptr<recob::Hit>&
hit)
355 for (
auto const& trk_hit : fHits) {
356 if (trk_hit->fHit == hit)
return false;
367 for (
size_t i = 0; i <
size(); i++) {
368 if (hit == fHits[i]->fHit) {
370 fHits.erase(fHits.begin() + i);
383 for (
auto s : fSegments) {
384 if (
s->HasHit(h))
return s->GetDirection3D();
386 for (
auto n : fNodes) {
387 if (
n->HasHit(h))
return n->GetDirection3D();
392 mf::LogWarning(
"pma::Track3D")
393 <<
"GetDirection3D(): had to update hit assignment to segment/node.";
395 return pe->GetDirection3D();
398 throw cet::exception(
"pma::Track3D") <<
"GetDirection3D(): direction of a not assigned hit "
399 << index <<
" (size: " << fHits.size() <<
")" << std::endl;
407 fHits.reserve(fHits.size() + hits.size());
408 for (
auto const&
hit : hits)
409 push_back(detProp,
hit);
416 for (
auto const&
hit : hits) {
419 if (n) MakeProjection();
426 for (
auto hit : fHits) {
427 if (
hit->View2D() == view) n++;
436 for (
auto hit : fHits) {
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++;
452 std::vector<unsigned int>
455 std::vector<unsigned int> tpc_idxs;
456 for (
auto hit : fHits) {
457 unsigned int tpc =
hit->TPC();
460 for (
unsigned int const tpc_idx : tpc_idxs)
461 if (tpc_idx == tpc) {
466 if (!found) tpc_idxs.push_back(tpc);
471 std::vector<unsigned int>
474 std::vector<unsigned int> cryo_idxs;
475 for (
auto hit : fHits) {
476 unsigned int cryo =
hit->Cryo();
479 for (
size_t j = 0; j < cryo_idxs.size(); j++)
480 if (cryo_idxs[j] == cryo) {
485 if (!found) cryo_idxs.push_back(cryo);
490 std::pair<TVector2, TVector2>
494 unsigned int cryo)
const
496 std::pair<TVector2, TVector2> range(TVector2(0., 0.), TVector2(0., 0.));
499 while ((n0 < fNodes.size()) && (fNodes[n0]->
TPC() != (int)tpc))
502 if (n0 < fNodes.size()) {
504 while ((n1 < fNodes.size()) && (fNodes[n1]->
TPC() == (int)tpc))
508 if (n1 == fNodes.size()) n1--;
510 TVector2 p0 = fNodes[n0]->Projection2D(view);
513 TVector2
p1 = fNodes[n1]->Projection2D(view);
516 if (p0.X() > p1.X()) {
518 p0.Set(p1.X(), p0.Y());
521 if (p0.Y() > p1.Y()) {
523 p0.Set(p0.X(), p1.Y());
535 std::vector<pma::Track3D*>& allTracks)
537 if (fNodes.size() < 2) {
return true; }
539 std::vector<pma::Track3D*> toSort;
552 allTracks.push_back(u);
553 if (u->
Flip(detProp, allTracks)) {
554 InternalFlip(toSort);
555 toSort.push_back(
this);
558 mf::LogWarning(
"pma::Track3D")
559 <<
"Flip(): Could not flip after split (but new track is preserved!!).";
568 throw cet::exception(
"pma::Track3D") <<
"Node not found." << std::endl;
573 if (t->
Flip(detProp, allTracks))
575 InternalFlip(toSort);
576 toSort.push_back(
this);
585 InternalFlip(toSort);
586 toSort.push_back(
this);
589 for (
size_t t = 0; t < toSort.size(); t++) {
591 for (
size_t u = 0; u < t; u++)
592 if (toSort[u] == toSort[t]) {
597 toSort[t]->MakeProjection();
598 toSort[t]->SortHits();
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++) {
615 if (fNodes.back()->NextCount())
616 for (
size_t j = 0; j < fNodes.back()->NextCount(); j++) {
618 toSort.push_back(s->
Parent());
621 if (fNodes.front()->Prev()) {
623 toSort.push_back(s->
Parent());
627 std::reverse(fNodes.begin(), fNodes.end());
628 toSort.push_back(
this);
635 std::vector<pma::Track3D*> toSort;
636 InternalFlip(toSort);
637 toSort.push_back(
this);
639 for (
size_t t = 0; t < toSort.size(); t++) {
641 for (
size_t u = 0; u < t; u++)
642 if (toSort[u] == toSort[t]) {
647 toSort[t]->MakeProjection();
648 toSort[t]->SortHits();
656 if (!fNodes.size()) {
return false; }
675 unsigned int nViews = 3;
677 for (
unsigned int i = 0; i < nViews; i++) {
678 GetRawdEdxSequence(dedxInViews[i], i, 1);
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;
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); }
689 if (!dedx.empty()) dedx.pop_back();
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) {
697 if (dedx.size() > 30)
699 else if (dedx.size() > 20)
701 else if (dedx.size() > 10)
707 size_t k = (dedx.size() - 2) >> 1;
710 for (
size_t i = 1, j = 0; j <
n; i++, j++) {
711 dEStart += dedx[i][5];
712 dxStart += dedx[i][6];
714 if (dxStart > 0.0
F) dEdxStart = dEStart / dxStart;
716 for (
size_t i = dedx.size() - 2, j = 0; j <
n; i--, j++) {
717 dEStop += dedx[i][5];
718 dxStop += dedx[i][6];
720 if (dxStop > 0.0
F) dEdxStop = dEStop / dxStop;
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.0
F) dEdxStart = dEStart / dxStart;
728 if (dxStop > 0.0
F) dEdxStop = dEStop / dxStop;
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];
738 mf::LogVerbatim(
"pma::Track3D")
739 <<
"Auto-flip fired (1), thr: " << (1.0 + thr) <<
", value: " << dEdxStart / dEdxStop;
743 mf::LogVerbatim(
"pma::Track3D")
744 <<
"Auto-flip fired (2), thr: " << (1.0 + thr) <<
", value: " << dEdxStop / dEdxStart;
751 std::vector<pma::Track3D*>& allTracks,
756 unsigned int nViews = 3;
758 for (
unsigned int i = 0; i < nViews; i++) {
759 GetRawdEdxSequence(dedxInViews[i], i, 1);
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;
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); }
770 if (!dedx.empty()) dedx.pop_back();
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) {
778 if (dedx.size() > 30)
780 else if (dedx.size() > 20)
782 else if (dedx.size() > 10)
788 size_t k = (dedx.size() - 2) >> 1;
791 for (
size_t i = 1, j = 0; j <
n; i++, j++) {
792 dEStart += dedx[i][5];
793 dxStart += dedx[i][6];
795 if (dxStart > 0.0
F) dEdxStart = dEStart / dxStart;
797 for (
size_t i = dedx.size() - 2, j = 0; j <
n; i--, j++) {
798 dEStop += dedx[i][5];
799 dxStop += dedx[i][6];
801 if (dxStop > 0.0
F) dEdxStop = dEStop / dxStop;
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.0
F) dEdxStart = dEStart / dxStart;
809 if (dxStop > 0.0
F) dEdxStop = dEStop / dxStop;
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];
820 mf::LogVerbatim(
"pma::Track3D")
821 <<
"Auto-flip fired (1), thr: " << (1.0 + thr) <<
", value: " << dEdxStart / dEdxStop;
822 done = Flip(detProp, allTracks);
825 mf::LogVerbatim(
"pma::Track3D")
826 <<
"Auto-flip fired (2), thr: " << (1.0 + thr) <<
", value: " << dEdxStop / dEdxStart;
827 done = Flip(detProp, allTracks);
835 bool normalized)
const
838 mf::LogWarning(
"pma::Track3D") <<
"TestHitsMse(): Empty cluster.";
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();
853 return mse / hits.size();
864 mf::LogWarning(
"pma::Track3D") <<
"TestHits(): Empty cluster.";
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;
880 auto const nHits =
size();
881 if (nHits < 2)
return 0.0;
888 if (start >= nHits - 1)
return 0.0;
889 if (stop >= nHits) stop = nHits - 1;
895 size_t i = start + step;
904 result += sqrt(
pma::Dist2(h0->Point3D(), back()->Point3D()));
913 if (index < -1) index = -1;
914 while (++index < (
int)
size())
917 if (hit->
View2D() == view) {
931 if (index > (
int)
size()) index = (int)
size();
935 if (hit->
View2D() == view) {
949 bool secondDir)
const
954 if (hit->
View2D() != view) {
955 mf::LogWarning(
"pma::Track3D") <<
"Function used with the hit not matching specified view.";
959 bool hitFound =
false;
963 while (!hitFound && (++i < (
int)
size())) {
967 if (nexthit->
View2D() == view)
979 mf::LogWarning(
"pma::Track3D") <<
"Single hit in this view.";
985 while (!hitFound && (--i >= 0)) {
989 if (nexthit->
View2D() == view)
1001 mf::LogWarning(
"pma::Track3D") <<
"Single hit in this view.";
1006 default: mf::LogError(
"pma::Track3D") <<
"Direction undefined.";
break;
1014 if (index <
size()) {
1019 mf::LogError(
"pma::Track3D") <<
"Hit index out of range.";
1030 while (k < nCount) {
1032 if (seg && (seg->
Parent() ==
this))
return seg;
1043 if (seg->Parent() ==
this)
return seg;
1052 bool inclDisabled)
const
1056 if (!
size())
return 0.0;
1062 double rv, dr, dR, dq, dEq, qSkipped = 0.0;
1064 size_t j = NextHit(-1, view, inclDisabled),
s = skip;
1065 if (j >=
size())
return 0.0F;
1077 j = NextHit(j, view, inclDisabled);
1080 size_t jmax = PrevHit(
size(), view, inclDisabled);
1082 std::vector<size_t> indexes;
1083 TVector3 p0(0., 0., 0.),
p1(0., 0., 0.);
1084 TVector2 c0(0., 0.), c1(0., 0.);
1088 indexes.push_back(j);
1102 rv = HitDxByView(j, view);
1107 while (((m < step) || (dR < 0.1) || (dr == 0.0)) && (j <= jmax)) {
1108 j = NextHit(j, view);
1109 if (j > jmax)
break;
1112 if (!inclDisabled && !hit->
IsEnabled()) {
1118 indexes.push_back(j);
1129 rv = HitDxByView(j, view);
1139 double range =
Length(0, j);
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);
1151 for (
auto const idx : indexes)
1152 dedx[idx] = trk_section;
1154 j = NextHit(j, view, inclDisabled);
1163 unsigned int view)
const
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;
1171 fNodes[i]->Projection2D(view).
X(),
1172 fNodes[i]->Projection2D(view).Y(),
1177 fNodes[i + 1]->Projection2D(view).
X(),
1178 fNodes[i + 1]->Projection2D(view).Y(),
1180 fNodes[i + 1]->
TPC(),
1181 fNodes[i + 1]->Cryo());
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);
1196 int dPrev, dw,
w, wx, wPrev, i = NextHit(-1, view);
1201 std::vector<pma::Hit3D*> missHits;
1203 while (i < (
int)
size()) {
1207 if (hit->
View2D() == view) {
1210 wPrev = hitPrev->
Wire();
1212 if (
abs(w - wPrev) > 1) {
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];
1229 mf::LogVerbatim(
"pma::Track3D") <<
"Track does not intersect with the wire " << wx;
1233 new pma::Hit3D(detProp, iWire, view, hit->
TPC(), hit->
Cryo(), peakTime, 1.0, 1.0);
1234 missHits.push_back(hmiss);
1244 i = NextHit(i, view,
true);
1245 while ((i < (
int)
size()) && (hit->
TPC() != fHits[i]->TPC())) {
1248 i = NextHit(i, view,
true);
1252 if (missHits.size()) {
1253 for (
size_t hi = 0; hi < missHits.size(); hi++) {
1254 push_back(missHits[hi]);
1261 return missHits.size();
1267 fNodes.push_back(node);
1268 if (fNodes.size() > 1) RebuildSegments();
1278 while (si < fSegments.size()) {
1279 if (!fSegments[si]->IsFrozen()) {
1280 maxSeg = fSegments[si];
1286 if (!maxSeg)
return false;
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++) {
1299 segHits = nHitsByView[0] + nHitsByView[1] + nHitsByView[2];
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;
1307 nHits = fNodes[i]->NEnabledHits() + seg->
NEnabledHits() + fNodes[i - 1]->NEnabledHits();
1309 if (nHits > maxHits) {
1311 maxLength = seg->
Length();
1312 maxSegHits = segHits;
1316 else if (nHits == maxHits) {
1317 segLength = seg->
Length();
1318 if (segLength > maxLength) {
1319 maxLength = segLength;
1320 maxSegHits = segHits;
1327 if (maxSegHits > 1) {
1334 unsigned int maxViewIdx = 2, midViewIdx = 2;
1335 if ((nHitsByView[2] >= nHitsByView[1]) && (nHitsByView[1] >= nHitsByView[0])) {
1339 else if ((nHitsByView[1] >= nHitsByView[2]) && (nHitsByView[2] >= nHitsByView[0])) {
1343 else if ((nHitsByView[0] >= nHitsByView[2]) && (nHitsByView[2] >= nHitsByView[1])) {
1347 else if ((nHitsByView[2] >= nHitsByView[0]) && (nHitsByView[0] >= nHitsByView[1])) {
1351 else if ((nHitsByView[0] >= nHitsByView[1]) && (nHitsByView[1] >= nHitsByView[2])) {
1355 else if ((nHitsByView[1] >= nHitsByView[0]) && (nHitsByView[0] >= nHitsByView[2])) {
1359 if (nHitsByView[midViewIdx] < 2) midViewIdx = maxViewIdx;
1361 if (nHitsByView[midViewIdx] < 2) {
1362 mf::LogVerbatim(
"pma::Track3D") <<
"AddNode(): too few hits.";
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) {
1372 if (maxSeg->
Hit(i).
View2D() == midViewIdx) {
1373 if (n == halfIndex)
break;
1382 while ((i < maxSeg->NHits()) &&
1388 if (!nHitsByView[0]) {
1389 if (nHitsByView[1] && (mHits[1] < 2)) {
1390 mf::LogVerbatim(
"pma::Track3D") <<
"AddNode(): low Ind2 hits.";
1393 if (nHitsByView[2] && (mHits[2] < 2)) {
1394 mf::LogVerbatim(
"pma::Track3D") <<
"AddNode(): low Coll hits.";
1402 unsigned int tpc = maxSeg->
Hit(i0).
TPC();
1403 unsigned int cryo = maxSeg->
Hit(i0).
Cryo();
1410 fNodes[vIndex]->GetDriftShift());
1412 fNodes.insert(fNodes.begin() + vIndex,
p);
1414 maxSeg->
AddNext(fNodes[vIndex]);
1416 seg =
new pma::Segment3D(
this, fNodes[vIndex], fNodes[vIndex + 1]);
1417 fSegments.insert(fSegments.begin() + vIndex, seg);
1427 TVector3
const& p3d,
1433 new pma::Node3D(detProp, p3d, tpc, cryo,
false, fNodes[at_idx]->GetDriftShift());
1434 fNodes.insert(fNodes.begin() + at_idx, vtx);
1436 if (fNodes.size() > 1) RebuildSegments();
1442 if ((fNodes.size() > 1) && (idx < fNodes.size())) {
1444 fNodes.erase(fNodes.begin() + idx);
1458 bool try_start_at_idx)
1460 if (!idx || (idx + 1 >= fNodes.size()))
return 0;
1468 for (
size_t i = 0; i < idx; ++i) {
1476 while (k < n->NextCount()) {
1484 fNodes.erase(fNodes.begin());
1495 while (h <
size()) {
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);
1501 if ((dist2D_new < dist2D_old) && t0->
HasTPC(tpc))
1503 else if (!HasTPC(tpc) && t0->
HasTPC(tpc))
1511 if (try_start_at_idx && t0->
CanFlip()) {
1512 mf::LogVerbatim(
"pma::Track3D") <<
" attach new t0 and this trk to a common start node";
1514 passed = t0->
AttachTo(fNodes.front());
1517 mf::LogVerbatim(
"pma::Track3D") <<
" attach this trk to the new t0 end node";
1518 passed = AttachTo(t0->
fNodes.back());
1522 mf::LogVerbatim(
"pma::Track3D") <<
" single-view track";
1527 mf::LogVerbatim(
"pma::Track3D") <<
" undo split";
1531 for (
size_t i = 0; i < idx; ++i) {
1532 fNodes.insert(fNodes.begin() + i, t0->
fNodes.front());
1549 if (vtx == vStart)
return true;
1552 if (vStart->
Prev()) {
1554 if (rootPrev->
IsAttachedTo(rootThis)) {
return false; }
1558 if (rootNext->
IsAttachedTo(rootThis)) {
return false; }
1564 for (
auto n : fNodes)
1566 mf::LogError(
"pma::Track3D") <<
"Don't create loops!";
1570 if (!noFlip && CanFlip() && (vStart->
TPC() == fNodes.back()->TPC()) &&
1573 (fNodes.back()->NextCount() == 0)) {
1574 mf::LogError(
"pma::Track3D") <<
"Flip, endpoint closer to vStart.";
1578 if (vStart->
TPC() == vtx->
TPC())
1579 return AttachToSameTPC(vStart);
1581 return AttachToOtherTPC(vStart);
1587 if (fNodes.front()->Prev())
return false;
1589 mf::LogVerbatim(
"pma::Track3D") <<
"Attach to track in another TPC.";
1591 fNodes.insert(fNodes.begin(), vStart);
1593 fSegments.insert(fSegments.begin(),
new pma::Segment3D(
this, fNodes[0], fNodes[1]));
1611 if (vStart->
Prev()) {
1619 mf::LogVerbatim(
"pma::Track3D") <<
"Reconnect prev to vStart.";
1624 mf::LogError(
"pma::Track3D") <<
"Flips in vtx and vStart not possible, cannot attach.";
1629 mf::LogVerbatim(
"pma::Track3D") <<
"Reconnect prev to vStart.";
1648 throw cet::exception(
"pma::Track3D") <<
"Something is still using disconnected vertex.";
1660 if (vtx == vStart)
return true;
1663 if (vStart->
Prev()) {
1665 if (rootPrev->
IsAttachedTo(rootThis)) {
return false; }
1669 if (rootNext->
IsAttachedTo(rootThis)) {
return false; }
1675 for (
auto n : fNodes)
1677 mf::LogError(
"pma::Track3D") <<
"Don't create loops!";
1681 if (vStart->
TPC() == vtx->
TPC())
1682 return AttachBackToSameTPC(vStart);
1684 return AttachBackToOtherTPC(vStart);
1690 if (vStart->
Prev())
return false;
1692 mf::LogVerbatim(
"pma::Track3D") <<
"Attach to track in another TPC.";
1694 fNodes.push_back(vStart);
1696 size_t idx = fNodes.size() - 1;
1697 fSegments.push_back(
new pma::Segment3D(
this, fNodes[idx - 1], fNodes[idx]));
1707 if (vStart->
Prev()) {
1711 mf::LogError(
"pma::Track3D") <<
"Cannot attach back to inner node of other track.";
1718 mf::LogError(
"pma::Track3D") <<
"Flip not possible, cannot attach.";
1722 fNodes[fNodes.size() - 1] = vStart;
1723 fSegments[fSegments.size() - 1]->
AddNext(vStart);
1736 throw cet::exception(
"pma::Track3D")
1737 <<
"Something is still using disconnected vertex." << std::endl;
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;
1754 for (
size_t i = 0; i < src->
fNodes.size(); ++i) {
1755 fNodes.push_back(src->
fNodes[i]);
1757 size_t idx = fNodes.size() - 1;
1758 fSegments.push_back(
new pma::Segment3D(
this, fNodes[idx - 1], fNodes[idx]));
1762 while (src->
size()) {
1767 fAssignedPoints.push_back(
p);
1782 if (fNodes.size()) {
1785 if (!trk) trk =
this;
1788 throw cet::exception(
"pma::Track3D") <<
"Broken track, no nodes.";
1796 for (
auto trk : branches)
1797 if (trk ==
this) {
throw cet::exception(
"pma::Track3D") <<
"Track tree has loop."; }
1799 branches.push_back(
this);
1802 if (skipFirst) i0 = 1;
1804 for (
size_t i = i0; i < fNodes.size(); ++i)
1805 for (
size_t n = 0;
n < fNodes[i]->NextCount();
n++) {
1816 if (trk ==
this)
return true;
1818 std::vector<pma::Track3D const*> branchesThis, branchesTrk;
1821 if (!GetBranches(branchesThis))
return true;
1823 for (
auto bThis : branchesThis)
1824 for (
auto bTrk : branchesTrk)
1825 if (bThis == bTrk)
return true;
1832 for (
auto point : fAssignedPoints)
1833 if (point == p)
return true;
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);
1846 for (
auto s : fSegments) {
1847 sumMse +=
s->SumDist2(view);
1848 nEnabledHits +=
s->NEnabledHits(view);
1852 return sumMse / nEnabledHits;
1861 float p = penaltyFactor * fPenaltyValue;
1862 for (
size_t i = 0; i < fNodes.size(); i++) {
1863 sum += fNodes[i]->GetObjFunction(p, fEndSegWeight);
1865 return sum / fNodes.size();
1877 if (!fNodes.size()) {
1878 mf::LogError(
"pma::Track3D") <<
"Track not initialized.";
1882 if (!UpdateParams()) {
1883 mf::LogError(
"pma::Track3D") <<
"Track empty.";
1886 double g0 = GetObjFunction(), g1 = 0.0;
1887 if (g0 == 0.0)
return g0;
1891 for (
auto n : fNodes)
1892 n->SetVertexToBranching(setAllNodes);
1895 fMinSegStop = fSegments.size();
1896 fMaxSegStop = (int)(
size() / fMaxSegStopFactor) + 1;
1898 if (selSegHits || selVtxHits) SelectRndHits(selSegHits, selVtxHits);
1900 bool stepDone =
true;
1901 unsigned int stepIter = 0;
1904 unsigned int iter = 0;
1905 while ((gstep > eps) && (iter < 1000)) {
1906 if ((fNodes.size() < 4) || (iter % 10 == 0))
1909 MakeFastProjection();
1911 if (!UpdateParams()) {
1912 mf::LogError(
"pma::Track3D") <<
"Track empty.";
1916 for (
auto n : fNodes)
1917 n->Optimize(fPenaltyValue, fEndSegWeight);
1920 g0 = GetObjFunction();
1926 gstep = fabs(g0 - g1) / g0;
1931 if (fNodes.size() > 2) {
1934 }
while (!stepDone && (stepIter < 5));
1940 if (SelectAllHits())
continue;
1944 case 0: stop =
true;
break;
1947 mf::LogVerbatim(
"pma::Track3D") <<
"optimized segments: " << fSegments.size();
1948 if ((fSegments.size() >= fSegStopValue) || (fSegments.size() >= fMaxSegStop)) { stop =
true; }
1950 if (!AddNode(detProp)) stop =
true;
1956 if (AddNode(detProp)) {
1961 mf::LogVerbatim(
"pma::Track3D") <<
"stop (3)";
1966 if (AddNode(detProp)) {
1969 if (AddNode(detProp)) nNodes--;
1972 else if (nNodes > 4) {
1973 if (AddNode(detProp)) {
1978 mf::LogVerbatim(
"pma::Track3D") <<
"stop (2)";
1983 if (AddNode(detProp)) nNodes--;
1986 if (AddNode(detProp)) { nNodes--; }
1988 mf::LogVerbatim(
"pma::Track3D") <<
"stop (1)";
1999 return GetObjFunction();
2005 constexpr
size_t maxTreeDepth = 100;
2010 if (
auto segThis = NextSegment(vtx)) vtx =
static_cast<pma::Node3D*
>(segThis->Next());
2012 if (++depth > maxTreeDepth) { mf::LogError(
"pma::Track3D") <<
"Tree depth above allowed max."; }
2018 auto segThis = NextSegment(vtx);
2020 for (
size_t i = 0; i < vtx->
NextCount(); i++) {
2031 if (!UpdateParams()) {
2032 mf::LogError(
"pma::Track3D") <<
"Track empty.";
2047 if (
auto segThis = NextSegment(vtx)) vtx =
static_cast<pma::Node3D*
>(segThis->Next());
2052 vtx->
Optimize(fPenaltyValue, fEndSegWeight);
2053 auto segThis = NextSegment(vtx);
2055 for (
size_t i = 0; i < vtx->
NextCount(); i++) {
2066 return g + GetObjFunction();
2075 if (
auto segThis = NextSegment(vtx)) vtx =
static_cast<pma::Node3D*
>(segThis->Next());
2079 dist = sqrt(
Dist2(p3d_cm));
2083 auto segThis = NextSegment(vtx);
2086 for (
size_t i = 0; i < vtx->
NextCount(); i++) {
2088 if (seg != segThis) {
2117 if (
auto segThis = NextSegment(vtx)) vtx =
static_cast<pma::Node3D*
>(segThis->Next());
2121 dist =
Dist2(p2d_cm, view, tpc, cryo);
2125 auto segThis = NextSegment(vtx);
2128 for (
size_t i = 0; i < vtx->
NextCount(); i++) {
2130 if (seg != segThis) {
2163 if (
auto segThis = NextSegment(vtx)) vtx =
static_cast<pma::Node3D*
>(segThis->Next());
2167 auto segThis = NextSegment(vtx);
2169 for (
size_t i = 0; i < vtx->
NextCount(); i++) {
2184 while (HasTwoViews(2) && (i <
size())) {
2188 nearestTrk = GetNearestTrkInTree(hit->
Point2D(), hit->
View2D(), hit->
TPC(), hit->
Cryo(), dmin);
2189 if ((nearestTrk !=
this) && (dmin < 0.5 * d0)) {
2191 mf::LogVerbatim(
"pma::Track3D") <<
"*** hit moved to another track ***";
2196 if (!
size()) { mf::LogError(
"pma::Track3D") <<
"ALL hits moved to other tracks."; }
2205 if (
auto segThis = NextSegment(vtx)) vtx =
static_cast<pma::Node3D*
>(segThis->Next());
2209 auto segThis = NextSegment(vtx);
2211 for (
size_t i = 0; i < vtx->
NextCount(); i++) {
2231 if (
auto segThis = NextSegment(vtx)) vtx =
static_cast<pma::Node3D*
>(segThis->Next());
2235 auto segThis = NextSegment(vtx);
2237 for (
size_t i = 0; i < vtx->
NextCount(); i++) {
2257 if (
auto segThis = NextSegment(vtx)) vtx =
static_cast<pma::Node3D*
>(segThis->Next());
2262 auto segThis = NextSegment(vtx);
2264 for (
size_t i = 0; i < vtx->
NextCount(); i++) {
2275 return g + GetObjFunction();
2281 if (
size_t depth = 1; !UpdateParamsInTree(
false, depth)) {
2282 mf::LogError(
"pma::Track3D") <<
"TuneFullTree failed.";
2286 double g0 = GetObjFnInTree(), g1 = 0.0;
2288 mf::LogError(
"pma::Track3D") <<
"Infinifte value of g.";
2292 mf::LogWarning(
"pma::Track3D") <<
"Too high value of g: " << g0;
2295 if (g0 == 0.0)
return g0;
2297 mf::LogVerbatim(
"pma::Track3D") <<
"Tune tree, g = " << g0;
2298 unsigned int stepIter = 0;
2301 unsigned int iter = 0;
2302 while ((gstep > eps) && (iter < 60)) {
2304 g0 = TuneSinglePass();
2306 MakeProjectionInTree();
2308 if (
size_t depth = 1; !UpdateParamsInTree(
false, depth)) {
2313 if (g0 == 0.0
F)
break;
2315 gstep = fabs(g0 - g1) / g0;
2321 }
while (stepIter < 5);
2323 MakeProjectionInTree();
2326 if (g0 >= 0) { mf::LogVerbatim(
"pma::Track3D") <<
" done, g = " << g0; }
2328 mf::LogError(
"pma::Track3D") <<
"TuneFullTree failed.";
2342 if (
auto segThis = NextSegment(node)) node =
static_cast<pma::Node3D*
>(segThis->Next());
2348 auto segThis = NextSegment(node);
2349 for (
size_t i = 0; i < node->
NextCount(); i++) {
2355 node =
static_cast<pma::Node3D*
>(segThis->Next());
2360 for (
auto h : fHits) {
2361 h->fPoint3D[0] += dx;
2364 for (
auto p : fAssignedPoints) {
2370 double newdx = fNodes.front()->GetDriftShift();
2373 SetT0FromDx(clockData, detProp, newdx);
2381 auto const* geom = lar::providerFrom<geo::Geometry>();
2382 const geo::TPCGeo& tpcGeo = geom->TPC(fNodes.front()->TPC(), fNodes.front()->Cryo());
2386 double correctedSign = 0;
2387 if (tpcGeo.DetectDriftDirection() > 0) {
2388 if (dx > 0) { correctedSign = 1.0; }
2390 correctedSign = -1.0;
2394 if (dx > 0) { correctedSign = -1.0; }
2396 correctedSign = 1.0;
2403 dxInTicks = dxInTicks * correctedSign;
2409 mf::LogDebug(
"pma::Track3D") << dx <<
", " << dxInTicks <<
", " << correctedSign <<
", " <<
fT0
2410 <<
", " << tpcGeo.DetectDriftDirection()
2421 for (
size_t i = 0; i < fSegments.size(); i++)
2422 delete fSegments[i];
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]));
2440 unsigned int nhits = 0;
2441 while (!nhits && (fNodes.size() > 2) && !fNodes.front()->IsBranching()) {
2443 nhits = vtx->
NHits();
2446 nhits += seg->
NHits();
2450 fNodes.erase(fNodes.begin());
2453 fSegments.erase(fSegments.begin());
2460 while (!nhits && (fNodes.size() > 2) && !fNodes.back()->IsBranching()) {
2462 nhits = vtx->
NHits();
2465 nhits += seg->
NHits();
2468 if (vtx->
NextCount() < 1)
delete fNodes.back();
2472 fSegments.pop_back();
2485 if (!(fNodes.front()->Prev())) {
2489 if (vtx == fNodes.front())
2492 mf::LogWarning(
"pma::Track3D") <<
"First hit is projected to inner node.";
2499 if (seg->
Prev() == fNodes.front()) {
2500 double l0 = seg->
Length();
2502 if ((seg->
Length() < 0.2 * l0) && (fNodes.size() > 2)) {
2505 mf::LogWarning(
"pma::Track3D")
2506 <<
"ShiftEndsToHits(): Short start segment, node removed.";
2507 fNodes.erase(fNodes.begin() + 1);
2515 mf::LogWarning(
"pma::Track3D") <<
"Branching node, not removed.";
2521 mf::LogWarning(
"pma::Track3D") <<
"First hit is projected to inner segment.";
2528 if (!(fNodes.back()->NextCount())) {
2529 el = GetNearestElement(back()->
Point3D());
2532 if (vtx == fNodes.back())
2535 mf::LogWarning(
"pma::Track3D") <<
"First hit is projected to inner node.";
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;
2549 mf::LogWarning(
"pma::Track3D")
2550 <<
"ShiftEndsToHits(): Short end segment, node removed.";
2551 fNodes.erase(fNodes.begin() + idx);
2559 mf::LogWarning(
"pma::Track3D") <<
"Branching node, not removed.";
2565 mf::LogWarning(
"pma::Track3D") <<
"First hit is projected to inner segment.";
2579 unsigned int cryo)
const
2581 double dist, min_dist = 1.0e12;
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;
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;
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;
2606 using namespace ranges;
2607 auto to_distance2 = [&p3d](
auto seg) {
return seg->GetDistance2To(p3d); };
2616 bool skipBackVtx)
const
2618 if (fSegments.front()->TPC() < 0) skipFrontVtx =
false;
2619 if (fSegments.back()->TPC() < 0) skipBackVtx =
false;
2621 if (skipFrontVtx && skipBackVtx && (fSegments.size() == 1))
2622 return fSegments.front();
2624 size_t v0 = 0, v1 = fNodes.size();
2625 if (skipFrontVtx) v0 = 1;
2626 if (skipBackVtx) --v1;
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) {
2638 for (
auto segment : fSegments)
2639 if (segment->TPC() == tpc) {
2640 if (segment->TPC() < 0)
continue;
2643 if (dist < min_dist) {
2648 if (!pe_min)
throw cet::exception(
"pma::Track3D") <<
"Nearest element not found." << std::endl;
2657 for (
size_t i = 1; i < fNodes.size(); i++) {
2658 dist = fNodes[i]->GetDistance2To(p3d);
2659 if (dist < min_dist) {
2664 for (
size_t i = 0; i < fSegments.size(); i++) {
2666 if (dist < min_dist) {
2668 pe_min = fSegments[i];
2676 art::Ptr<recob::Hit>
hit,
2678 double& dist2)
const
2683 hit->WireID().Plane,
2685 hit->WireID().Cryostat);
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;
2694 d2 = fSegments[i]->GetDistance2To(p2d, view);
2701 p3d = seg->GetUnconstrainedProj3D(p2d, view);
2714 std::vector<pma::Hit3D*> hits_tmp;
2715 hits_tmp.reserve(
size());
2721 for (
size_t i = 0; i < vtx->
NHits(); i++) {
2723 if (h3d->
fParent ==
this) hits_tmp.push_back(h3d);
2728 for (
size_t i = 0; i < seg->
NHits(); i++) {
2730 if (h3d->
fParent ==
this) hits_tmp.push_back(h3d);
2734 seg = NextSegment(vtx);
2740 if (
size() == hits_tmp.size()) {
2741 for (
size_t i = 0; i <
size(); i++) {
2742 fHits[i] = hits_tmp[i];
2746 mf::LogError(
"pma::Track3D") <<
"Hit sorting problem.";
2754 unsigned int nDisabled = 0;
2756 std::array<int, 4> hasHits{{}};
2761 bool rebuild =
false, stop =
false;
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];
2780 nViews = hasHits[0] + hasHits[1] + hasHits[2] + hasHits[3];
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];
2797 nViews = hasHits[0] + hasHits[1] + hasHits[2] + hasHits[3];
2806 if (fNodes.size() < 3)
break;
2808 nViews = hasHits[1] + hasHits[2] + hasHits[3];
2809 if (hasHits[0] || (nViews > 1))
2811 else if (!fNodes.front()->IsBranching()) {
2813 fNodes.erase(fNodes.begin());
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];
2840 nViews = hasHits[0] + hasHits[1] + hasHits[2] + hasHits[3];
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];
2857 nViews = hasHits[0] + hasHits[1] + hasHits[2] + hasHits[3];
2866 if (fNodes.size() < 3)
break;
2868 nViews = hasHits[1] + hasHits[2] + hasHits[3];
2869 if (hasHits[0] || (nViews > 1))
2871 else if (!fNodes.back()->IsBranching()) {
2891 if (fraction < 0.0
F) fraction = 0.0F;
2892 if (fraction > 1.0
F) fraction = 1.0F;
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;
2900 bool b, changed =
false;
2901 for (
auto h : fHits) {
2903 if (fraction < 1.0
F) {
2904 h->SetEnabled(
false);
2905 switch (
h->View2D()) {
2907 if (coll++ < nHitsColl)
h->SetEnabled(
true);
2910 if (ind2++ < nHitsInd2)
h->SetEnabled(
true);
2913 if (ind1++ < nHitsInd1)
h->SetEnabled(
true);
2918 h->SetEnabled(
true);
2920 changed |= (b !=
h->IsEnabled());
2923 if (fraction < 1.0
F) {
2924 FirstElement()->SelectAllHits();
2925 LastElement()->SelectAllHits();
2933 bool changed =
false;
2934 for (
auto n : fNodes)
2935 changed |=
n->SelectRndHits(vtxmax);
2936 for (
auto s : fSegments)
2937 changed |=
s->SelectRndHits(segmax);
2944 bool changed =
false;
2945 for (
auto h : fHits) {
2946 changed |= !(
h->IsEnabled());
2947 h->SetEnabled(
true);
2955 for (
auto n : fNodes)
2956 n->ClearAssigned(
this);
2957 for (
auto s : fSegments)
2958 s->ClearAssigned(
this);
2962 bool skipFrontVtx =
false, skipBackVtx =
false;
2965 if (!(fNodes.front()->IsFrozen()) && !(fNodes.front()->Prev()) &&
2966 (fNodes.front()->NextCount() == 1)) {
2967 skipFrontVtx =
true;
2969 if (!(fNodes.front()->IsFrozen()) && (fNodes.back()->NextCount() == 0)) { skipBackVtx =
true; }
2971 for (
auto h : fHits)
2973 pe = GetNearestElement(
h->Point2D(),
h->View2D(),
h->TPC(), skipFrontVtx, skipBackVtx);
2977 for (
auto p : fAssignedPoints)
2979 pe = GetNearestElement(*
p);
2983 for (
auto n : fNodes)
2984 n->UpdateHitParams();
2985 for (
auto s : fSegments)
2986 s->UpdateHitParams();
2992 std::vector<std::pair<pma::Hit3D*, pma::Element3D*>> assignments;
2993 assignments.reserve(fHits.size());
2995 for (
auto hi : fHits) {
2998 for (
auto s : fSegments) {
2999 for (
size_t j = 0; j <
s->NHits(); ++j)
3000 if (hi ==
s->Hits()[j])
3003 double min_d2 =
s->GetDistance2To(hi->Point2D(), hi->View2D());
3004 int const tpc = hi->TPC();
3007 if (nnext->
TPC() == tpc) {
3008 double const d2 = nnext->
GetDistance2To(hi->Point2D(), hi->View2D());
3015 if (snext && (snext->
TPC() == tpc)) {
3016 double const d2 = snext->
GetDistance2To(hi->Point2D(), hi->View2D());
3023 if (nnext->
TPC() == tpc) {
3024 double const d2 = nnext->
GetDistance2To(hi->Point2D(), hi->View2D());
3034 if (nprev->
TPC() == tpc) {
3035 double const d2 = nprev->
GetDistance2To(hi->Point2D(), hi->View2D());
3042 if (sprev && (sprev->
TPC() == tpc)) {
3043 double const d2 = sprev->
GetDistance2To(hi->Point2D(), hi->View2D());
3050 if (nprev->
TPC() == tpc) {
3051 double const d2 = nprev->
GetDistance2To(hi->Point2D(), hi->View2D());
3067 for (
auto n : fNodes) {
3068 for (
size_t j = 0; j <
n->NHits(); ++j)
3069 if (hi ==
n->Hits()[j])
3072 double d2, min_d2 =
n->GetDistance2To(hi->Point2D(), hi->View2D());
3073 int tpc = hi->TPC();
3076 if (snext && (snext->
TPC() == tpc)) {
3084 if (nnext->
TPC() == tpc) {
3091 snext = NextSegment(nnext);
3092 if (snext && (snext->
TPC() == tpc)) {
3103 if (sprev && (sprev->
TPC() == tpc)) {
3111 if (nprev->
TPC() == tpc) {
3118 sprev = PrevSegment(nprev);
3119 if (sprev && (sprev->
TPC() == tpc)) {
3136 assignments.emplace_back(hi, pe);
3138 mf::LogWarning(
"pma::Track3D") <<
"Hit was not assigned to any element.";
3141 for (
auto const&
a : assignments)
3142 a.second->AddHit(
a.first);
3144 for (
auto n : fNodes)
3145 n->UpdateHitParams();
3146 for (
auto s : fSegments)
3147 s->UpdateHitParams();
3153 for (
auto n : fNodes)
3154 n->UpdateProjection();
3155 for (
auto s : fSegments)
3156 s->UpdateProjection();
3163 unsigned int count = 0;
3165 for (
auto n : fNodes) {
3166 sum +=
n->SumDist2();
3167 count +=
n->NEnabledHits();
3170 for (
auto s : fSegments) {
3171 sum +=
s->SumDist2();
3172 count +=
s->NEnabledHits();
3175 if (count) {
return sum /
count; }
3177 mf::LogError(
"pma::Track3D") <<
"0 enabled hits in AverageDist2 calculation.";
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);
3198 fSegStopValue = (int)(fSegStopFactor * nCubeRoot * fHitsRadius / avgDist2Root);
3199 if (fSegStopValue < fMinSegStop) fSegStopValue = fMinSegStop;
3212 if (v0 == v1)
return false;
3226 fNodes[v1]->RemoveNext(nextSeg);
3230 fNodes[v0] = fNodes[v1];
3233 if (prevSeg) prevSeg->
AddNext(fNodes[v0]);
3234 fNodes[v0]->AddNext(midSeg);
3236 if (nextSeg) fNodes[v1]->AddNext(nextSeg);
3242 fNodes[v0] = fNodes[v1];
3251 unsigned int v1, v2;
3254 if (fSegments.front()->IsFrozen())
return false;
3255 if (fNodes.front()->NextCount() > 1)
return false;
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;
3265 default:
return false;
3267 if (fNodes[v1]->
TPC() != fNodes[v2]->
TPC())
return false;
3269 double g1, g0 = GetObjFunction();
3271 if (SwapVertices(v1, v2)) RebuildSegments();
3273 g1 = GetObjFunction();
3276 if (SwapVertices(v1, v2)) RebuildSegments();
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;
bool SelectHits(float fraction=1.0F)
void ApplyDriftShift(double dx)
void AddHits(detinfo::DetectorPropertiesData const &detProp, const std::vector< art::Ptr< recob::Hit >> &hits)
void MakeFastProjection()
process_name opflash particleana ie ie ie z
TVector3 const & Point3D() const
float Length(const PFPStruct &pfp)
void AutoFlip(pma::Track3D::EDirection dir, double thr=0.0, unsigned int n=0)
bool HasTPC(int tpc) const
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
Implementation of the Projection Matching Algorithm.
bool IsAttachedTo(pma::Track3D const *trk) const
process_name opflash particleana ie x
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.
int PrevHit(int index, unsigned int view=geo::kZ, bool inclDisabled=false) const
double GetXTicksCoefficient(int t, int c) const
void ApplyDriftShiftInTree(const detinfo::DetectorClocksData &clockData, detinfo::DetectorPropertiesData const &detProp, double dx, bool skipFirst=false)
float PeakTime() const noexcept
void ClearAssigned(pma::Track3D *trk=0) override
void AddPoint(TVector3 *p)
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.
::fhicl::TupleAs< Point(::geo::Length_t,::geo::Length_t,::geo::Length_t)> Point3D
Atom object for reading a 3D point or vector (centimeters).
BEGIN_PROLOG opflashtpc1 TPCs
Geometry information for a single TPC.
void ReassignHitsInTree(pma::Track3D *plRoot=nullptr)
int index_of(const pma::Hit3D *hit) const
bool AttachBackToSameTPC(pma::Node3D *vStart)
bool GetBranches(std::vector< pma::Track3D const * > &branches, bool skipFirst=false) const
virtual unsigned int NextCount(void) const
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)
double GetObjFunction(float penaltyFactor=1.0F) const
Objective function optimized in track reconstruction.
double TriggerOffsetTPC() const
TVector3 const & Point3D() const
bool Initialize(detinfo::DetectorPropertiesData const &detProp, float initEndSegW=0.05F)
std::size_t size(FixedBins< T, C > const &) noexcept
void Optimize(float penaltyValue, float endSegWeight)
Planes which measure Z direction.
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
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)
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.
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)
unsigned int NEnabledHits(unsigned int view=geo::kUnknown) const
int TPC(void) const
TPC index or -1 if out of any TPC.
std::vector< unsigned int > Cryos() const
constexpr double TickPeriod() const noexcept
A single tick period in microseconds.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
pma::Track3D * Split(detinfo::DetectorPropertiesData const &detProp, size_t idx, bool try_start_at_idx=true)
double TestHitsMse(detinfo::DetectorPropertiesData const &detProp, const std::vector< art::Ptr< recob::Hit >> &hits, bool normalized=true) const
MSE of 2D hits.
bool UpdateParamsInTree(bool skipFirst, size_t &depth)
bool CanFlip() const
Check if the track can be flipped without breaking any other track.
size_t NPoints(void) const
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)
bool isfinite(Vector const &v)
Returns whether all components of the vector are finite.
unsigned int NHits(unsigned int view) const
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.
virtual int RemoveNext(pma::SortedObjectBase *nextElement)
unsigned int View2D() const noexcept
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
double GetDriftShift() const
bool HasRefPoint(TVector3 *p) const
auto end(FixedBins< T, C > const &) noexcept
bool InitFromRefPoints(detinfo::DetectorPropertiesData const &detProp, int tpc, int cryo)
std::vector< float > DriftsOfWireIntersection(detinfo::DetectorPropertiesData const &detProp, unsigned int wire, unsigned int view) const
bool SetPoint3D(const TVector3 &p3d)
void SetT0FromDx(const detinfo::DetectorClocksData &clockData, detinfo::DetectorPropertiesData const &detProp, double dx)
Function to convert dx into dT0.
pma::Hit3D & Hit(size_t index)
void SetEnabled(bool state) noexcept
void RemoveHits(const std::vector< art::Ptr< recob::Hit >> &hits)
Remove hits; removes also hit->node/seg assignments.
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.
double GetObjFnInTree(bool skipFirst=false)
void InternalFlip(std::vector< pma::Track3D * > &toSort)
bool erase(const art::Ptr< recob::Hit > &hit)
unsigned int DisableSingleViewEnds()
double GetDistance2To(const TVector3 &p3d) const override
Distance [cm] from the 3D point to the point 3D.
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
bool SelectRndHits(size_t segmax, size_t vtxmax)
size_t CompleteMissingWires(detinfo::DetectorPropertiesData const &detProp, unsigned int view)
double ConvertTicksToX(double ticks, int p, int t, int c) const
void InitFromMiddle(detinfo::DetectorPropertiesData const &detProp, int tpc, int cryo)
void push_back(pma::Hit3D *hit)
TVector2 const & Point2D() const noexcept
double AverageDist2() const
bool HasTwoViews(size_t nmin=1) const
int Cryo(void) const
Cryostat index or -1 if out of any cryostat.
void CleanupTails()
Cut out tails with no hits assigned.
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
void MakeProjectionInTree(bool skipFirst=false)
std::map< size_t, std::vector< double > > dedx_map
unsigned int Cryo() const noexcept
virtual pma::SortedObjectBase * Next(unsigned int index=0) const
double Length(size_t step=1) const
bool IsFrozen(void) const
Check if the vertex 3D position is fixed.
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
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
double GetDistToProj() const
int NextHit(int index, unsigned int view=geo::kZ, bool inclDisabled=false) const
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
void AddHit(pma::Hit3D *h)
bool SwapVertices(size_t v0, size_t v1)
virtual void Disconnect(void)
unsigned int Wire() const noexcept
pma::Track3D * GetNearestTrkInTree(const TVector3 &p3d_cm, double &dist, bool skipFirst=false)
virtual bool AddNext(pma::SortedObjectBase *nextElement)
std::size_t count(Cont const &cont)
virtual pma::SortedObjectBase * Prev(void) const
bool Flip(const detinfo::DetectorPropertiesData &detProp, std::vector< pma::Track3D * > &allTracks)
pma::Track3D * Parent(void) const
virtual pma::SortedObjectBase * Next(unsigned int index=0) const
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
physics associatedGroupsWithLeft p1
art framework interface to geometry description
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
float SummedADC() const noexcept
std::vector< pma::Hit3D * > fHits