9 #include "messagefacility/MessageLogger/MessageLogger.h"
27 using namespace detail;
39 if (slc.
tjs.size() < 2)
return;
42 constexpr
float maxSep = 4;
47 mf::LogVerbatim(
"TC") <<
"MakeJunkVertices: prt set for plane " << planeID.
Plane
48 <<
" maxSep btw tjs " << maxSep;
58 junkVx.
ID = USHRT_MAX;
60 junkVx.
PosErr = {{2.0, 2.0}};
65 for (
unsigned short it1 = 0; it1 < slc.
tjs.size() - 1; ++it1) {
66 auto& tj1 = slc.
tjs[it1];
68 if (tj1.SSID > 0 || tj1.AlgMod[
kShowerLike])
continue;
69 if (tj1.CTP != inCTP)
continue;
70 if (tj1.AlgMod[
kJunkTj])
continue;
72 if (tj1.MCSMom < 100)
continue;
73 for (
unsigned short end1 = 0; end1 < 2; ++end1) {
75 if (tj1.VtxID[end1] > 0)
continue;
76 auto& tp1 = tj1.Pts[tj1.EndPt[end1]];
79 if (tjlist.empty())
continue;
81 junkVx.
ID = USHRT_MAX;
82 for (
auto tj2id : tjlist) {
83 auto& tj2 = slc.
tjs[tj2id - 1];
84 if (tj2.CTP != inCTP)
continue;
85 if (tj2id == tj1.ID)
continue;
86 if (tj2.SSID > 0 || tj2.AlgMod[
kShowerLike])
continue;
88 unsigned short closeEnd = USHRT_MAX;
89 for (
unsigned short end2 = 0; end2 < 2; ++end2) {
90 auto& tp2 = tj2.Pts[tj2.EndPt[end2]];
91 float sep =
PosSep(tp1.Pos, tp2.Pos);
97 if (closeEnd > 1)
continue;
98 auto& tp2 = tj2.Pts[tj2.EndPt[closeEnd]];
100 if (!signalBetween)
continue;
101 if (junkVx.
ID == USHRT_MAX) {
103 junkVx.
ID = slc.
vtxs.size() + 1;
104 junkVx.
Pos = tp1.Pos;
106 tj2.VtxID[closeEnd] = junkVx.
ID;
107 tj1.VtxID[end1] = junkVx.
ID;
109 if (junkVx.
ID == USHRT_MAX)
continue;
111 mf::LogVerbatim(
"TC") <<
"MJV: StoreVertex failed";
112 for (
auto& tj : slc.
tjs) {
113 if (tj.AlgMod[
kKilled])
continue;
114 if (tj.VtxID[0] == junkVx.
ID) tj.VtxID[0] = 0;
115 if (tj.VtxID[1] == junkVx.
ID) tj.VtxID[1] = 0;
120 mf::LogVerbatim(
"TC") <<
" New junk 2V" << junkVx.
ID <<
" at " << std::fixed
121 << std::setprecision(1) << junkVx.
Pos[0] <<
":"
124 junkVx.
ID = USHRT_MAX;
156 if (slc.
tjs.size() < 2)
return;
158 bool firstPassCuts = (pass == 0);
163 bool requireVtxTjChg =
true;
168 mf::LogVerbatim(
"TC") <<
"prt set for CTP " << inCTP <<
" in Find2DVertices. firstPassCuts? "
169 << firstPassCuts <<
" requireVtxTjChg " << requireVtxTjChg;
174 for (
unsigned short it1 = 0; it1 < slc.
tjs.size() - 1; ++it1) {
175 auto& tj1 = slc.
tjs[it1];
177 if (tj1.SSID > 0 || tj1.AlgMod[
kShowerLike])
continue;
178 if (tj1.CTP != inCTP)
continue;
179 bool tj1Short = (
TrajLength(tj1) < maxShortTjLen);
180 for (
unsigned short end1 = 0; end1 < 2; ++end1) {
182 if (tj1.VtxID[end1] > 0)
continue;
184 if (tj1.PDGCode == 111 && end1 != tj1.StartEnd)
continue;
187 short endPt1 = tj1.EndPt[end1];
188 float wire1 = tj1.Pts[endPt1].Pos[0];
192 if (tj1.Pts.size() > 6 && tj1.Pts[endPt1].NTPsFit < 4) {
193 if (end1 == 0 && endPt1 <
int(tj1.Pts.size()) - 3) { endPt1 += 3; }
194 else if (end1 == 1 && endPt1 >= 3) {
203 endPt1 = tj1.EndPt[end1];
204 short oendPt1 = tj1.EndPt[1 - end1];
206 auto& otp1 = tj1.Pts[oendPt1];
207 for (
unsigned short it2 = it1 + 1; it2 < slc.
tjs.size(); ++it2) {
208 auto& tj2 = slc.
tjs[it2];
210 if (tj2.SSID > 0 || tj2.AlgMod[
kShowerLike])
continue;
211 if (tj2.CTP != inCTP)
continue;
212 if (tj1.VtxID[end1] > 0)
continue;
214 bool tj2Short = (
TrajLength(tj2) < maxShortTjLen);
216 unsigned short end2 = 0;
217 if (
PosSep2(tj2.Pts[tj2.EndPt[1]].Pos, tp1.
Pos) <
220 if (tj2.VtxID[end2] > 0)
continue;
222 if (tj2.PDGCode == 111 && end2 != tj2.StartEnd)
continue;
224 if (tj1.VtxID[1 - end1] > 0 && tj1.VtxID[1 - end1] == tj2.VtxID[1 - end2])
continue;
226 unsigned short oendPt2 = tj2.EndPt[1 - end2];
227 auto& otp2 = tj2.Pts[oendPt2];
228 if (
PosSep2(otp1.Pos, otp2.Pos) <
PosSep2(tp1.
Pos, tj2.Pts[tj2.EndPt[end2]].Pos))
230 short endPt2 = tj2.EndPt[end2];
231 float wire2 = tj2.Pts[endPt2].Pos[0];
232 if (tj2.Pts.size() > 6 && tj2.Pts[endPt2].NTPsFit < 4) {
233 if (end2 == 0 && endPt2 <
int(tj2.Pts.size()) - 3) { endPt2 += 3; }
234 else if (end2 == 1 && endPt2 >= 3) {
242 endPt2 = tj2.EndPt[end2];
254 if (tj1Short || tj2Short) { sepCut =
tcc.
vtx2DCuts[1]; }
268 if (prt && vt1Sep < 200 && vt2Sep < 200) {
269 mf::LogVerbatim myprt(
"TC");
270 myprt <<
"F2DV candidate T" << tj1.ID <<
"_" << end1 <<
"-T" << tj2.ID <<
"_" << end2;
271 myprt <<
" vtx pos " << (int)wint <<
":" << (
int)(tint /
tcc.
unitsPerTick) <<
" tp1 "
273 myprt <<
" dwc1 " << dwc1 <<
" dwc2 " << dwc2 <<
" on dead wire? " << vtxOnDeadWire;
274 myprt <<
" vt1Sep " << vt1Sep <<
" vt2Sep " << vt2Sep <<
" sepCut " << sepCut;
276 if (vt1Sep > sepCut || vt2Sep > sepCut)
continue;
278 if (
PosSep(vPos, slc.
tjs[it1].Pts[oendPt1].Pos) < vt1Sep) {
280 mf::LogVerbatim(
"TC") <<
" tj1 other end " <<
PrintPos(slc, tj1.Pts[oendPt1])
281 <<
" is closer to the vertex";
284 if (
PosSep(vPos, slc.
tjs[it2].Pts[oendPt2].Pos) < vt2Sep) {
286 mf::LogVerbatim(
"TC") <<
" tj2 other end " <<
PrintPos(slc, tj2.Pts[oendPt2])
287 <<
" is closer to the vertex";
291 unsigned short closePt1;
292 float doca1 = sepCut;
297 short dpt1 = stepDir * (closePt1 - endPt1);
299 mf::LogVerbatim(
"TC") <<
" endPt1 " << endPt1 <<
" closePt1 " << closePt1 <<
" dpt1 "
300 << dpt1 <<
" doca1 " << doca1;
301 if (dpt1 < -1)
continue;
302 if (slc.
tjs[it1].EndPt[1] > 4) {
303 if (dpt1 > 3)
continue;
307 if (dpt1 > 2)
continue;
309 unsigned short closePt2;
310 float doca2 = sepCut;
312 short dpt2 = stepDir * (closePt2 - endPt2);
314 mf::LogVerbatim(
"TC") <<
" endPt2 " << endPt2 <<
" closePt2 " << closePt2 <<
" dpt2 "
315 << dpt2 <<
" doca2 " << doca2;
316 if (dpt2 < -1)
continue;
317 if (slc.
tjs[it2].EndPt[1] > 4) {
318 if (dpt2 > 3)
continue;
322 if (dpt2 > 2)
continue;
324 bool fixVxPos =
false;
326 if (tj1.EndFlag[end1][
kAtKink]) fixVxPos =
true;
328 mf::LogVerbatim(
"TC") <<
" wint:tint " << (int)wint <<
":"
330 if (requireVtxTjChg) {
332 bool signalBetween =
true;
333 short dpt =
abs(wint - tp1.
Pos[0]);
335 if (prt) mf::LogVerbatim(
"TC") <<
" Fails SignalBetween for tp1 " << dpt;
336 signalBetween =
false;
338 dpt =
abs(wint - tp2.
Pos[0]);
340 if (prt) mf::LogVerbatim(
"TC") <<
" Fails SignalBetween for tp2 " << dpt;
341 signalBetween =
false;
345 if (!signalBetween) {
346 unsigned short ipt1, ipt2;
348 bool isClose =
TrajTrajDOCA(slc, tj1, tj2, ipt1, ipt2, maxSep,
false);
350 if (isClose) isClose = (
abs(ipt1 - endPt1) < 4 &&
abs(ipt2 - endPt2) < 4);
353 mf::LogVerbatim(
"TC")
354 <<
" TrajTrajDOCA are close with minSep " << maxSep <<
" near "
355 <<
PrintPos(slc, tj1.Pts[ipt1].Pos) <<
" " <<
PrintPos(slc, tj2.Pts[ipt2].Pos);
368 mf::LogVerbatim(
"TC")
369 <<
" new wint:tint " << (int)wint <<
":" << (
int)(tint /
tcc.
unitsPerTick);
382 aVtx.
Pass = tj1.Pass;
384 aVtx.
Topo = 2 * end1;
393 unsigned short newVtxID = slc.
vtxs.size() + 1;
395 tj1.VtxID[end1] = newVtxID;
396 tj2.VtxID[end2] = newVtxID;
405 if (prt) mf::LogVerbatim(
"TC") <<
" Merged with close vertex " << mergeMeWithVx;
411 mf::LogVerbatim myprt(
"TC");
412 myprt <<
" New vtx 2V" << aVtx.
ID;
413 myprt <<
" Tjs " << tj1.ID <<
"_" << end1 <<
"-" << tj2.ID <<
"_" << end2;
414 myprt <<
" at " << std::fixed << std::setprecision(1) << aVtx.
Pos[0] <<
":"
424 if (pass == USHRT_MAX) {
429 if (prt)
PrintAllTraj(detProp,
"F2DVo", slc, USHRT_MAX, USHRT_MAX);
447 if (oVxID > slc.
vtxs.size())
return false;
448 auto& oVx = slc.
vtxs[oVxID - 1];
449 if (vx.
CTP != oVx.CTP)
return false;
453 if (tjlist.empty())
return false;
455 if (tmp.empty())
return false;
456 for (
auto tjid : tmp) {
457 if (std::find(tjlist.begin(), tjlist.end(), tjid) == tjlist.end()) tjlist.push_back(tjid);
459 if (tjlist.size() < 2)
return false;
461 if (tjlist.size() == 2) {
466 for (
auto tjid : tjlist) {
467 auto& tj = slc.
tjs[tjid - 1];
468 for (
unsigned short end = 0;
end < 2; ++
end) {
469 if (tj.VtxID[
end] == vx.
ID) tj.VtxID[
end] = oVx.ID;
474 mf::LogVerbatim(
"TC") <<
"MWV: merge failed " << vx.
ID <<
" and existing " << oVx.ID;
481 std::vector<SortEntry> sortVec(tjlist.size());
482 for (
unsigned int indx = 0; indx < sortVec.size(); ++indx) {
483 sortVec[indx].index = indx;
484 auto& tj = slc.
tjs[tjlist[indx] - 1];
485 sortVec[indx].val = tj.Pts.size();
490 for (
unsigned short ii = 0; ii < sortVec.size(); ++ii)
491 tjlist[ii] = ttl[sortVec[ii].index];
496 std::vector<TrajPoint> tjpts(tjlist.size());
500 std::array<float, 2> vpos;
501 vpos[0] = 0.5 * (vx.
Pos[0] + oVx.Pos[0]);
502 vpos[1] = 0.5 * (vx.
Pos[1] + oVx.Pos[1]);
503 for (
unsigned short ii = 0; ii < tjpts.size(); ++ii) {
504 auto& tj = slc.
tjs[tjlist[ii] - 1];
508 unsigned short endPt = tj.EndPt[
end];
509 if (npwc > 6 && tj.Pts[endPt].NTPsFit < 4) {
510 if (end == 0) { endPt += 3; }
516 if (endPt < tj.EndPt[0]) endPt = tj.EndPt[0];
517 if (endPt > tj.EndPt[1]) endPt = tj.EndPt[1];
519 tjpts[ii].CTP = tj.CTP;
520 tjpts[ii].Pos = tj.Pts[endPt].Pos;
521 tjpts[ii].Dir = tj.Pts[endPt].Dir;
522 tjpts[ii].Ang = tj.Pts[endPt].Ang;
523 tjpts[ii].AngErr = tj.Pts[endPt].AngErr;
525 tjpts[ii].Step = endPt;
527 tjpts[ii].AngleCode =
end;
529 tjpts[ii].Hits.resize(1, tj.ID);
532 mf::LogVerbatim myprt(
"TC");
533 myprt <<
"MWV: " << oVxID;
535 for (
unsigned short ii = 0; ii < tjpts.size(); ++ii) {
536 auto& tjpt = tjpts[ii];
537 myprt <<
" " << tjlist[ii] <<
"_" << tjpt.Step <<
"_" <<
PrintPos(slc, tjpt.Pos);
544 if (prt) mf::LogVerbatim(
"TC") <<
"MWV: first fit failed ";
548 bool needsUpdate =
false;
549 for (
unsigned short ii = 2; ii < tjlist.size(); ++ii) {
550 fitpts.push_back(tjpts[ii]);
551 if (
FitVertex(slc, aVx, fitpts, prt)) { needsUpdate =
false; }
559 if (needsUpdate)
FitVertex(slc, aVx, fitpts, prt);
560 if (prt) mf::LogVerbatim(
"TC") <<
"MWV: done " << vx.
ID <<
" and existing " << oVx.ID;
563 for (
auto& tj : slc.
tjs) {
565 if (tj.CTP != vx.
CTP)
continue;
566 for (
unsigned short end = 0;
end < 2; ++
end) {
567 if (tj.VtxID[
end] == vx.
ID) tj.VtxID[
end] = 0;
568 if (tj.VtxID[
end] == oVxID) tj.VtxID[
end] = 0;
572 for (
unsigned short ii = 0; ii < fitpts.size(); ++ii) {
573 auto& tjpt = fitpts[ii];
574 unsigned short end = tjpt.AngleCode;
575 auto& tj = slc.
tjs[tjpt.Hits[0] - 1];
576 if (tj.VtxID[end] != 0)
return false;
577 tj.VtxID[
end] = oVxID;
584 oVx.NTraj = fitpts.size();
590 mf::LogVerbatim myprt(
"TC");
591 myprt <<
"MWV: " << oVxID;
592 myprt <<
" Done TPs";
593 for (
unsigned short ii = 0; ii < fitpts.size(); ++ii) {
594 auto& tjpt = fitpts[ii];
595 myprt <<
" " << tjpt.Hits[0] <<
"_" << tjpt.AngleCode <<
"_" <<
PrintPos(slc, tjpt.Pos);
621 if (prt) mf::LogVerbatim(
"TC") <<
"Inside HamVx2";
623 for (
unsigned short it1 = 0; it1 < slc.
tjs.size(); ++it1) {
624 if (slc.
tjs[it1].CTP != inCTP)
continue;
626 if (slc.
tjs[it1].AlgMod[
kHamVx])
continue;
629 if (slc.
tjs[it1].PDGCode == 111)
continue;
631 if (numPtsWithCharge1 < 6)
continue;
633 if (slc.
tjs[it1].MCSMom < 200)
continue;
635 bool didaSplit =
false;
636 for (
unsigned short end1 = 0; end1 < 2; ++end1) {
638 if (slc.
tjs[it1].VtxID[end1] > 0)
continue;
639 unsigned short endPt1 = slc.
tjs[it1].EndPt[end1];
640 for (
unsigned short it2 = 0; it2 < slc.
tjs.size(); ++it2) {
641 if (it1 == it2)
continue;
642 if (slc.
tjs[it2].AlgMod[
kKilled] || slc.
tjs[it2].AlgMod[kHaloTj])
continue;
643 if (slc.
tjs[it2].AlgMod[kHamVx])
continue;
644 if (slc.
tjs[it2].AlgMod[kHamVx2])
continue;
646 if (slc.
tjs[it2].CTP != inCTP)
continue;
648 if (slc.
tjs[it2].AlgMod[kJunkTj])
continue;
649 if (slc.
tjs[it2].PDGCode == 111)
continue;
651 if (numPtsWithCharge2 < 6)
continue;
653 if (numPtsWithCharge2 > 100 && slc.
tjs[it2].MCSMom > 500)
continue;
656 float doca = minDOCA;
657 unsigned short closePt2 = 0;
659 if (doca == minDOCA)
continue;
661 mf::LogVerbatim myprt(
"TC");
662 auto& tj1 = slc.
tjs[it1];
663 auto& tj2 = slc.
tjs[it2];
664 myprt <<
" FHV2 CTP" << tj1.CTP;
665 myprt <<
" t" << tj1.ID <<
"_" << end1 <<
" MCSMom " << tj1.MCSMom <<
" ChgRMS "
667 myprt <<
" split t" << tj2.ID <<
"? MCSMom " << tj2.MCSMom <<
" ChgRMS " << tj2.ChgRMS;
668 myprt <<
" doca " << doca <<
" tj2.EndPt[0] " << tj2.EndPt[0] <<
" closePt2 "
670 myprt <<
" tj2.EndPt[1] " << tj2.EndPt[1];
673 if (closePt2 < slc.
tjs[it2].EndPt[0] + 3)
continue;
674 if (closePt2 > slc.
tjs[it2].EndPt[1] - 3)
continue;
679 float dang =
DeltaAngle(slc.
tjs[it1].Pts[endPt1].Ang, slc.
tjs[it2].Pts[closePt2].Ang);
680 if (dang < 0.2)
continue;
683 unsigned short closePt1 = 0;
685 if (closePt1 != endPt1)
continue;
687 mf::LogVerbatim(
"TC") <<
" intersection W:T " << (int)wint <<
":"
692 unsigned short intPt2;
695 mf::LogVerbatim(
"TC") <<
" intPt2 on tj2 " << intPt2 <<
" at Pos "
696 <<
PrintPos(slc, slc.
tjs[it2].Pts[intPt2]) <<
" doca " << doca;
697 if (doca == minDOCA)
continue;
699 float mcsmom = slc.
tjs[it2].MCSMom;
700 float mcsmom1 =
MCSMom(slc, slc.
tjs[it2], slc.
tjs[it2].EndPt[0], intPt2);
701 float mcsmom2 =
MCSMom(slc, slc.
tjs[it2], intPt2, slc.
tjs[it2].EndPt[1]);
704 mf::LogVerbatim(
"TC") <<
" Check MCSMom after split: mcsmom1 " << mcsmom1 <<
" mcsmom2 "
706 if (mcsmom1 < mcsmom || mcsmom2 < mcsmom)
continue;
710 if (intPt2 < closePt2) dir = -1;
711 unsigned short nit = 0;
712 unsigned short ipt = intPt2;
713 float mostChg = slc.
tjs[it2].Pts[ipt].Chg;
715 mf::LogVerbatim(
"TC") <<
" ipt " << ipt <<
" at Pos "
716 <<
PrintPos(slc, slc.
tjs[it2].Pts[ipt]) <<
" chg " << mostChg;
719 if (ipt < 3 || ipt > slc.
tjs[it2].Pts.size() - 4)
break;
721 slc.
tjs[it2].Pts[ipt].Pos[0],
722 slc.
tjs[it2].Pts[ipt].Pos[1],
723 slc.
tjs[it1].Pts[endPt1]);
724 float sep =
PosSep(slc.
tjs[it2].Pts[ipt].Pos, slc.
tjs[it1].Pts[endPt1].Pos);
725 float dang = delta / sep;
726 float pull = dang / slc.
tjs[it1].Pts[endPt1].DeltaRMS;
727 if (pull < 2 && slc.
tjs[it2].Pts[ipt].Chg > mostChg) {
728 mostChg = slc.
tjs[it2].Pts[ipt].Chg;
733 float chgPull = (mostChg - slc.
tjs[it2].AveChg) / slc.
tjs[it2].ChgRMS;
734 if (prt) mf::LogVerbatim(
"TC") <<
" chgPull at intersection point " << chgPull;
735 if (chgPull < 10)
continue;
738 if (slc.
tjs[it1].Pts[endPt1].Pos[0] < -0.4)
continue;
739 unsigned int fromWire = std::nearbyint(slc.
tjs[it1].Pts[endPt1].Pos[0]);
740 if (slc.
tjs[it2].Pts[intPt2].Pos[0] < -0.4)
continue;
741 unsigned int toWire = std::nearbyint(slc.
tjs[it2].Pts[intPt2].Pos[0]);
742 if (fromWire > toWire) {
743 unsigned int tmp = fromWire;
748 for (
unsigned int wire = fromWire + 1; wire < toWire; ++wire) {
755 if (skipIt)
continue;
759 aVtx.
Pos = slc.
tjs[it2].Pts[intPt2].Pos;
765 aVtx.
ID = slc.
vtxs.size() + 1;
766 unsigned short ivx = slc.
vtxs.size();
768 if (!
SplitTraj(slc, it2, intPt2, ivx, prt)) {
769 if (prt) mf::LogVerbatim(
"TC") <<
"FHV2: Failed to split trajectory";
773 slc.
tjs[it1].VtxID[end1] = slc.
vtxs[ivx].ID;
776 unsigned short newTjIndex = slc.
tjs.size() - 1;
785 mf::LogVerbatim(
"TC") <<
" FHV2: New vtx 2V" << slc.
vtxs[ivx].ID <<
" Score "
786 << slc.
vtxs[ivx].Score;
790 if (didaSplit)
break;
811 if (prt) { mf::LogVerbatim(
"TC") <<
"Inside HamVx inCTP " << inCTP; }
813 for (
unsigned short it1 = 0; it1 < slc.
tjs.size(); ++it1) {
814 if (slc.
tjs[it1].CTP != inCTP)
continue;
818 if (slc.
tjs[it1].PDGCode == 111)
continue;
820 unsigned short tj1len = slc.
tjs[it1].EndPt[1] - slc.
tjs[it1].EndPt[0] + 1;
821 if (tj1len < 5)
continue;
823 if (slc.
tjs[it1].MCSMom < 50)
continue;
824 if (prt) mf::LogVerbatim(
"TC") <<
"FHV: intersection T" << slc.
tjs[it1].ID <<
" candidate";
826 bool didaSplit =
false;
827 for (
unsigned short end1 = 0; end1 < 2; ++end1) {
829 if (slc.
tjs[it1].VtxID[end1] > 0)
continue;
830 unsigned short endPt1 = slc.
tjs[it1].EndPt[end1];
831 for (
unsigned short it2 = 0; it2 < slc.
tjs.size(); ++it2) {
832 if (slc.
tjs[it2].CTP != inCTP)
continue;
833 if (it1 == it2)
continue;
834 if (slc.
tjs[it2].AlgMod[
kKilled] || slc.
tjs[it2].AlgMod[kHaloTj])
continue;
835 if (slc.
tjs[it2].AlgMod[kJunkTj])
continue;
836 if (slc.
tjs[it2].PDGCode == 111)
continue;
838 unsigned short tj2len = slc.
tjs[it2].EndPt[1] - slc.
tjs[it2].EndPt[0] + 1;
839 if (tj2len < 6)
continue;
841 if (tj2len > 200 && slc.
tjs[it2].PDGCode == 13 && slc.
tjs[it2].MCSMom > 600)
continue;
843 minDOCA /=
std::abs(slc.
tjs[it1].Pts[endPt1].Dir[0]);
844 float doca = minDOCA;
845 unsigned short closePt2 = 0;
847 if (doca == minDOCA)
continue;
850 mf::LogVerbatim(
"TC") <<
"FHV: Candidate T" << slc.
tjs[it1].ID <<
" T"
851 << slc.
tjs[it2].ID <<
" doca " << doca <<
" tj2.EndPt[0] "
852 << slc.
tjs[it2].EndPt[0] <<
" closePt2 " << closePt2
853 <<
" tj2.EndPt[1] " << slc.
tjs[it2].EndPt[1];
854 if (closePt2 < slc.
tjs[it2].EndPt[0] + 3)
continue;
855 if (closePt2 > slc.
tjs[it2].EndPt[1] - 3)
continue;
857 float dang =
DeltaAngle(slc.
tjs[it1].Pts[endPt1].Ang, slc.
tjs[it2].Pts[closePt2].Ang);
859 mf::LogVerbatim(
"TC") <<
" dang " << dang <<
" imposing a hard cut of 0.4 for now ";
860 if (dang < 0.4)
continue;
862 std::vector<int> tjids(2);
863 tjids[0] = slc.
tjs[it1].ID;
864 tjids[1] = slc.
tjs[it2].ID;
866 if (prt) mf::LogVerbatim(
"TC") <<
" chgFrac " << chgFrac;
867 if (chgFrac < 0.9)
continue;
871 slc.
tjs[it1].Pts[endPt1], slc.
tjs[it2].Pts[closePt2], vxpos[0], vxpos[1]);
876 mf::LogVerbatim(
"TC") <<
" better pos " <<
PrintPos(slc, vxpos) <<
" new closePt2 "
886 aVtx.
ID = slc.
vtxs.size() + 1;
888 unsigned short ivx = slc.
vtxs.size() - 1;
889 if (!
SplitTraj(slc, it2, closePt2, ivx, prt)) {
890 if (prt) mf::LogVerbatim(
"TC") <<
"FHV: Failed to split trajectory";
894 slc.
tjs[it1].VtxID[end1] = slc.
vtxs[ivx].ID;
897 unsigned short newTjIndex = slc.
tjs.size() - 1;
898 slc.
tjs[newTjIndex].AlgMod[
kHamVx] =
true;
905 auto& vx2 = slc.
vtxs[ivx];
906 mf::LogVerbatim myprt(
"TC");
907 myprt <<
" new 2V" << vx2.ID <<
" Score " << vx2.Score <<
" Tjs";
908 auto tjlist =
GetAssns(slc,
"2V", vx2.
ID,
"T");
909 for (
auto tid : tjlist)
910 myprt <<
" t" << tid;
915 if (didaSplit)
break;
929 if (slc.
vtxs.empty())
return;
930 if (slc.
tjs.empty())
return;
932 constexpr
float docaCut = 4;
935 if (prt) mf::LogVerbatim(
"TC") <<
"Inside SplitTrajCrossingVertices inCTP " << inCTP;
939 unsigned short nTraj = slc.
tjs.size();
940 for (
unsigned short itj = 0; itj < nTraj; ++itj) {
942 if (slc.
tjs[itj].CTP != inCTP)
continue;
948 if (slc.
tjs[itj].EndPt[1] < 6)
continue;
949 for (
unsigned short iv = 0; iv < slc.
vtxs.size(); ++iv) {
950 auto& vx2 = slc.
vtxs[iv];
952 if (vx2.NTraj == 0)
continue;
954 if (slc.
tjs[itj].VtxID[0] == vx2.ID || slc.
tjs[itj].VtxID[1] == vx2.ID)
continue;
956 if (slc.
tjs[itj].CTP != vx2.CTP)
continue;
959 float doca = docaCut;
963 unsigned short closePt = 0;
968 doca =
PointTrajDOCA(slc, vx2.Pos[0], vx2.Pos[1], slc.
tjs[itj].Pts[closePt]);
970 if (doca > docaCut)
continue;
972 mf::LogVerbatim(
"TC") <<
" doca " << doca <<
" btw T" << slc.
tjs[itj].ID <<
" and 2V"
973 << slc.
vtxs[iv].ID <<
" closePt " << closePt <<
" in plane "
979 if (vxtjs.empty())
continue;
980 unsigned short maxPts = 0;
984 float tjAng = slc.
tjs[itj].Pts[closePt].Ang;
985 for (
auto tjid : vxtjs) {
986 auto& vtj = slc.
tjs[tjid - 1];
989 if (npwc > maxPts) maxPts = npwc;
990 unsigned short end = 0;
991 if (vtj.VtxID[1] == slc.
vtxs[iv].ID) end = 1;
992 auto& vtp = vtj.Pts[vtj.EndPt[
end]];
994 if (dang > maxdang) maxdang = dang;
1000 if (!skipit && maxdang < 0.3) skipit =
true;
1002 mf::LogVerbatim(
"TC") <<
" maxPts " << maxPts <<
" vxtjs[0] " << vxtjs[0] <<
" maxdang "
1003 << maxdang <<
" skipit? " << skipit;
1014 auto& closeTP = slc.
tjs[itj].Pts[closePt];
1015 if (slc.
tjs[itj].StepDir > 0 && closePt > slc.
tjs[itj].EndPt[0]) {
1016 if (closeTP.Pos[0] > vx2.Pos[0]) --closePt;
1018 else if (slc.
tjs[itj].StepDir < 0 && closePt < slc.
tjs[itj].EndPt[1]) {
1019 if (closeTP.Pos[0] < vx2.Pos[0]) ++closePt;
1026 if ((slc.
tjs[itj].Pts[closePt].Pos[0] - vx2.Pos[0]) *
1027 (slc.
tjs[itj].Pts[slc.
tjs[itj].EndPt[1]].Pos[0] - vx2.Pos[0]) +
1028 (slc.
tjs[itj].Pts[closePt].Pos[1] - vx2.Pos[1]) *
1029 (slc.
tjs[itj].Pts[slc.
tjs[itj].EndPt[1]].Pos[1] - vx2.Pos[1]) <
1031 closePt < slc.
tjs[itj].EndPt[1] - 1)
1033 else if ((slc.
tjs[itj].Pts[closePt].Pos[0] - vx2.Pos[0]) *
1034 (slc.
tjs[itj].Pts[slc.
tjs[itj].EndPt[0]].Pos[0] - vx2.Pos[0]) +
1035 (slc.
tjs[itj].Pts[closePt].Pos[1] - vx2.Pos[1]) *
1036 (slc.
tjs[itj].Pts[slc.
tjs[itj].EndPt[0]].Pos[1] - slc.
vtxs[iv].Pos[1]) <
1038 closePt > slc.
tjs[itj].EndPt[0] + 1)
1043 mf::LogVerbatim(
"TC") <<
"Good doca " << doca <<
" btw T" << slc.
tjs[itj].ID <<
" and 2V"
1044 << vx2.ID <<
" closePt " << closePt <<
" in plane " << planeID.
Plane
1045 <<
" CTP " << slc.
vtxs[iv].CTP;
1046 PrintTP(
"STCV", slc, closePt, 1, slc.
tjs[itj].Pass, slc.
tjs[itj].Pts[closePt]);
1049 if (closePt < slc.
tjs[itj].EndPt[0] + 3)
continue;
1050 if (closePt > slc.
tjs[itj].EndPt[1] - 3)
continue;
1051 if (!
SplitTraj(slc, itj, closePt, iv, prt)) {
1052 if (prt) mf::LogVerbatim(
"TC") <<
"SplitTrajCrossingVertices: Failed to split trajectory";
1056 unsigned short newTjIndex = slc.
tjs.size() - 1;
1072 if (slc.
vtxs.empty())
return;
1077 std::vector<std::vector<int>> vx2Cls;
1080 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
1083 for (
unsigned short ii = 0; ii < slc.
vtxs.size() - 1; ++ii) {
1084 auto& i2v = slc.
vtxs[ii];
1085 if (i2v.ID <= 0)
continue;
1087 for (
unsigned short jj = ii + 1; jj < slc.
vtxs.size(); ++jj) {
1088 auto& j2v = slc.
vtxs[jj];
1089 if (j2v.ID <= 0)
continue;
1092 float dp0 =
std::abs(i2v.Pos[0] - j2v.Pos[0]);
1093 if (dp0 > 10)
continue;
1094 float dp1 =
std::abs(i2v.Pos[1] - j2v.Pos[1]);
1095 if (dp1 > 10)
continue;
1097 float err = i2v.PosErr[0];
1098 if (j2v.PosErr[0] > err) err = j2v.PosErr[0];
1099 float dp0Sig = dp0 /
err;
1100 if (dp0Sig > 4)
continue;
1101 err = i2v.PosErr[1];
1102 if (j2v.PosErr[1] > err) err = j2v.PosErr[1];
1103 float dp1Sig = dp1 /
err;
1104 if (dp1Sig > 4)
continue;
1107 for (
auto& vx2cls : vx2Cls) {
1108 bool goti = (std::find(vx2cls.begin(), vx2cls.end(), i2v.ID) != vx2cls.end());
1109 bool gotj = (std::find(vx2cls.begin(), vx2cls.end(), j2v.ID) != vx2cls.end());
1115 vx2cls.push_back(j2v.ID);
1121 vx2cls.push_back(i2v.ID);
1127 std::vector<int> cls(2);
1130 vx2Cls.push_back(cls);
1134 if (vx2Cls.empty())
continue;
1136 mf::LogVerbatim myprt(
"TC");
1137 myprt <<
"2V clusters in plane " << plane;
1138 for (
auto& vx2cls : vx2Cls) {
1140 for (
auto vx2id : vx2cls)
1141 myprt <<
" 2V" << vx2id;
1144 for (
auto& vx2cls : vx2Cls) {
1151 bool VxEnvironmentNeedsUpdate =
false;
1152 for (
auto& vx : slc.
vtxs) {
1153 if (vx.ID <= 0)
continue;
1154 if (!vx.Stat[
kVxEnvOK]) VxEnvironmentNeedsUpdate =
true;
1169 if (vx2cls.size() < 2)
return false;
1172 std::vector<int> t2vList;
1175 for (
auto vx2id : vx2cls) {
1176 auto& vx2 = slc.
vtxs[vx2id - 1];
1179 if (vx2.ID <= 0)
return true;
1180 auto tlist =
GetAssns(slc,
"2V", vx2.
ID,
"T");
1181 for (
auto tid : tlist)
1182 if (std::find(t2vList.begin(), t2vList.end(), tid) == t2vList.end()) t2vList.push_back(tid);
1184 if (t2vList.size() < 3)
return false;
1189 for (
auto tid : t2vList) {
1190 auto& tj = slc.
tjs[tid - 1];
1191 for (
unsigned short end = 0;
end < 2; ++
end) {
1192 if (tj.VtxID[
end] <= 0)
continue;
1193 if (std::find(vx2cls.begin(), vx2cls.end(), tj.VtxID[
end]) == vx2cls.end())
continue;
1194 auto& vx = slc.
vtxs[tj.VtxID[
end] - 1];
1195 unsigned short nearEnd = 1 -
FarEnd(slc, tj, vx.Pos);
1197 if (fitPt == USHRT_MAX)
return false;
1198 auto& tp = tj.Pts[fitPt];
1205 mf::LogVerbatim myprt(
"TC");
1206 myprt <<
"R2VTs: cluster:";
1207 for (
auto vid : vx2cls)
1208 myprt <<
" 2V" << vid;
1210 for (
auto tid : t2vList)
1211 myprt <<
" T" << tid;
1212 myprt <<
" sumPulls " << std::setprecision(2) << sumPulls <<
" cnt " << cnt;
1220 for (
auto vid : vx2cls) {
1221 auto& vx = slc.
vtxs[vid - 1];
1222 oneVx.
Pos[0] += vx.Pos[0];
1223 oneVx.
Pos[1] += vx.Pos[2];
1225 oneVx.
Pos[0] /= vx2cls.size();
1226 oneVx.
Pos[1] /= vx2cls.size();
1227 std::vector<TrajPoint> oneVxTPs(t2vList.size());
1228 for (
unsigned short itj = 0; itj < t2vList.size(); ++itj) {
1229 auto& tj = slc.
tjs[t2vList[itj] - 1];
1230 unsigned short nearEnd = 1 -
FarEnd(slc, tj, oneVx.
Pos);
1232 if (fitPt == USHRT_MAX)
return false;
1233 oneVxTPs[itj] = tj.Pts[fitPt];
1236 oneVxTPs[itj].Step = tj.ID;
1238 if (!
FitVertex(slc, oneVx, oneVxTPs, prt))
return false;
1242 auto& vx = slc.
vtxs[vx2cls[0] - 1];
1244 vx.PosErr = oneVx.
PosErr;
1245 vx.NTraj = t2vList.size();
1246 vx.ChiDOF = oneVx.
ChiDOF;
1251 for (
unsigned short ivx = 1; ivx < vx2cls.size(); ++ivx) {
1252 auto& vx = slc.
vtxs[vx2cls[ivx] - 1];
1256 for (
auto tid : t2vList) {
1257 auto& tj = slc.
tjs[tid - 1];
1258 unsigned short nearEnd = 1 -
FarEnd(slc, tj, vx.Pos);
1259 tj.VtxID[nearEnd] = vx.ID;
1275 if (slc.
vtxs.size() < 2)
return;
1278 std::vector<std::vector<unsigned short>> vIndex(3);
1279 for (
unsigned short ivx = 0; ivx < slc.
vtxs.size(); ++ivx) {
1281 if (slc.
vtxs[ivx].ID == 0)
continue;
1284 unsigned short plane = planeID.
Plane;
1285 if (plane > 2)
continue;
1286 vIndex[plane].push_back(ivx);
1289 unsigned short vtxInPln = 0;
1290 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane)
1291 if (vIndex[plane].
size() > 0) ++vtxInPln;
1292 if (vtxInPln < 2)
return;
1297 mf::LogVerbatim(
"TC") <<
"Inside Find3DVertices. dX cut " <<
tcc.
vtx3DCuts[0]
1298 <<
" thirdPlanedXCut " << thirdPlanedXCut;
1301 size_t vsize = slc.
vtxs.size();
1303 std::vector<short> vPtr(vsize, -1);
1305 std::vector<float> vX(vsize, FLT_MAX);
1307 for (
unsigned short ivx = 0; ivx < vsize; ++ivx) {
1308 if (slc.
vtxs[ivx].ID <= 0)
continue;
1310 if (slc.
vtxs[ivx].Pos[0] < -0.4)
continue;
1318 std::vector<Vtx3Store> v3temp;
1324 constexpr
float maxSep = 4;
1328 for (
unsigned short ipl = 0; ipl < 2; ++ipl) {
1329 for (
unsigned short ii = 0; ii < vIndex[ipl].size(); ++ii) {
1330 unsigned short ivx = vIndex[ipl][ii];
1331 if (vX[ivx] == FLT_MAX)
continue;
1332 auto& ivx2 = slc.
vtxs[ivx];
1333 if (ivx2.Pos[0] < -0.4)
continue;
1334 unsigned int iWire = std::nearbyint(ivx2.Pos[0]);
1335 for (
unsigned short jpl = ipl + 1; jpl < 3; ++jpl) {
1336 for (
unsigned short jj = 0; jj < vIndex[jpl].size(); ++jj) {
1337 unsigned short jvx = vIndex[jpl][jj];
1338 if (vX[jvx] == FLT_MAX)
continue;
1339 auto& jvx2 = slc.
vtxs[jvx];
1340 if (jvx2.Pos[0] < -0.4)
continue;
1341 unsigned int jWire = std::nearbyint(jvx2.Pos[0]);
1342 float dX =
std::abs(vX[ivx] - vX[jvx]);
1345 mf::LogVerbatim(
"TC")
1346 <<
"F3DV: ipl " << ipl <<
" i2V" << ivx2.ID <<
" iX " << vX[ivx] <<
" jpl " << jpl
1347 <<
" j2V" << jvx2.ID <<
" jvX " << vX[jvx] <<
" W:T " << (int)jvx2.Pos[0] <<
":"
1348 << (
int)jvx2.Pos[1] <<
" dX " << dX;
1350 double y = -1000,
z = -1000;
1352 if (y < slc.yLo || y > slc.
yHi || z < slc.zLo || z > slc.
zHi)
continue;
1353 unsigned short kpl = 3 - ipl - jpl;
1354 float kX = 0.5 * (vX[ivx] + vX[jvx]);
1358 std::array<int, 2> wireWindow;
1359 std::array<float, 2> timeWindow;
1360 wireWindow[0] = kWire - maxSep;
1361 wireWindow[1] = kWire + maxSep;
1364 timeWindow[0] = time - maxSep;
1365 timeWindow[1] = time + maxSep;
1367 std::vector<unsigned int> closeHits =
1370 mf::LogVerbatim myprt(
"TC");
1371 myprt <<
" Hits near " << kpl <<
":" << kWire <<
":"
1373 for (
auto iht : closeHits)
1376 if (!hitsNear)
continue;
1383 v3d.
Vx2ID[ipl] = ivx2.ID;
1384 v3d.
Vx2ID[jpl] = jvx2.ID;
1393 float vxScoreWght = 0;
1396 if (posError < 0.5) posError = 0;
1397 v3d.
Score = posError + vxScoreWght;
1400 v3temp.push_back(v3d);
1403 mf::LogVerbatim myprt(
"TC");
1404 myprt <<
" 2 Plane match i2V";
1405 myprt << slc.
vtxs[ivx].ID <<
" P:W:T " << ipl <<
":" << (int)slc.
vtxs[ivx].Pos[0]
1406 <<
":" << (
int)slc.
vtxs[ivx].Pos[1];
1407 myprt <<
" j2V" << slc.
vtxs[jvx].ID <<
" P:W:T " << jpl <<
":"
1408 << (int)slc.
vtxs[jvx].Pos[0] <<
":" << (
int)slc.
vtxs[jvx].Pos[1];
1409 myprt << std::fixed << std::setprecision(3);
1410 myprt <<
" dX " << dX <<
" posError " << posError <<
" vxScoreWght " << vxScoreWght
1411 <<
" Score " << v3d.
Score;
1414 if (slc.
nPlanes == 2)
continue;
1417 for (
unsigned short kk = 0; kk < vIndex[kpl].size(); ++kk) {
1418 unsigned short kvx = vIndex[kpl][kk];
1422 if (dX > thirdPlanedXCut)
continue;
1425 double y = -1000,
z = -1000;
1427 v3d.
YErr = y - v3d.
Y;
1436 posError = dX * dX + dY * dY + dZ * dZ;
1440 if (posError < 0.5) posError = 0;
1441 v3d.
Score = posError + vxScoreWght;
1442 if (v3d.
Score > maxScore) maxScore = v3d.
Score;
1444 mf::LogVerbatim(
"TC") <<
" k2V" << kvx + 1 <<
" dX " << dX <<
" dW " << dW
1445 <<
" 3D score " << v3d.
Score;
1446 v3temp.push_back(v3d);
1453 if (v3temp.empty())
return;
1458 for (
auto& v3 : v3temp)
1459 if (v3.Wire >= 0) v3.Score += maxScore;
1462 mf::LogVerbatim(
"TC") <<
"v3temp list";
1463 for (
auto& v3 : v3temp) {
1465 mf::LogVerbatim(
"TC") <<
"2V" << v3.Vx2ID[0] <<
" 2V" << v3.Vx2ID[1] <<
" wire "
1466 << v3.Wire <<
" Score " << v3.Score;
1469 mf::LogVerbatim(
"TC") <<
"2V" << v3.Vx2ID[0] <<
" 2V" << v3.Vx2ID[1] <<
" 2V"
1470 << v3.Vx2ID[2] <<
" wire " << v3.Wire <<
" Score " << v3.Score;
1475 std::vector<SortEntry> sortVec(v3temp.size());
1476 for (
unsigned short ivx = 0; ivx < v3temp.size(); ++ivx) {
1478 sEntry.
val = v3temp[ivx].Score;
1479 sortVec[ivx] = sEntry;
1481 if (sortVec.size() > 1) std::sort(sortVec.begin(), sortVec.end(),
valsIncreasing);
1483 std::vector<Vtx3Store> v3sel;
1484 for (
unsigned short ii = 0; ii < sortVec.size(); ++ii) {
1485 unsigned short ivx = sortVec[ii].
index;
1487 bool skipit =
false;
1488 for (
auto& v3 : v3sel) {
1489 for (
unsigned short ipl = 0; ipl < slc.
nPlanes; ++ipl) {
1490 if (v3temp[ivx].Vx2ID[ipl] == 0)
continue;
1491 if (v3temp[ivx].Vx2ID[ipl] == v3.Vx2ID[ipl]) {
1498 if (skipit)
continue;
1499 v3sel.push_back(v3temp[ivx]);
1504 mf::LogVerbatim myprt(
"TC");
1505 myprt <<
"v3sel list\n";
1506 for (
auto& v3d : v3sel) {
1507 for (
auto vx2id : v3d.Vx2ID)
1508 if (vx2id > 0) myprt <<
" 2V" << vx2id;
1509 myprt <<
" wire " << v3d.Wire <<
" Score " << v3d.Score;
1515 unsigned short ninc = 0;
1516 for (
auto& vx3 : v3sel) {
1517 if (slc.
nPlanes == 3 && vx3.Wire >= 0) ++ninc;
1518 vx3.ID = slc.
vtx3s.size() + 1;
1522 mf::LogVerbatim myprt(
"TC");
1523 myprt <<
" 3V" << vx3.ID;
1524 for (
auto v2id : vx3.Vx2ID)
1525 myprt <<
" 2V" << v2id;
1526 myprt <<
" wire " << vx3.Wire;
1528 slc.
vtx3s.push_back(vx3);
1530 for (
unsigned short ipl = 0; ipl < slc.
nPlanes; ++ipl) {
1531 if (vx3.Vx2ID[ipl] == 0)
continue;
1545 for (
auto& tj : slc.
tjs) {
1548 if (planeID.
TPC != tpc || planeID.
Cryostat != cstat)
continue;
1552 for (
auto& vx2 : slc.
vtxs) {
1553 if (vx2.ID == 0)
continue;
1555 if (planeID.
TPC != tpc || planeID.
Cryostat != cstat)
continue;
1559 for (
auto& vx3 : slc.
vtx3s) {
1560 if (vx3.ID == 0)
continue;
1571 for (
unsigned short ivx = 0; ivx < slc.
vtxs.size(); ++ivx) {
1572 if (slc.
vtxs[ivx].ID == 0)
continue;
1573 if (slc.
vtxs[ivx].CTP != tp.
CTP)
continue;
1587 if (pfp.
ID <= 0)
return false;
1589 float pLen =
Length(pfp);
1590 if (pLen == 0)
return false;
1594 for (
unsigned short end = 0;
end < 2; ++
end)
1596 std::array<Point3_t, 2> endPos;
1600 std::array<float, 2> foms{{100., 100.}};
1601 std::array<int, 2> vtxs{{0}};
1602 for (
auto& vx3 : slc.
vtx3s) {
1603 if (vx3.ID <= 0)
continue;
1604 if (vx3.TPCID != pfp.
TPCID)
continue;
1605 std::array<float, 2> sep;
1606 Point3_t vpos = {{vx3.X, vx3.Y, vx3.Z}};
1607 sep[0] =
PosSep(vpos, endPos[0]);
1608 sep[1] =
PosSep(vpos, endPos[1]);
1609 unsigned short end = 0;
1610 if (sep[1] < sep[0]) end = 1;
1612 if (sep[end] > 100)
continue;
1617 float fom = dotp * sep[
end];
1619 mf::LogVerbatim(
"TC") <<
"ATAV: P" << pfp.
ID <<
" end " << end <<
" 3V" << vx3.ID <<
" sep "
1620 << sep[
end] <<
" fom " << fom <<
" maxSep " << maxSep;
1622 if (sep[end] > maxSep)
continue;
1623 if (fom < foms[end]) {
1629 for (
unsigned short end = 0;
end < 2; ++
end) {
1630 if (vtxs[
end] == 0)
continue;
1632 mf::LogVerbatim(
"TC") <<
"ATAV: set P" << pfp.
ID <<
" end " <<
end <<
" -> 3V" << vtxs[
end];
1644 if (tjID <= 0 || tjID > (
int)slc.
tjs.size())
return false;
1645 if (slc.
vtxs.empty())
return false;
1646 auto& tj = slc.
tjs[tjID - 1];
1647 if (tj.AlgMod[
kKilled])
return false;
1650 unsigned short bestVx = USHRT_MAX;
1654 for (
unsigned short ivx = 0; ivx < slc.
vtxs.size(); ++ivx) {
1655 auto& vx = slc.
vtxs[ivx];
1656 if (vx.ID == 0)
continue;
1657 if (vx.CTP != tj.CTP)
continue;
1659 std::array<float, 2> sep;
1660 sep[0] =
PosSep(vx.Pos, tj.Pts[tj.EndPt[0]].Pos);
1661 sep[1] =
PosSep(vx.Pos, tj.Pts[tj.EndPt[1]].Pos);
1662 unsigned short end = 0;
1663 if (sep[1] < sep[0]) end = 1;
1664 if (sep[end] > 100)
continue;
1665 if (tj.VtxID[end] > 0)
continue;
1666 auto& tp = tj.Pts[tj.EndPt[
end]];
1669 if (fom > bestFOM)
continue;
1671 mf::LogVerbatim(
"TC") <<
"AAVTT: T" << tjID <<
" 2V" << vx.ID <<
" FOM " << fom <<
" cut "
1676 if (bestVx > slc.
vtxs.size() - 1)
return false;
1677 auto& vx = slc.
vtxs[bestVx];
1686 if (ivx > slc.
vtxs.size() - 1)
return false;
1687 if (slc.
vtxs[ivx].ID == 0)
return false;
1692 if (vx.
Topo == 5 || vx.
Topo == 6)
return false;
1694 unsigned short bestTj = USHRT_MAX;
1698 for (
unsigned int itj = 0; itj < slc.
tjs.size(); ++itj) {
1699 auto& tj = slc.
tjs[itj];
1701 if (tj.CTP != vx.
CTP)
continue;
1703 std::array<float, 2> sep;
1704 sep[0] =
PosSep(vx.
Pos, tj.Pts[tj.EndPt[0]].Pos);
1705 sep[1] =
PosSep(vx.
Pos, tj.Pts[tj.EndPt[1]].Pos);
1706 unsigned short end = 0;
1707 if (sep[1] < sep[0]) end = 1;
1708 if (sep[end] > 100)
continue;
1709 if (tj.VtxID[end] > 0)
continue;
1710 auto& tp = tj.Pts[tj.EndPt[
end]];
1713 if (fom > bestFOM)
continue;
1715 mf::LogVerbatim(
"TC") <<
"AATTV: T" << tj.ID <<
" 2V" << vx.
ID <<
" Topo " << vx.
Topo
1716 <<
" FOM " << fom <<
" cut " << bestFOM;
1721 if (bestTj > slc.
tjs.size() - 1)
return false;
1722 auto& tj = slc.
tjs[bestTj];
1742 if (tj.
CTP != vx.
CTP)
return false;
1752 unsigned short end = 0;
1755 if (sep1 < vtxTjSep2) {
1761 if (tj.
VtxID[end] > 0)
return false;
1764 bool tjShort = (tj.
EndPt[1] - tj.
EndPt[0] < maxShortTjLen);
1766 if (!tjShort && tj.
ChgRMS > 0.5) tjShort =
true;
1767 float closestApproach;
1770 if (vtxTjSep2 > maxSepCutShort2)
return false;
1775 if (vtxTjSep2 > maxSepCutLong2)
return false;
1784 unsigned short closePt;
1790 if (end == 0) { dpt = closePt - tj.
EndPt[
end]; }
1797 if (length > 4 && length < closestApproach)
return false;
1803 if (tjShort) pullCut *= 2;
1806 mf::LogVerbatim myprt(
"TC");
1807 myprt <<
"ATTV: 2V" << vx.
ID;
1808 myprt <<
" NTraj " << vx.
NTraj;
1810 for (
unsigned short itj = 0; itj < slc.
tjs.size(); ++itj) {
1813 if (tj.
CTP != vx.
CTP)
continue;
1814 if (tj.
VtxID[0] == vx.
ID) myprt <<
" T" << tj.
ID <<
"_0";
1815 if (tj.
VtxID[1] == vx.
ID) myprt <<
" T" << tj.
ID <<
"_1";
1817 myprt <<
" + T" << tj.
ID <<
"_" << end <<
" vtxTjSep " << sqrt(vtxTjSep2) <<
" tpVxPull "
1818 << tpVxPull <<
" pullCut " << pullCut <<
" dpt " << dpt;
1820 if (tpVxPull > pullCut)
return false;
1821 if (dpt > 2)
return true;
1835 if (prt) mf::LogVerbatim(
"TC") <<
" Success";
1842 mf::LogVerbatim(
"TC") <<
" Poor fit. Keep T" << tj.
ID <<
"-2V" << vx.
ID
1843 <<
" assn with kNoFitVx";
1862 double vxErrW = vx.
PosErr[0] * tp.
Dir[1];
1863 double vxErrT = vx.
PosErr[1] * tp.
Dir[0];
1864 double vxErr2 = vxErrW * vxErrW + vxErrT * vxErrT;
1870 if (sep2 < 1)
return (
float)(ip / sqrt(vxErr2));
1872 double dang = ip / sqrt(sep2);
1876 double angErr = vxErr2 / sep2;
1879 if (angErr == 0)
return 999;
1880 angErr = sqrt(angErr);
1881 return (
float)(dang / angErr);
1890 double dx = vx1.
X - vx2.
X;
1891 double dy = vx1.
Y - vx2.
Y;
1892 double dz = vx1.
Z - vx2.
Z;
1896 dx = dx * dx / dxErr2;
1897 dy = dy * dy / dyErr2;
1898 dz = dz * dz / dzErr2;
1899 return (
float)(sqrt(dx + dy + dz) / 3);
1907 double dw = vx1.
Pos[0] - vx2.
Pos[0];
1908 double dt = vx1.
Pos[1] - vx2.
Pos[1];
1911 dw = dw * dw / dwErr2;
1912 dt = dt * dt / dtErr2;
1913 return (
float)sqrt(dw + dt);
1923 if (vx.
ID !=
int(slc.
vtxs.size() + 1))
return false;
1928 unsigned short nvxtj = 0;
1929 unsigned short nok = 0;
1930 for (
auto& tj : slc.
tjs) {
1931 if (tj.AlgMod[
kKilled])
continue;
1932 if (vx.
ID == tj.VtxID[0] || vx.
ID == tj.VtxID[1]) ++nvxtj;
1933 if (vx.
CTP != tj.CTP)
continue;
1934 if (vx.
ID == tj.VtxID[0] || vx.
ID == tj.VtxID[1]) ++nok;
1938 mf::LogVerbatim(
"TC") <<
"StoreVertex: vertex " << vx.
ID <<
" Topo " << vx.
Topo
1939 <<
" has inconsistent CTP code " << vx.
CTP <<
" with one or more Tjs\n";
1940 for (
auto& tj : slc.
tjs) {
1941 if (tj.AlgMod[
kKilled])
continue;
1942 if (tj.VtxID[0] == vx.
ID) tj.VtxID[0] = 0;
1943 if (tj.VtxID[1] == vx.
ID) tj.VtxID[1] = 0;
1948 slc.
vtxs.push_back(vx);
1968 if (prt) mf::LogVerbatim(
"TC") <<
" vertex position fixed. No fit allowed";
1973 std::vector<TrajPoint> vxTp;
1974 for (
auto& tj : slc.
tjs) {
1976 if (tj.CTP != vx.
CTP)
continue;
1977 if (tj.AlgMod[
kPhoton])
continue;
1979 if (tj.VtxID[0] == vx.
ID && !tj.EndFlag[0][
kNoFitVx]) {
1980 vxTp.push_back(tj.Pts[tj.EndPt[0]]);
1983 if (tj.VtxID[1] == vx.
ID && !tj.EndFlag[1][
kNoFitVx]) {
1984 vxTp.push_back(tj.Pts[tj.EndPt[1]]);
1989 auto& tp = vxTp[vxTp.size() - 1];
1990 if (tj.ID > 0) tp.Step = (int)tj.ID;
1992 if (tp.NTPsFit < 4) tp.AngErr *= 4;
1996 bool success =
FitVertex(slc, vx, vxTp, prt);
1998 if (!success)
return false;
2013 if (vxTPs.size() < 2)
return false;
2014 if (vxTPs.size() == 2) {
2019 unsigned short npts = vxTPs.size();
2020 TMatrixD
A(npts, 2);
2022 for (
unsigned short itj = 0; itj < vxTPs.size(); ++itj) {
2023 auto& tp = vxTPs[itj];
2024 double dtdw = tp.Dir[1] / tp.Dir[0];
2025 double wt = 1 / (tp.AngErr * tp.AngErr);
2026 A(itj, 0) = -dtdw * wt;
2027 A(itj, 1) = 1. * wt;
2028 b(itj) = (tp.Pos[1] - tp.Pos[0] * dtdw) * wt;
2031 TMatrixD AT(2, npts);
2033 TMatrixD ATA = AT *
A;
2041 if (det == NULL)
return false;
2042 TVectorD vxPos = ATA * AT * b;
2043 vx.
PosErr[0] = sqrt(ATA[0][0]);
2044 vx.
PosErr[1] = sqrt(ATA[1][1]);
2045 vx.
Pos[0] = vxPos[0];
2046 vx.
Pos[1] = vxPos[1];
2050 if (vxTPs.size() > 2) {
2051 for (
auto& tp : vxTPs) {
2056 vx.
ChiDOF /= (float)(vxTPs.size() - 2);
2060 mf::LogVerbatim(
"TC") <<
"Note: TP - 2V pull is stored in TP.Delta";
2062 for (
auto& tp : vxTPs)
2063 PrintTP(
"FV", slc, 0, 1, 1, tp);
2077 unsigned short plane = planeID.
Plane;
2078 for (
auto& vx2 : slc.
vtxs) {
2079 if (vx2.CTP != inCTP)
continue;
2080 if (vx2.ID == 0)
continue;
2081 if (vx2.Vx3ID == 0)
continue;
2082 if (vx2.Vx3ID >
int(slc.
vtx3s.size())) {
2083 mf::LogVerbatim(
"TC") <<
"ChkVtxAssociations: Invalid vx2.Vx3ID " << vx2.Vx3ID
2084 <<
" in 2D vtx " << vx2.ID;
2087 auto& vx3 = slc.
vtx3s[vx2.Vx3ID - 1];
2089 mf::LogVerbatim(
"TC") <<
"ChkVtxAssociations: 2V" << vx2.ID <<
" thinks it is matched to 3V"
2090 << vx3.ID <<
" but vx3 is obsolete";
2093 if (vx3.Vx2ID[plane] != vx2.ID) {
2094 mf::LogVerbatim(
"TC") <<
"ChkVtxAssociations: 2V" << vx2.ID <<
" thinks it is matched to 3V"
2095 << vx3.ID <<
" but vx3 says no!";
2100 for (
auto& vx3 : slc.
vtx3s) {
2101 if (vx3.ID == 0)
continue;
2102 if (vx3.Vx2ID[plane] == 0)
continue;
2103 if (vx3.Vx2ID[plane] > (
int)slc.
vtxs.size()) {
2104 mf::LogVerbatim(
"TC") <<
"ChkVtxAssociations: Invalid vx3.Vx2ID " << vx3.Vx2ID[plane]
2105 <<
" in CTP " << inCTP;
2108 auto& vx2 = slc.
vtxs[vx3.Vx2ID[plane] - 1];
2109 if (vx2.Vx3ID != vx3.ID) {
2110 mf::LogVerbatim(
"TC") <<
"ChkVtxAssociations: 3V" << vx3.ID <<
" thinks it is matched to 2V"
2111 << vx2.ID <<
" but vx2 says no!";
2117 for (
auto& tj : slc.
tjs) {
2119 for (
unsigned short end = 0;
end < 2; ++
end) {
2120 if (tj.VtxID[
end] == 0)
continue;
2121 if (tj.VtxID[
end] > slc.
vtxs.size()) {
2122 mf::LogVerbatim(
"TC") <<
"ChkVtxAssociations: T" << tj.ID <<
" thinks it is matched to 2V"
2123 << tj.VtxID[
end] <<
" on end " <<
end
2124 <<
" but no vertex exists. Recovering";
2128 unsigned short ivx = tj.VtxID[
end] - 1;
2129 auto& vx2 = slc.
vtxs[ivx];
2131 mf::LogVerbatim(
"TC") <<
"ChkVtxAssociations: T" << tj.ID <<
" thinks it is matched to 2V"
2132 << tj.VtxID[
end] <<
" on end " <<
end
2133 <<
" but the vertex is killed. Fixing the Tj";
2151 for (
auto& vx : slc.
vtxs) {
2152 if (vx.ID == 0)
continue;
2156 for (
auto& tj : slc.
tjs) {
2161 for (
auto& vx : slc.
vtxs) {
2162 if (vx.ID == 0)
continue;
2166 for (
auto& vx3 : slc.
vtx3s) {
2167 if (vx3.ID == 0)
continue;
2177 if (slc.
vtxs.empty())
return;
2178 for (
auto& vx : slc.
vtxs) {
2179 if (vx.ID == 0)
continue;
2182 auto& vx3 = slc.
vtx3s[vx.Vx3ID - 1];
2183 if (vx3.Primary)
continue;
2197 if (vx3.
ID == 0)
return;
2199 for (
unsigned short ipl = 0; ipl < slc.
nPlanes; ++ipl) {
2200 if (vx3.
Vx2ID[ipl] <= 0)
continue;
2205 std::vector<int> vxlist;
2210 for (
auto tjid : tjlist) {
2211 auto& tj = slc.
tjs[tjid - 1];
2213 for (
unsigned short end = 0;
end < 2; ++
end) {
2214 if (tj.VtxID[
end] == 0)
continue;
2215 auto& vx2 = slc.
vtxs[tj.VtxID[
end] - 1];
2218 vxlist.push_back(vx2.
ID);
2222 if (vxlist.empty())
break;
2224 std::vector<int> newtjlist;
2225 for (
auto vxid : vxlist) {
2226 auto& vx2 = slc.
vtxs[vxid - 1];
2228 for (
auto tjid : tmp) {
2229 if (std::find(tjlist.begin(), tjlist.end(), tjid) == tjlist.end())
2230 newtjlist.push_back(tjid);
2233 if (newtjlist.empty())
break;
2247 if (vx3.
ID == 0)
return;
2250 for (
unsigned short ipl = 0; ipl < slc.
nPlanes; ++ipl) {
2251 if (vx3.
Vx2ID[ipl] <= 0)
continue;
2267 if (slc.
vtxs.empty())
return;
2268 auto& vx2 = slc.
vtxs[slc.
vtxs.size() - 1];
2277 if (vx2.
ID == 0)
return;
2288 constexpr
float maxChgRMS = 0.25;
2289 constexpr
float momBin = 50;
2293 if (vx2.
ID == 0)
return;
2297 if (vtxTjIDs.empty())
return;
2302 unsigned short m3Dcnt = 0;
2303 if (vx2.
Vx3ID > 0) {
2306 unsigned short ivx3 = vx2.
Vx3ID - 1;
2307 if (slc.
vtx3s[ivx3].Wire < 0) m3Dcnt = 2;
2315 std::vector<int> tjids;
2316 std::vector<float> tjwts;
2317 unsigned short cnt13 = 0;
2318 for (
auto tjid : vtxTjIDs) {
2322 unsigned short lenth = tj.
EndPt[1] - tj.
EndPt[0] + 1;
2323 if (lenth < 3)
continue;
2324 float wght = (float)tj.
MCSMom / momBin;
2328 if (cnt13 == 1) wght *= 2;
2331 if (tj.
ChgRMS < maxChgRMS) ++wght;
2336 tjids.push_back(tjid);
2337 tjwts.push_back(wght);
2340 if (tjids.empty())
return;
2345 for (
unsigned short it1 = 0; it1 < tjids.size() - 1; ++it1) {
2347 float wght1 = tjwts[it1];
2349 unsigned short end1 = 0;
2350 if (tj1.
VtxID[1] == vx2.
ID) end1 = 1;
2351 unsigned short endPt1 = tj1.
EndPt[end1];
2353 unsigned short oend1 = 1 - end1;
2355 float ang1 = tj1.
Pts[endPt1].Ang;
2356 float ang1Err2 = tj1.
Pts[endPt1].AngErr * tj1.
Pts[endPt1].AngErr;
2357 for (
unsigned short it2 = it1 + 1; it2 < tjids.size(); ++it2) {
2359 float wght2 = tjwts[it2];
2361 if (tj2.
VtxID[1] == vx2.
ID) end2 = 1;
2363 unsigned short oend2 = 1 - end2;
2364 if (tj2.
EndFlag[oend2][kBragg]) ++wght2;
2365 unsigned short endPt2 = tj2.
EndPt[end2];
2366 float ang2 = tj2.
Pts[endPt2].Ang;
2367 float ang2Err2 = tj2.
Pts[endPt2].AngErr * tj2.
Pts[endPt2].AngErr;
2369 float dangErr = 0.5 * sqrt(ang1Err2 + ang2Err2);
2370 if ((dang / dangErr) > 3 && wght1 > 0 && wght2 > 0) {
2371 sum += wght1 + wght2;
2380 vx2.
Score = vpeScore + m3DScore + cfScore + tjScore;
2384 mf::LogVerbatim myprt(
"TC");
2385 bool printHeader =
true;
2386 Print2V(
"SVx2S", myprt, vx2, printHeader);
2387 myprt << std::fixed << std::setprecision(1);
2388 myprt <<
" vpeScore " << vpeScore <<
" m3DScore " << m3DScore;
2389 myprt <<
" cfScore " << cfScore <<
" tjScore " << tjScore;
2390 myprt <<
" Score " << vx2.
Score;
2403 if (prt) mf::LogVerbatim(
"TC") <<
"Inside CI3DVIG:";
2405 for (
unsigned short iv3 = 0; iv3 < slc.
vtx3s.size(); ++iv3) {
2408 if (vx3.
ID == 0)
continue;
2410 if (vx3.
Wire < 0)
continue;
2411 unsigned short mPlane = USHRT_MAX;
2412 for (
unsigned short ipl = 0; ipl < slc.
nPlanes; ++ipl) {
2413 if (vx3.
Vx2ID[ipl] > 0)
continue;
2417 if (mPlane == USHRT_MAX)
continue;
2421 if (dwc < 5)
continue;
2424 aVtx.
ID = slc.
vtxs.size() + 1;
2434 mf::LogVerbatim(
"TC") <<
"CI3DVIG: Incomplete vertex " << iv3 <<
" in plane " << mPlane
2435 <<
" wire " << vx3.
Wire <<
" Made 2D vertex ";
2436 std::vector<int> tjIDs;
2437 std::vector<unsigned short> tjEnds;
2438 for (
unsigned short itj = 0; itj < slc.
tjs.size(); ++itj) {
2439 if (slc.
tjs[itj].CTP != mCTP)
continue;
2441 for (
unsigned short end = 0;
end < 2; ++
end) {
2442 unsigned short ept = slc.
tjs[itj].EndPt[
end];
2444 unsigned short oept = slc.
tjs[itj].EndPt[1 -
end];
2449 if (doca > 2)
continue;
2452 if (aVtx.
Pos[0] > tp.
Pos[0]) { ptSep = aVtx.
Pos[0] - tp.
Pos[0] - dwc; }
2454 ptSep = tp.
Pos[0] - aVtx.
Pos[0] - dwc;
2457 mf::LogVerbatim(
"TC") <<
"CI3DVIG: tj ID " << slc.
tjs[itj].ID <<
" doca " << doca
2458 <<
" ptSep " << ptSep;
2459 if (ptSep < -2 || ptSep > 2)
continue;
2461 if (slc.
tjs[itj].VtxID[
end] > 0)
continue;
2462 tjIDs.push_back(slc.
tjs[itj].ID);
2463 tjEnds.push_back(
end);
2466 if (!tjIDs.empty()) {
2473 for (
unsigned short ii = 0; ii < tjIDs.size(); ++ii) {
2474 unsigned short itj = tjIDs[ii] - 1;
2475 slc.
tjs[itj].VtxID[tjEnds[ii]] = aVtx.
ID;
2482 mf::LogVerbatim(
"TC") <<
"CI3DVIG: new vtx 2V" << aVtx.
ID <<
" points to 3V" << vx3.
ID;
2502 if (prt) mf::LogVerbatim(
"TC") <<
"Inside CI3DV with maxdoca set to " << maxdoca;
2503 unsigned short ivx3 = 0;
2504 for (
auto& vx3 : slc.
vtx3s) {
2506 if (vx3.ID == 0)
continue;
2508 if (vx3.Wire < 0)
continue;
2509 unsigned short mPlane = USHRT_MAX;
2511 bool indPlnNoChgVtx =
false;
2512 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
2513 if (vx3.Vx2ID[plane] > 0) {
2514 auto& vx2 = slc.
vtxs[vx3.Vx2ID[plane] - 1];
2520 if (mPlane == USHRT_MAX)
continue;
2521 if (indPlnNoChgVtx)
continue;
2522 CTP_t mCTP =
EncodeCTP(vx3.TPCID.Cryostat, vx3.TPCID.TPC, mPlane);
2526 vtp.
Pos[0] = vx3.Wire;
2527 vtp.
Pos[1] = detProp.
ConvertXToTicks(vx3.X, mPlane, vx3.TPCID.TPC, vx3.TPCID.Cryostat) *
2530 mf::LogVerbatim(
"TC") <<
"CI3DV 3V" << vx3.ID <<
" Pos " << mPlane <<
":"
2532 std::vector<int> tjIDs;
2533 std::vector<unsigned short> tjPts;
2534 for (
auto& tj : slc.
tjs) {
2535 if (tj.CTP != mCTP)
continue;
2537 if (tj.Pts.size() < 6)
continue;
2539 float doca = maxdoca;
2541 unsigned short closePt = 0;
2543 if (closePt > tj.EndPt[1])
continue;
2548 mf::LogVerbatim(
"TC") <<
"CI3DV 3V" << vx3.ID <<
" candidate T" << tj.ID <<
" vtx pos "
2549 <<
PrintPos(slc, vtp.
Pos) <<
" doca " << doca <<
" closePt "
2551 tjIDs.push_back(tj.ID);
2552 tjPts.push_back(closePt);
2554 if (tjIDs.empty())
continue;
2558 auto vxtjs =
GetAssns(slc,
"3V", vx3.
ID,
"T");
2559 unsigned short maxPts = 0;
2560 unsigned short minPts = USHRT_MAX;
2561 for (
auto tjid : vxtjs) {
2562 auto& tj = slc.
tjs[tjid - 1];
2564 if (npwc > maxPts) maxPts = npwc;
2565 if (npwc < minPts) minPts = npwc;
2569 bool skipit =
false;
2570 for (
auto tjid : tjIDs) {
2571 auto& tj = slc.
tjs[tjid - 1];
2575 mf::LogVerbatim(
"TC") <<
" maxPts " << maxPts <<
" skipit? " << skipit <<
" minPts "
2577 if (skipit)
continue;
2580 unsigned short newVtxIndx = slc.
vtxs.size();
2581 aVtx.
ID = newVtxIndx + 1;
2591 mf::LogVerbatim(
"TC") <<
" charge fraction near position " << aVtx.
TjChgFrac
2597 if (prt) mf::LogVerbatim(
"TC") <<
" Stored new 2V" << newVtx.
ID;
2599 std::array<float, 2> vpos = aVtx.
Pos;
2600 for (
unsigned short ii = 0; ii < tjIDs.size(); ++ii) {
2601 unsigned short itj = tjIDs[ii] - 1;
2602 unsigned short closePt = tjPts[ii];
2604 unsigned short end = 1;
2606 if (fabs(closePt - slc.
tjs[itj].EndPt[0]) < fabs(closePt - slc.
tjs[itj].EndPt[1])) end = 0;
2607 short dpt = fabs(closePt - slc.
tjs[itj].EndPt[end]);
2608 if (prt) mf::LogVerbatim(
"TC") <<
" dpt " << dpt <<
" to end " <<
end;
2611 if (slc.
tjs[itj].VtxID[end] > 0) {
2613 auto& oldTj = slc.
tjs[itj];
2614 auto& oldVx = slc.
vtxs[oldTj.VtxID[
end] - 1];
2615 short oldSep = fabs(oldVx.Pos[0] - oldTj.Pts[oldTj.EndPt[end]].Pos[0]);
2617 mf::LogVerbatim(
"TC")
2618 <<
" T" << slc.
tjs[itj].ID <<
" has vertex 2V" << slc.
tjs[itj].VtxID[
end]
2619 <<
" at end " << end <<
". oldSep " << oldSep;
2625 slc.
tjs[itj].VtxID[
end] = slc.
vtxs[newVtxIndx].ID;
2628 mf::LogVerbatim(
"TC") <<
" attach Traj T" << slc.
tjs[itj].ID <<
" at end " <<
end;
2630 vpos = slc.
tjs[itj].Pts[slc.
tjs[itj].EndPt[
end]].Pos;
2634 if (
SplitTraj(slc, itj, closePt, newVtxIndx, prt)) {
2636 mf::LogVerbatim(
"TC")
2637 <<
" SplitTraj success 2V" << slc.
vtxs[newVtxIndx].ID <<
" at closePt " << closePt;
2643 if (prt) mf::LogVerbatim(
"TC") <<
" SplitTraj failed";
2653 unsigned short newtj = slc.
tjs.size() - 1;
2656 if (newVtx.
NTraj == 0) {
2658 if (prt) mf::LogVerbatim(
"TC") <<
" Failed. Recover and delete vertex " << newVtx.
ID;
2663 vx3.Vx2ID[mPlane] = newVtx.
ID;
2664 newVtx.
Vx3ID = vx3.ID;
2667 if (newVtx.
NTraj == 1) {
2674 mf::LogVerbatim myprt(
"TC");
2675 myprt <<
" Success: new 2V" << newVtx.
ID <<
" at " << (int)newVtx.
Pos[0] <<
":"
2677 myprt <<
" points to 3V" << vx3.ID;
2679 for (
auto& tjID : tjIDs)
2692 unsigned short& nearPt,
2699 float maxChg = tj.
Pts[nearPt].Chg;
2700 short maxChgPt = nearPt;
2701 unsigned short fromPt = tj.
EndPt[0];
2702 short spt = (short)nearPt - (
short)nPtsToChk;
2703 if (spt > (
short)fromPt) fromPt = nearPt - nPtsToChk;
2704 unsigned short toPt = nearPt + nPtsToChk;
2707 for (
short ipt = fromPt; ipt <= toPt; ++ipt) {
2708 if (ipt < tj.
EndPt[0] || ipt > tj.
EndPt[1])
continue;
2709 auto& tp = tj.
Pts[ipt];
2710 if (tp.Chg > maxChg) {
2715 mf::LogVerbatim(
"TC") <<
"RVP: ipt " << ipt <<
" Pos " << tp.CTP <<
":"
2716 <<
PrintPos(slc, tp.Pos) <<
" chg " << (int)tp.Chg <<
" nhits "
2719 if (nearPt == maxChgPt)
return false;
2731 bool hasHighScoreVx3 = (vx2.
Vx3ID > 0);
2736 mf::LogVerbatim(
"TC") << fcnLabel <<
" MVO: killing 2V" << vx2.
ID;
2741 if (vx2.
Vx3ID > 0) {
2743 for (
auto& v3v2id : vx3.Vx2ID)
2744 if (v3v2id == vx2.
ID) v3v2id = 0;
2747 for (
auto& tj : slc.
tjs) {
2749 for (
unsigned short end = 0;
end < 2; ++
end) {
2750 if (tj.VtxID[
end] != vx2id)
continue;
2754 for (
unsigned short ii = 0; ii < tj.Pts.size(); ++ii) {
2756 unsigned short ipt = tj.EndPt[0] + ii;
2757 auto& tp = tj.Pts[ipt];
2759 if (ipt == tj.EndPt[1])
break;
2762 unsigned short ipt = tj.EndPt[1] - ii;
2763 auto& tp = tj.Pts[ipt];
2765 if (ipt == tj.EndPt[0])
break;
2770 unsigned short oend = 1 -
end;
2771 if (tj.VtxID[oend] > 0) {
2772 auto& ovx2 = slc.
vtxs[tj.VtxID[oend] - 1];
2779 if (!hasHighScoreVx3)
return true;
2785 unsigned short plane = planeID.
Plane;
2786 if (vx3.
Vx2ID[plane] != vx2id)
return true;
2787 vx3.
Vx2ID[plane] = 0;
2790 unsigned short n2D = 0;
2791 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane)
2792 if (vx3.
Vx2ID[plane] > 0) ++n2D;
2803 for (
auto& vx2 : slc.
vtxs) {
2804 if (vx2.
ID == 0)
continue;
2807 for (
auto& pfp : slc.
pfps) {
2808 for (
unsigned short end = 0;
end < 2; ++
end)
2809 if (pfp.Vx3ID[
end] == vx3.
ID) pfp.Vx3ID[
end] = 0;
2823 if (vx3.
ID <= 0)
return true;
2824 if (vx3.
ID >
int(slc.
vtx3s.size()))
return false;
2826 for (
auto vx2id : vx3.
Vx2ID) {
2827 if (vx2id == 0 || vx2id > (
int)slc.
vtxs.size())
continue;
2828 auto& vx2 = slc.
vtxs[vx2id - 1];
2840 std::vector<int> tmp;
2841 if (vx2.
ID == 0)
return tmp;
2842 for (
auto& tj : slc.
tjs) {
2843 if (tj.AlgMod[
kKilled])
continue;
2844 if (tj.CTP != vx2.
CTP)
continue;
2845 for (
unsigned short end = 0;
end < 2; ++
end) {
2846 if (tj.VtxID[
end] == vx2.
ID) tmp.push_back(tj.ID);
2857 std::vector<int> tmp;
2858 if (vx3.
ID == 0)
return tmp;
2861 for (
auto& vx2 : slc.
vtxs) {
2862 if (vx2.ID == 0)
continue;
2863 if (vx2.Vx3ID != vx3.
ID)
continue;
2865 tmp.insert(tmp.end(), vtxTjID2.begin(), vtxTjID2.end());
2869 if (nvx2 < 1)
return tmp;
2873 std::sort(tmp.begin(), tmp.end());
2882 unsigned short plane,
2899 unsigned short imBest = 0;
2900 for (
auto& vx2 : slc.
vtxs) {
2901 if (vx2.CTP != inVx2.
CTP)
continue;
2902 if (vx2.ID <= 0)
continue;
2904 if (pull < minPull) {
2919 unsigned short imBest = 0;
2920 for (
auto& oldvx3 : slc.
vtx3s) {
2921 if (oldvx3.ID == 0)
continue;
2924 if (pull < minPull) {
Expect tracks entering from the front face. Don't create neutrino PFParticles.
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
BEGIN_PROLOG or simple_flux see Environment
short MCSMom(const TCSlice &slc, const std::vector< int > &tjIDs)
process_name opflash particleana ie ie ie z
std::vector< Trajectory > tjs
vector of all trajectories in each plane
unsigned short FarEnd(const TCSlice &slc, const PFPStruct &pfp, const Point3_t &pos)
float Length(const PFPStruct &pfp)
bool MergeWithVertex(TCSlice &slc, VtxStore &vx, unsigned short oVxID)
then if[["$THISISATEST"==1]]
bool MakeVertexObsolete(std::string fcnLabel, TCSlice &slc, VtxStore &vx2, bool forceKill)
unsigned short CloseEnd(const TCSlice &slc, const Trajectory &tj, const Point2_t &pos)
struct of temporary 2D vertices (end points)
std::vector< int > GetAssns(TCSlice &slc, std::string type1Name, int id, std::string type2Name)
static unsigned int kWire
float TrajPointVertexPull(const TCSlice &slc, const TrajPoint &tp, const VtxStore &vx)
bool AttachAnyVertexToTraj(TCSlice &slc, int tjID, bool prt)
CTP_t CTP
Cryostat, TPC, Plane code.
std::vector< float > maxPos0
void CompleteIncomplete3DVerticesInGaps(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc)
std::array< double, 3 > Point3_t
bool SignalAtTp(TrajPoint &tp)
bool FitVertex(TCSlice &slc, VtxStore &vx, bool prt)
std::vector< float > vtx3DCuts
2D vtx -> 3D vtx matching cuts
void SetPDGCode(TCSlice &slc, unsigned short itj)
void Find3DVertices(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc)
void Print2V(std::string someText, mf::LogVerbatim &myprt, VtxStore &vx2, bool &printHeader)
vertex position fixed manually - no fitting done
EResult err(const char *call)
void SplitTrajCrossingVertices(TCSlice &slc, CTP_t inCTP)
void PrintTP(std::string someText, const TCSlice &slc, unsigned short ipt, short dir, unsigned short pass, const TrajPoint &tp)
void Reconcile2Vs(TCSlice &slc)
Planes which measure X direction.
The data type to uniquely identify a Plane.
matched to a high-score 3D vertex
BEGIN_PROLOG or score(default)}sbnd_crttrackmatchingalg_crID
step from US -> DS (true) or DS -> US (false)
short MCSMom
Normalized RMS using ALL hits. Assume it is 50% to start.
bool RefineVtxPosition(TCSlice &slc, const Trajectory &tj, unsigned short &nearPt, short nPtsToChk, bool prt)
std::string PrintPos(const TCSlice &slc, const TrajPoint &tp)
CryostatID_t Cryostat
Index of cryostat.
std::size_t size(FixedBins< T, C > const &) noexcept
bool TrajClosestApproach(Trajectory const &tj, float x, float y, unsigned short &closePt, float &DOCA)
void PosInPlane(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, const Vtx3Store &vx3, unsigned short plane, Point2_t &pos)
bool AttachAnyTrajToVertex(TCSlice &slc, unsigned short ivx, bool prt)
unsigned short TPNearVertex(const TCSlice &slc, const TrajPoint &tp)
Point3_t PosAtEnd(const PFPStruct &pfp, unsigned short end)
float PointTrajDOCA(const TCSlice &slc, unsigned int iht, TrajPoint const &tp)
double DeltaAngle(const Vector3_t v1, const Vector3_t v2)
bool dbgSlc
debug only in the user-defined slice? default is all slices
std::array< int, 2 > Vx3ID
void SetVx3Score(TCSlice &slc, Vtx3Store &vx3)
tick ticks
Alias for common language habits.
void CompleteIncomplete3DVertices(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc)
bool StoreVertex(TCSlice &slc, VtxStore &vx)
bool dbg3V
debug 3D vertex finding
Access the description of detector geometry.
struct of temporary 3D vertices
void PrintAllTraj(detinfo::DetectorPropertiesData const &detProp, std::string someText, TCSlice &slc, unsigned short itj, unsigned short ipt, bool prtVtx)
process_name opflash particleana ie ie y
std::array< float, 2 > Point2_t
std::vector< float > maxPos1
float unitsPerTick
scale factor from Tick to WSE equivalent units
float DeadWireCount(const TCSlice &slc, const TrajPoint &tp1, const TrajPoint &tp2)
unsigned short NearbyCleanPt(const TCSlice &slc, const Trajectory &tj, unsigned short end)
Vector3_t PointDirection(const Point3_t p1, const Point3_t p2)
CTP_t CTP
Cryostat, TPC, Plane code.
the environment near the vertex was checked - See UpdateVxEnvironment
bool dbg2V
debug 2D vertex finding
std::vector< TrajPoint > Pts
Trajectory points.
bool ChkVtxAssociations(TCSlice &slc, const CTP_t &inCTP)
bool Reconcile2VTs(TCSlice &slc, std::vector< int > &vx2cls, bool prt)
for($it=0;$it< $RaceTrack_number;$it++)
float ChgFracNearPos(const TCSlice &slc, const Point2_t &pos, const std::vector< int > &tjIDs)
std::vector< unsigned int > FindCloseHits(const TCSlice &slc, std::array< int, 2 > const &wireWindow, Point2_t const &timeWindow, const unsigned short plane, HitStatus_t hitRequest, bool usePeakTime, bool &hitsNear)
auto end(FixedBins< T, C > const &) noexcept
std::vector< VtxStore > vtxs
2D vertices
std::array< unsigned short, 2 > EndPt
First and last point in the trajectory that has charge.
unsigned short PDGCode
shower-like or track-like {default is track-like}
double ConvertXToTicks(double X, int p, int t, int c) const
void ScoreVertices(TCSlice &slc)
double PosSep2(const Point3_t &pos1, const Point3_t &pos2)
std::string PrintHit(const TCHit &tch)
bool SplitTraj(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, unsigned short itj, float XPos, bool makeVx2, bool prt)
void TrajPointTrajDOCA(const TCSlice &slc, TrajPoint const &tp, Trajectory const &tj, unsigned short &closePt, float &minSep)
const geo::GeometryCore * geom
PlaneID_t Plane
Index of the plane within its TPC.
unsigned short NearestPtWithChg(const TCSlice &slc, const Trajectory &tj, unsigned short thePt)
bool valsIncreasing(const SortEntry &c1, const SortEntry &c2)
bool IntersectionPoint(geo::WireID const &wid1, geo::WireID const &wid2, double &y, double &z) const
Returns the intersection point of two wires.
Definition of data types for geometry description.
int ID
ID that is local to one slice.
std::array< unsigned short, 2 > VtxID
ID of 2D vertex.
vertex quality is suspect - No requirement made on chg btw it and the Tj
double ConvertTicksToX(double ticks, int p, int t, int c) const
std::bitset< 16 > modes
number of points to find AveChg
std::vector< TCHit > slHits
unsigned short IsCloseToVertex(const TCSlice &slc, const VtxStore &inVx2)
float VertexVertexPull(const TCSlice &slc, const Vtx3Store &vx1, const Vtx3Store &vx2)
std::bitset< 16 > Stat
Vertex status bits using kVtxBit_t.
void TrajIntersection(TrajPoint const &tp1, TrajPoint const &tp2, Point2_t &pos)
std::vector< float > vtxScoreWeights
double DotProd(const Vector3_t &v1, const Vector3_t &v2)
void SetHighScoreBits(TCSlice &slc, Vtx3Store &vx3)
std::vector< Vtx3Store > vtx3s
3D vertices
bool AttachTrajToVertex(TCSlice &slc, Trajectory &tj, VtxStore &vx, bool prt)
std::bitset< 128 > useAlg
Max hit separation for making junk trajectories. < 0 to turn off.
float TrajLength(const Trajectory &tj)
std::string to_string(WindowPattern const &pattern)
std::bitset< 128 > AlgMod
Bit set if algorithm AlgBit_t modifed the trajectory.
void UpdateVxEnvironment(TCSlice &slc)
geo::PlaneID DecodeCTP(CTP_t CTP)
std::vector< int > GetVtxTjIDs(const TCSlice &slc, const VtxStore &vx2)
double PosSep(const Point3_t &pos1, const Point3_t &pos2)
std::bitset< 128 > dbgAlg
Allow user to turn on debug printing in algorithms (that print...)
bool valsDecreasing(const SortEntry &c1, const SortEntry &c2)
CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
void KillPoorVertices(TCSlice &slc)
std::array< std::bitset< 8 >, 2 > EndFlag
int ID
ID of the recob::Slice (not the sub-slice)
void SetVx2Score(TCSlice &slc)
void FindHammerVertices(TCSlice &slc, const CTP_t &inCTP)
std::vector< float > vtx2DCuts
Max position pull, max Position error rms.
std::vector< PFPStruct > pfps
std::vector< int > FindCloseTjs(const TCSlice &slc, const TrajPoint &fromTp, const TrajPoint &toTp, const float &maxDelta)
bool SignalBetween(const TCSlice &slc, const TrajPoint &tp1, const TrajPoint &tp2, const float &MinWireSignalFraction)
void MoveTPToWire(TrajPoint &tp, float wire)
unsigned short NumPtsWithCharge(const TCSlice &slc, const Trajectory &tj, bool includeDeadWires)
void MakeJunkVertices(TCSlice &slc, const CTP_t &inCTP)
void Find2DVertices(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, const CTP_t &inCTP, unsigned short pass)
print OUTPUT<< EOF;< setup name="Default"version="1.0">< worldref="volWorld"/></setup ></gdml > EOF close(OUTPUT)
TPCID_t TPC
Index of the TPC within its cryostat.
bool TrajTrajDOCA(const TCSlice &slc, const Trajectory &tj1, const Trajectory &tj2, unsigned short &ipt1, unsigned short &ipt2, float &minSep)
Vector3_t DirAtEnd(const PFPStruct &pfp, unsigned short end)
void FindHammerVertices2(TCSlice &slc, const CTP_t &inCTP)
float TjChgFrac
Fraction of charge near the vertex that is from hits on the vertex Tjs.
master switch for turning on debug mode
bool AttachToAnyVertex(TCSlice &slc, PFPStruct &pfp, float maxSep, bool prt)
void PrintTPHeader(std::string someText)
CTP_t CTP
set to an invalid CTP