5 #include "TDecompSVD.h" 38 using namespace detail;
45 if (
slices.size() < 2)
return;
54 std::string fcnLabel =
"SP";
57 bool printHeader =
true;
58 for (
size_t isl = 0; isl <
slices.size(); ++isl) {
61 if (slc.pfps.empty())
continue;
62 for (
auto& pfp : slc.pfps)
63 PrintP(myprt, pfp, printHeader);
68 std::vector<std::vector<int>> stLists;
69 for (std::size_t sl1 = 0; sl1 <
slices.size() - 1; ++sl1) {
71 for (std::size_t sl2 = sl1 + 1; sl2 <
slices.size(); ++sl2) {
74 if (slc1.ID != slc2.ID)
continue;
75 for (
auto& p1 : slc1.pfps) {
76 if (p1.ID <= 0)
continue;
78 if (p1.PDGCode == 1111)
continue;
79 for (
auto& p2 : slc2.pfps) {
80 if (p2.ID <= 0)
continue;
82 if (p2.PDGCode == 1111)
continue;
86 for (
unsigned short e1 = 0; e1 < 2; ++e1) {
89 if (
InsideFV(slc1, p1, e1))
continue;
91 for (
unsigned short e2 = 0; e2 < 2; ++e2) {
94 if (
InsideFV(slc2, p2, e2))
continue;
96 float sep =
PosSep2(pos1, pos2);
97 if (sep > maxSep2)
continue;
99 if (cth < maxCth)
continue;
105 if (!gotit)
continue;
108 myprt <<
"Stitch slice " << slc1.ID <<
" P" << p1.UID <<
" TPC " << p1.TPCID.TPC;
109 myprt <<
" and P" << p2.UID <<
" TPC " << p2.TPCID.TPC;
110 myprt <<
" sep " << sqrt(maxSep2) <<
" maxCth " << maxCth;
114 for (
auto& pm : stLists) {
115 bool p1InList = (std::find(pm.begin(), pm.end(), p1.UID) != pm.end());
116 bool p2InList = (std::find(pm.begin(), pm.end(), p2.UID) != pm.end());
117 if (p1InList || p2InList) {
118 if (p1InList) pm.push_back(p2.UID);
119 if (p2InList) pm.push_back(p1.UID);
125 std::vector<int>
tmp(2);
128 stLists.push_back(tmp);
134 if (stLists.empty())
return;
136 for (
auto& stl : stLists) {
139 std::pair<unsigned short, unsigned short> minZIndx;
140 unsigned short minZEnd = 2;
141 for (
auto puid : stl) {
143 if (slcIndex.first == USHRT_MAX)
continue;
144 auto& pfp =
slices[slcIndex.first].pfps[slcIndex.second];
145 for (
unsigned short end = 0;
end < 2; ++
end) {
154 if (minZEnd > 1)
continue;
156 auto& pfp =
slices[minZIndx.first].pfps[minZIndx.second];
159 for (
auto puid : stl) {
160 if (puid == pfp.UID)
continue;
162 if (sIndx.first == USHRT_MAX)
continue;
163 auto& opfp =
slices[sIndx.first].pfps[sIndx.second];
165 pfp.TjUIDs.insert(pfp.TjUIDs.end(), opfp.TjUIDs.begin(), opfp.TjUIDs.end());
168 if (opfp.ParentUID > 0) {
170 if (pSlcIndx.first <
slices.size()) {
171 auto& parpfp =
slices[pSlcIndx.first].pfps[pSlcIndx.second];
172 std::replace(parpfp.DtrUIDs.begin(), parpfp.DtrUIDs.begin(), opfp.UID, pfp.UID);
175 for (
auto dtruid : opfp.DtrUIDs) {
177 if (dSlcIndx.first <
slices.size()) {
178 auto& dtrpfp =
slices[dSlcIndx.first].pfps[dSlcIndx.second];
179 dtrpfp.ParentUID = pfp.UID;
200 for (
auto& tj : slc.
tjs) {
201 for (
auto& tp : tj.Pts)
208 std::vector<MatchStruct> matVec;
215 unsigned short maxNit = 2;
216 if (slc.
nPlanes == 2) maxNit = 1;
220 for (
unsigned short nit = 0; nit < maxNit; ++nit) {
222 if (slc.
nPlanes == 3 && nit == 0) {
230 if (matVec.empty())
continue;
233 myprt <<
"nit " << nit <<
" MVI Count Tjs\n";
234 for (
unsigned int indx = 0; indx < matVec.size(); ++indx) {
235 auto& ms = matVec[indx];
236 myprt << std::setw(5) << indx << std::setw(6) << (int)ms.Count;
237 for (
auto tid : ms.TjIDs)
238 myprt <<
" T" << tid;
241 for (
auto tid : ms.TjIDs) {
242 auto& tj = slc.
tjs[tid - 1];
245 float frac = ms.Count / tpCnt;
246 myprt <<
" matFrac " << std::fixed << std::setprecision(3) << frac;
255 for (
auto& pfp : slc.
pfps)
257 PrintTP3Ds(clockData, detProp,
"FPFP", slc, pfp, -1);
268 std::vector<MatchStruct> matVec,
269 unsigned short matVec_Iter)
272 if (matVec.empty())
return;
277 for (std::size_t indx = 0; indx < matVec.size(); ++indx) {
280 if (foundMVI) prt =
true;
281 auto& ms = matVec[indx];
283 std::cout <<
"found MVI " << indx <<
" in MakePFParticles ms.Count = " << ms.Count <<
"\n";
286 if (ms.Count == 0)
continue;
289 for (std::size_t itj = 0; itj < ms.TjIDs.size(); ++itj) {
290 auto& tj = slc.
tjs[ms.TjIDs[itj] - 1];
291 for (
unsigned short ipt = tj.EndPt[0]; ipt <= tj.EndPt[1]; ++ipt)
292 if (tj.Pts[ipt].InPFP == 0) ++npts;
295 std::vector<PFPStruct> pfpVec(1);
298 pfpVec[0].TjIDs = ms.TjIDs;
299 pfpVec[0].MVI = indx;
302 if (!
MakeTP3Ds(detProp, slc, pfpVec[0], foundMVI)) {
303 if (foundMVI)
mf::LogVerbatim(
"TC") <<
" MakeTP3Ds failed. Too many points already used ";
307 if (!
FitSection(detProp, slc, pfpVec[0], 0))
continue;
308 if (pfpVec[0].SectionFits[0].ChiDOF > 500 && !pfpVec[0].Flags[
kSmallAngle]) {
311 << pfpVec[0].SectionFits[0].ChiDOF <<
"\n";
312 Recover(detProp, slc, pfpVec[0], foundMVI);
320 npts = pfpVec[0].TP3Ds.size();
321 pfpVec[0].AlgMod[
kJunk3D] = (npts < 20 &&
MCSMom(slc, pfpVec[0].TjIDs) < 50) || (npts < 10);
323 auto& pfp = pfpVec[0];
325 myprt <<
" indx " << matVec_Iter <<
"/" << indx <<
" Count " << std::setw(5)
327 myprt <<
" P" << pfpVec[0].ID;
329 for (
auto& tjid : pfp.TjIDs)
330 myprt <<
" T" << tjid;
331 myprt <<
" projInPlane";
332 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
333 CTP_t inCTP =
EncodeCTP(pfp.TPCID.Cryostat, pfp.TPCID.TPC, plane);
334 auto tp =
MakeBareTP(detProp, pfp.SectionFits[0].Pos, pfp.SectionFits[0].Dir, inCTP);
335 myprt <<
" " << std::setprecision(2) << tp.Delta;
337 myprt <<
" maxTjLen " << (int)
MaxTjLen(slc, pfp.TjIDs);
338 myprt <<
" MCSMom " <<
MCSMom(slc, pfp.TjIDs);
339 myprt <<
" PDGCodeVote " <<
PDGCodeVote(clockData, detProp, slc, pfp);
340 myprt <<
" nTP3Ds " << pfp.TP3Ds.size();
341 myprt <<
" Reco3DRange " 344 if (foundMVI) {
PrintTP3Ds(clockData, detProp,
"FF", slc, pfpVec[0], -1); }
345 for (
unsigned short ip = 0; ip < pfpVec.size(); ++ip) {
346 auto& pfp = pfpVec[ip];
349 for (
unsigned short end = 0;
end < 2; ++
end) {
351 pfp.EndFlag[
end].reset();
357 pfp.EndFlag[0][
kAtKink] =
true;
360 vx3.
X = pfp.TP3Ds[0].Pos[0];
361 vx3.
Y = pfp.TP3Ds[0].Pos[1];
362 vx3.
Z = pfp.TP3Ds[0].Pos[2];
371 slc.
vtx3s.push_back(vx3);
372 pfp.Vx3ID[0] = vx3.
ID;
373 auto& prevPFP = slc.
pfps[slc.
pfps.size() - 1];
374 prevPFP.Vx3ID[1] = vx3.
ID;
379 if (pfp.TjIDs.size() == 2 && slc.
nPlanes == 3 && pfp.TP3Ds.size() > 20 &&
394 if (!
ReSection(detProp, slc, pfp, foundMVI))
continue;
396 if (foundMVI) {
PrintTP3Ds(clockData, detProp,
"RS", slc, pfp, -1); }
401 FillGaps3D(clockData, detProp, slc, pfp, foundMVI);
407 for (
auto& tp3d : pfp.TP3Ds) {
409 auto& tp = slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex];
412 FilldEdx(clockData, detProp, slc, pfp);
413 pfp.PDGCode =
PDGCodeVote(clockData, detProp, slc, pfp);
415 PrintTP3Ds(clockData, detProp,
"STORE", slc, pfp, -1);
432 if (pfp.
TjIDs.empty())
return false;
433 if (pfp.
TP3Ds.empty())
return false;
434 if (pfp.
ID <= 0)
return false;
437 std::vector<std::pair<int, float>> tjTPCnt;
438 for (
auto& tp3d : pfp.
TP3Ds) {
440 if (tp3d.TjID <= 0)
return false;
442 auto& tp = slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex];
443 if (tp.InPFP > 0 && tp.InPFP != pfp.
ID)
return false;
445 unsigned short indx = 0;
446 for (indx = 0; indx < tjTPCnt.size(); ++indx)
447 if (tjTPCnt[indx].first == tp3d.TjID)
break;
448 if (indx == tjTPCnt.size()) tjTPCnt.push_back(std::make_pair(tp3d.TjID, 0));
449 ++tjTPCnt[indx].second;
454 std::vector<int> nTjIDs;
455 for (
auto& tjtpcnt : tjTPCnt) {
456 auto& tj = slc.
tjs[tjtpcnt.first - 1];
458 if (tjtpcnt.second > 0.8 * npwc) nTjIDs.push_back(tjtpcnt.first);
460 if (prt) {
mf::LogVerbatim(
"TC") <<
"RTPs3D: P" << pfp.
ID <<
" nTjIDs " << nTjIDs.size(); }
462 if (nTjIDs.size() < 2) {
return false; }
481 std::vector<int> TinP;
482 for (
auto& pfp : slc.
pfps) {
483 if (pfp.ID <= 0)
continue;
485 for (std::size_t ipt = 0; ipt < pfp.TP3Ds.size(); ++ipt) {
486 auto& tp3d = pfp.TP3Ds[ipt];
487 if (tp3d.TjID <= 0)
continue;
488 if (std::find(TinP.begin(), TinP.end(), tp3d.TjID) == TinP.end()) TinP.push_back(tp3d.TjID);
489 auto& tp = slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex];
515 std::vector<int> killme;
516 for (
auto& pfp : slc.
pfps) {
517 if (pfp.ID <= 0)
continue;
518 for (
auto& tp3d : pfp.TP3Ds) {
519 if (tp3d.TjID <= 0)
continue;
521 if (std::find(killme.begin(), killme.end(), tp3d.TjID) == killme.end())
522 killme.push_back(tp3d.TjID);
528 for (
auto tid : killme)
533 std::vector<Trajectory> ptjs(slc.
nPlanes);
535 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
536 ptjs[plane].Pass = 0;
539 ptjs[plane].StepDir = 0;
543 ptjs[plane].AlgMod[
kMat3D] =
true;
547 for (
auto& pfp : slc.
pfps) {
548 if (pfp.ID <= 0)
continue;
550 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
551 ptjs[plane].Pts.clear();
559 for (
auto& tp3d : pfp.TP3Ds) {
560 if (tp3d.TjID <= 0)
continue;
563 auto tp = slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex];
564 if (tp.InPFP > 0 && tp.InPFP != pfp.ID)
continue;
570 ptjs[plane].Pts.push_back(tp);
574 std::vector<int> tids(ptjs.size(), 0);
575 for (
unsigned short plane = 0; plane < ptjs.size(); ++plane) {
576 auto& tj = ptjs[plane];
577 if (tj.Pts.size() < 2)
continue;
578 tj.PDGCode = pfp.PDGCode;
579 tj.MCSMom =
MCSMom(slc, tj);
582 auto& newTj = slc.
tjs.back();
583 pfp.TjIDs.push_back(newTj.ID);
584 tids[plane] = newTj.ID;
587 for (
unsigned short end = 0;
end < 2; ++
end) {
588 if (pfp.Vx3ID[
end] <= 0)
continue;
589 auto& vx3 = slc.
vtx3s[pfp.Vx3ID[
end] - 1];
590 for (
unsigned short plane = 0; plane < ptjs.size(); ++plane) {
591 if (tids[plane] == 0)
continue;
592 if (vx3.Vx2ID[plane] <= 0)
continue;
593 auto& vx2 = slc.
vtxs[vx3.Vx2ID[plane] - 1];
594 auto& tj = slc.
tjs[tids[plane] - 1];
596 tj.VtxID[tend] = vx2.ID;
598 mf::LogVerbatim(
"TC") <<
"MPFPTjs: 3V" << vx3.ID <<
" -> 2V" << vx2.ID <<
" -> T" 599 << tj.ID <<
"_" << tend <<
" in plane " << plane;
618 unsigned int maxWire = slc.
nWires[0];
619 for (
auto nw : slc.
nWires)
620 if (nw < maxWire) maxWire = nw;
622 unsigned int firstWire = maxWire / 2;
625 std::vector<std::pair<unsigned short, unsigned short>> pln1pln2;
626 for (
unsigned short pln1 = 0; pln1 < slc.
nPlanes - 1; ++pln1) {
627 for (
unsigned short pln2 = pln1 + 1; pln2 < slc.
nPlanes; ++pln2) {
628 auto p1p2 = std::make_pair(pln1, pln2);
629 if (std::find(pln1pln2.begin(), pln1pln2.end(), p1p2) != pln1pln2.end())
continue;
631 for (
unsigned int wire = firstWire; wire < maxWire; ++wire) {
658 tcwi.
dydw1 = (y10 - y00) / 10;
659 tcwi.
dzdw1 = (z10 - z00) / 10;
660 tcwi.
dydw2 = (y01 - y00) / 10;
661 tcwi.
dzdw2 = (z01 - z00) / 10;
680 if (pln1 == pln2)
return false;
683 std::swap(pln1, pln2);
684 std::swap(wir1, wir2);
688 if (wi.pln1 != pln1)
continue;
689 if (wi.pln2 != pln2)
continue;
691 double dw1 = wir1 - wi.wir1;
692 double dw2 = wir2 - wi.wir2;
693 y = (float)(wi.y + dw1 * wi.dydw1 + dw2 * wi.dydw2);
694 z = (float)(wi.z + dw1 * wi.dzdw1 + dw2 * wi.dzdw2);
707 std::vector<int> inTraj((*
evt.
allHits).size(), 0);
708 for (
auto& tch : slc.
slHits)
709 inTraj[tch.allHitsIndex] = tch.InTraj;
712 std::array<int, 3> tIDs;
714 std::vector<std::array<int, 3>> mtIDs;
716 std::vector<unsigned short> mCnt;
718 unsigned short maxCnt = USHRT_MAX;
721 std::vector<unsigned short> tMaxed;
726 if (sptHits.size() != 3)
continue;
728 if (!
SptInTPC(sptHits, tpc))
continue;
729 unsigned short cnt = 0;
730 for (
unsigned short plane = 0; plane < 3; ++plane) {
731 unsigned int iht = sptHits[plane];
732 if (iht == UINT_MAX)
continue;
733 if (inTraj[iht] <= 0)
continue;
734 tIDs[plane] = inTraj[iht];
737 if (cnt != 3)
continue;
739 unsigned short indx = 0;
740 for (indx = 0; indx < mtIDs.size(); ++indx)
741 if (tIDs == mtIDs[indx])
break;
742 if (indx == mtIDs.size()) {
744 mtIDs.push_back(tIDs);
748 if (mCnt[indx] == maxCnt) {
750 tMaxed.insert(tMaxed.end(), tIDs[0]);
751 tMaxed.insert(tMaxed.end(), tIDs[1]);
752 tMaxed.insert(tMaxed.end(), tIDs[2]);
758 std::vector<SortEntry> sortVec;
759 for (
unsigned short indx = 0; indx < mCnt.size(); ++indx) {
760 auto& tIDs = mtIDs[indx];
762 float minTPCnt = USHRT_MAX;
763 for (
auto tid : tIDs) {
764 auto& tj = slc.
tjs[tid - 1];
766 if (tpcnt < minTPCnt) minTPCnt = tpcnt;
768 float frac = (float)mCnt[indx] / minTPCnt;
770 if (frac < 0.05)
continue;
774 sortVec.push_back(se);
776 if (sortVec.size() > 1) std::sort(sortVec.begin(), sortVec.end(),
valsDecreasing);
778 matVec.resize(sortVec.size());
780 for (
unsigned short ii = 0; ii < sortVec.size(); ++ii) {
781 unsigned short indx = sortVec[ii].index;
782 auto& ms = matVec[ii];
783 ms.Count = mCnt[indx];
785 for (
unsigned short plane = 0; plane < 3; ++plane)
786 ms.TjIDs[plane] = mtIDs[indx][plane];
792 bool SptInTPC(
const std::array<unsigned int, 3>& sptHits,
unsigned int tpc)
797 unsigned int ahi = UINT_MAX;
798 for (
auto ii : sptHits)
799 if (ii != UINT_MAX) {
803 if (ahi >= (*
evt.
allHits).size())
return false;
806 if (
hit.WireID().TPC == tpc)
return true;
829 std::array<unsigned short, 3> tIDs;
831 std::vector<std::array<unsigned short, 3>> mtIDs;
833 std::vector<unsigned short> mCnt;
835 unsigned short maxCnt = USHRT_MAX;
838 std::vector<unsigned short> tMaxed;
840 for (std::size_t ipt = 0; ipt < slc.
mallTraj.size() - 1; ++ipt) {
843 if (std::find(tMaxed.begin(), tMaxed.end(), iTjPt.id) != tMaxed.end())
continue;
844 auto& itp = slc.
tjs[iTjPt.id - 1].Pts[iTjPt.ipt];
845 unsigned int iPlane = iTjPt.plane;
846 unsigned int iWire = std::nearbyint(itp.Pos[0]);
847 tIDs[iPlane] = iTjPt.id;
848 bool hitMaxCnt =
false;
849 for (std::size_t jpt = ipt + 1; jpt < slc.
mallTraj.size() - 1; ++jpt) {
852 if (jTjPt.plane == iTjPt.plane)
continue;
854 if (jTjPt.xlo > iTjPt.xhi)
continue;
856 if (jTjPt.xlo > iTjPt.xhi + xcut)
break;
858 if (std::find(tMaxed.begin(), tMaxed.end(), jTjPt.id) != tMaxed.end())
continue;
859 auto& jtp = slc.
tjs[jTjPt.id - 1].Pts[jTjPt.ipt];
860 unsigned short jPlane = jTjPt.plane;
861 unsigned int jWire = jtp.Pos[0];
864 tIDs[jPlane] = jTjPt.id;
865 for (std::size_t kpt = jpt + 1; kpt < slc.
mallTraj.size(); ++kpt) {
868 if (kTjPt.plane == iTjPt.plane || kTjPt.plane == jTjPt.plane)
continue;
869 if (kTjPt.xlo > iTjPt.xhi)
continue;
871 if (kTjPt.xlo > iTjPt.xhi + xcut)
break;
873 if (std::find(tMaxed.begin(), tMaxed.end(), kTjPt.id) != tMaxed.end())
continue;
874 auto& ktp = slc.
tjs[kTjPt.id - 1].Pts[kTjPt.ipt];
875 unsigned short kPlane = kTjPt.plane;
876 unsigned int kWire = ktp.Pos[0];
879 if (
std::abs(ijPos[0] - ikPos[0]) > yzcut)
continue;
880 if (
std::abs(ijPos[1] - ikPos[1]) > yzcut)
continue;
884 unsigned int indx = 0;
885 for (indx = 0; indx < mtIDs.size(); ++indx)
886 if (tIDs == mtIDs[indx])
break;
887 if (indx == mtIDs.size()) {
889 mtIDs.push_back(tIDs);
893 if (mCnt[indx] == maxCnt) {
895 tMaxed.insert(tMaxed.end(), tIDs[0]);
896 tMaxed.insert(tMaxed.end(), tIDs[1]);
897 tMaxed.insert(tMaxed.end(), tIDs[2]);
902 if (hitMaxCnt)
break;
906 if (mCnt.empty())
return;
908 std::vector<SortEntry> sortVec;
909 for (std::size_t indx = 0; indx < mCnt.size(); ++indx) {
910 auto& tIDs = mtIDs[indx];
913 for (
auto tid : tIDs) {
914 auto& tj = slc.
tjs[tid - 1];
917 float frac = mCnt[indx] / tpCnt;
920 if (frac < 0.05)
continue;
924 sortVec.push_back(se);
926 if (sortVec.size() > 1) std::sort(sortVec.begin(), sortVec.end(),
valsDecreasing);
928 matVec.resize(sortVec.size());
930 for (std::size_t ii = 0; ii < sortVec.size(); ++ii) {
931 unsigned short indx = sortVec[ii].index;
932 auto& ms = matVec[ii];
933 ms.Count = mCnt[indx];
935 for (
unsigned short plane = 0; plane < 3; ++plane)
936 ms.TjIDs[plane] = (
int)mtIDs[indx][plane];
955 std::array<unsigned short, 2> tIDs;
957 std::vector<std::array<unsigned short, 2>> mtIDs;
959 std::vector<unsigned short> mCnt;
961 unsigned short maxCnt = USHRT_MAX;
964 std::vector<unsigned short> tMaxed;
966 for (std::size_t ipt = 0; ipt < slc.
mallTraj.size() - 1; ++ipt) {
969 if (std::find(tMaxed.begin(), tMaxed.end(), iTjPt.id) != tMaxed.end())
continue;
970 auto& itp = slc.
tjs[iTjPt.id - 1].Pts[iTjPt.ipt];
971 unsigned short iPlane = iTjPt.plane;
972 unsigned int iWire = itp.Pos[0];
973 bool hitMaxCnt =
false;
974 for (std::size_t jpt = ipt + 1; jpt < slc.
mallTraj.size() - 1; ++jpt) {
977 if (jTjPt.plane == iTjPt.plane)
continue;
979 if (jTjPt.xlo > iTjPt.xhi)
continue;
981 if (jTjPt.xlo > iTjPt.xhi + xcut)
break;
983 if (std::find(tMaxed.begin(), tMaxed.end(), jTjPt.id) != tMaxed.end())
continue;
984 auto& jtp = slc.
tjs[jTjPt.id - 1].Pts[jTjPt.ipt];
985 unsigned short jPlane = jTjPt.plane;
986 unsigned int jWire = jtp.Pos[0];
988 ijPos[0] = itp.Pos[0];
997 if (tIDs[0] > tIDs[1]) std::swap(tIDs[0], tIDs[1]);
999 std::size_t indx = 0;
1000 for (indx = 0; indx < mtIDs.size(); ++indx)
1001 if (tIDs == mtIDs[indx])
break;
1002 if (indx == mtIDs.size()) {
1004 mtIDs.push_back(tIDs);
1008 if (mCnt[indx] == maxCnt) {
1010 tMaxed.insert(tMaxed.end(), tIDs[0]);
1011 tMaxed.insert(tMaxed.end(), tIDs[1]);
1015 if (hitMaxCnt)
break;
1019 if (mCnt.empty())
return;
1021 std::vector<SortEntry> sortVec;
1022 for (std::size_t indx = 0; indx < mCnt.size(); ++indx) {
1023 auto& tIDs = mtIDs[indx];
1026 for (
auto tid : tIDs) {
1027 auto& tj = slc.
tjs[tid - 1];
1030 float frac = mCnt[indx] / tpCnt;
1033 if (frac < 0.05)
continue;
1036 se.
val = mCnt[indx];
1037 sortVec.push_back(se);
1039 if (sortVec.size() > 1) std::sort(sortVec.begin(), sortVec.end(),
valsDecreasing);
1041 matVec.resize(sortVec.size());
1043 for (std::size_t ii = 0; ii < sortVec.size(); ++ii) {
1044 unsigned short indx = sortVec[ii].index;
1045 auto& ms = matVec[ii];
1046 ms.Count = mCnt[indx];
1048 for (
unsigned short plane = 0; plane < 2; ++plane)
1049 ms.TjIDs[plane] = (
int)mtIDs[indx][plane];
1063 for (
unsigned short sfi = 0; sfi < pfp.
SectionFits.size(); ++sfi) {
1065 if (!sf.NeedsUpdate)
continue;
1069 for (
unsigned short ipt = 0; ipt < pfp.
TP3Ds.size(); ++ipt) {
1070 auto& tp3d = pfp.
TP3Ds[ipt];
1071 if (tp3d.SFIndex < sfi)
continue;
1072 if (tp3d.SFIndex > sfi)
break;
1074 double delta = tp3d.Pos[0] - tp3d.TPX;
1075 sf.ChiDOF += delta * delta / tp3d.TPXErr2;
1077 if (sf.NPts < 5) { sf.ChiDOF = 0; }
1079 sf.ChiDOF /= (float)(sf.NPts - 4);
1081 sf.NeedsUpdate =
false;
1087 for (std::size_t sfi = 0; sfi < pfp.
SectionFits.size(); ++sfi) {
1089 if (!sf.NeedsUpdate)
continue;
1090 if (!
FitSection(detProp, slc, pfp, sfi))
return false;
1092 sf.NeedsUpdate =
false;
1096 for (
auto& tp3d : pfp.
TP3Ds) {
1118 if (pfp.
TP3Ds.size() < 12) {
1134 for (
auto& tp3d : pfp.
TP3Ds) {
1139 if (!
FitSection(detProp, slc, pfp, 0)) {
return false; }
1145 unsigned short min2DPts = 3;
1146 unsigned short fromPt = 0;
1148 for (
auto& tp3d : pfp.
TP3Ds)
1149 tp3d.SFIndex = USHRT_MAX;
1151 unsigned short nPtsToAdd = pfp.
TP3Ds.size() / 4;
1153 unsigned short nPts = nPtsToAdd;
1155 unsigned short nPtsMin =
Find3DRecoRange(slc, pfp, fromPt, min2DPts, 1) - fromPt + 1;
1156 if (nPtsMin >= pfp.
TP3Ds.size()) {
1161 if (nPts < nPtsMin) nPts = nPtsMin;
1163 if (pfp.
TP3Ds.size() > 100) {
1164 unsigned short nhalf = pfp.
TP3Ds.size() / 2;
1165 FitTP3Ds(detProp, slc, pfp, fromPt, nhalf, USHRT_MAX);
1168 bool lastSection =
false;
1169 for (
unsigned short sfIndex = 0; sfIndex < 20; ++sfIndex) {
1171 float chiDOFPrev = 0;
1173 for (
unsigned short nit = 0; nit < 10; ++nit) {
1175 unsigned short nPtsNext = nPts;
1176 if (!
FitTP3Ds(detProp, slc, pfp, fromPt, nPts, USHRT_MAX)) { nPtsNext += 1.5 * nPtsToAdd; }
1177 else if (chiDOF < chiLo) {
1184 nPtsNext += nPtsToAdd;
1188 else if (chiDOF > chiHi) {
1197 short npnext = (short)nPts - nHiChi * 5;
1200 if (npnext > nPtsMin) nPtsNext = npnext;
1208 if (fromPt + nPtsNext >= pfp.
TP3Ds.size()) {
1209 nPtsNext = pfp.
TP3Ds.size() - fromPt;
1214 myprt <<
" RS: P" << pfp.
ID <<
" sfi/nit/npts " << sfIndex <<
"/" << nit <<
"/" << nPts;
1215 myprt << std::fixed << std::setprecision(1) <<
" chiDOF " << chiDOF;
1216 myprt <<
" fromPt " << fromPt;
1217 myprt <<
" nPtsNext " << nPtsNext;
1218 myprt <<
" nHiChi " << nHiChi;
1219 myprt <<
" lastSection? " << lastSection;
1221 if (nPtsNext == 0)
break;
1223 if (lastSection)
break;
1224 if (chiDOF == chiDOFPrev) {
1229 chiDOFPrev = chiDOF;
1232 unsigned short toPt = fromPt + nPts;
1233 if (toPt > pfp.
TP3Ds.size()) toPt = pfp.
TP3Ds.size();
1234 for (
unsigned short ipt = fromPt; ipt < toPt; ++ipt)
1235 pfp.
TP3Ds[ipt].SFIndex = sfIndex;
1240 unsigned short nextFromPt = fromPt + nPts;
1242 unsigned short nextToPtMin =
Find3DRecoRange(slc, pfp, nextFromPt, min2DPts, 1);
1243 if (nextToPtMin == USHRT_MAX) {
1247 for (std::size_t ipt = nextFromPt; ipt < pfp.
TP3Ds.size(); ++ipt)
1248 pfp.
TP3Ds[ipt].SFIndex = sfIndex;
1254 if (lastSection)
break;
1256 fromPt = fromPt + nPts;
1258 nPtsMin =
Find3DRecoRange(slc, pfp, fromPt, min2DPts, 1) - fromPt + 1;
1259 if (nPtsMin >= pfp.
TP3Ds.size())
break;
1266 unsigned short badSFI = pfp.
SectionFits.size() - 1;
1269 for (std::size_t ipt = pfp.
TP3Ds.size() - 1; ipt > 0; --ipt) {
1270 auto& tp3d = pfp.
TP3Ds[ipt];
1271 if (tp3d.SFIndex < badSFI)
break;
1278 for (std::size_t ipt = pfp.
TP3Ds.size() - 1; ipt > 0; --ipt) {
1279 auto& tp3d = pfp.
TP3Ds[ipt];
1286 Update(detProp, slc, pfp);
1299 unsigned short fromPt,
1300 unsigned short toPt,
1301 unsigned short& nBadPts,
1302 unsigned short& firstBadPt)
1305 firstBadPt = USHRT_MAX;
1307 if (fromPt > pfp.
TP3Ds.size() - 1) {
1308 nBadPts = USHRT_MAX;
1311 if (toPt > pfp.
TP3Ds.size()) toPt = pfp.
TP3Ds.size();
1313 for (
unsigned short ipt = fromPt; ipt < toPt; ++ipt) {
1314 auto& tp3d = pfp.
TP3Ds[ipt];
1318 auto& tp = slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex];
1336 if (pfp.
TP3Ds.size() < 12)
return false;
1338 if (toPt > pfp.
TP3Ds.size())
return false;
1340 if (nextToPt > pfp.
TP3Ds.size())
return false;
1347 unsigned short fromPt,
1348 unsigned short min2DPts,
1354 if (fromPt > pfp.
TP3Ds.size() - 1)
return USHRT_MAX;
1355 if (pfp.
TP3Ds.size() < 2 * min2DPts)
return USHRT_MAX;
1356 if (dir == 0)
return USHRT_MAX;
1358 std::vector<unsigned short> cntInPln(slc.
nPlanes);
1359 for (std::size_t ii = 0; ii < pfp.
TP3Ds.size(); ++ii) {
1360 unsigned short ipt = fromPt + ii;
1361 if (dir < 0) ipt = fromPt - ii;
1362 if (ipt >= pfp.
TP3Ds.size())
break;
1363 auto& tp3d = pfp.
TP3Ds[ipt];
1367 unsigned short enufInPlane = 0;
1368 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane)
1369 if (cntInPln[plane] >= min2DPts) ++enufInPlane;
1370 if (enufInPlane > 1)
return ipt + 1;
1371 if (dir < 0 && ipt == 0)
break;
1378 unsigned short sfIndex,
1379 unsigned short& fromPt,
1380 unsigned short& npts)
1384 if (pfp.
TP3Ds.empty())
return;
1388 for (std::size_t ipt = 0; ipt < pfp.
TP3Ds.size(); ++ipt) {
1389 auto& tp3d = pfp.
TP3Ds[ipt];
1390 if (tp3d.SFIndex < sfIndex)
continue;
1391 if (tp3d.SFIndex > sfIndex)
break;
1392 if (fromPt == USHRT_MAX) fromPt = ipt;
1401 unsigned short sfIndex)
1405 if (pfp.
TP3Ds.size() < 4)
return false;
1406 if (sfIndex >= pfp.
SectionFits.size())
return false;
1410 unsigned short fromPt = USHRT_MAX;
1411 unsigned short npts = 0;
1412 GetRange(pfp, sfIndex, fromPt, npts);
1413 if (fromPt == USHRT_MAX)
return false;
1414 if (npts < 4)
return false;
1417 for (
unsigned short ipt = fromPt; ipt < fromPt + npts; ++ipt) {
1418 auto& tp3d = pfp.
TP3Ds[ipt];
1419 if (tp3d.SFIndex != sfIndex)
return false;
1423 return FitTP3Ds(detProp, slc, pfp, fromPt, npts, sfIndex);
1430 const std::vector<TP3D>& tp3ds,
1431 unsigned short fromPt,
1433 unsigned short nPtsFit)
1440 if (nPtsFit < 5)
return sf;
1441 if (!(fitDir == -1 || fitDir == 1))
return sf;
1442 if (fitDir == 1 && fromPt + nPtsFit > tp3ds.size())
return sf;
1443 if (fitDir == -1 && fromPt < 3)
return sf;
1446 std::vector<std::array<double, 3>> ocs(slc.
nPlanes);
1447 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
1457 const unsigned int nvars = 4;
1458 unsigned int npts = 0;
1461 std::vector<unsigned short> cntInPln(slc.
nPlanes, 0);
1464 for (
short ii = 0; ii < nPtsFit; ++ii) {
1465 short ipt = fromPt + fitDir * ii;
1466 if (ipt < 0 || ipt >= (
short)tp3ds.size())
break;
1467 auto& tp3d = tp3ds[ipt];
1469 if (tp3d.TPXErr2 < 0.0001)
return sf;
1475 if (npts < 6)
return sf;
1477 unsigned short enufInPlane = 0;
1478 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane)
1479 if (cntInPln[plane] > 2) ++enufInPlane;
1480 if (enufInPlane < 2)
return sf;
1484 TMatrixD A(npts, nvars);
1487 unsigned short cnt = 0;
1489 for (
short ii = 0; ii < nPtsFit; ++ii) {
1490 short ipt = fromPt + fitDir * ii;
1491 auto& tp3d = tp3ds[ipt];
1494 double x = tp3d.TPX - x0;
1495 A[cnt][0] = weight * ocs[plane][1];
1496 A[cnt][1] = weight * ocs[plane][2];
1497 A[cnt][2] = weight * ocs[plane][1] *
x;
1498 A[cnt][3] = weight * ocs[plane][2] *
x;
1499 w[cnt] = weight * (tp3d.Wire - ocs[plane][0]);
1505 TVectorD tVec = svd.Solve(w, ok);
1507 double norm = sqrt(1 + tVec[2] * tVec[2] + tVec[3] * tVec[3]);
1515 sf.
Pos[1] = tVec[0];
1516 sf.
Pos[2] = tVec[1];
1521 TMatrixD AT(nvars, npts);
1523 TMatrixD ATA = AT * A;
1537 std::vector<TrajPoint> plnTP(slc.
nPlanes);
1538 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
1545 for (
short ii = 0; ii < nPtsFit; ++ii) {
1546 short ipt = fromPt + fitDir * ii;
1547 auto& tp3d = tp3ds[ipt];
1550 double dw = tp3d.Wire - plnTP[plane].Pos[0];
1552 double t = dw * plnTP[plane].DeltaRMS;
1553 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
1554 pos[xyz] = sf.
Pos[xyz] + t * sf.
Dir[xyz];
1558 double delta = pos[0] - tp3d.TPX;
1559 sf.
ChiDOF += delta * delta / tp3d.TPXErr2;
1561 double dangErr = delta / dw;
1562 sf.
DirErr[0] += dangErr * dangErr;
1565 sf.
ChiDOF /= (float)(npts - 4);
1574 unsigned short fromPt,
1575 unsigned short nPtsFit,
1576 unsigned short sfIndex)
1582 if (nPtsFit < 5)
return false;
1583 if (fromPt + nPtsFit > pfp.
TP3Ds.size())
return false;
1585 auto sf =
FitTP3Ds(detProp, slc, pfp.
TP3Ds, fromPt, 1, nPtsFit);
1586 if (sf.ChiDOF > 900)
return false;
1589 if (sfIndex >= pfp.
SectionFits.size())
return true;
1595 std::vector<TrajPoint> plnTP(slc.
nPlanes);
1596 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
1598 plnTP[plane] =
MakeBareTP(detProp, sf.Pos, sf.Dir, inCTP);
1601 bool needsSort =
false;
1602 double prevAlong = 0;
1603 for (
unsigned short ipt = fromPt; ipt < fromPt + nPtsFit; ++ipt) {
1604 auto& tp3d = pfp.
TP3Ds[ipt];
1606 double dw = tp3d.Wire - plnTP[plane].Pos[0];
1608 double t = dw * plnTP[plane].DeltaRMS;
1609 if (ipt == fromPt) { prevAlong = t; }
1611 if (t < prevAlong) needsSort =
true;
1614 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
1615 pos[xyz] = sf.Pos[xyz] + t * sf.Dir[xyz];
1619 double delta = pos[0] - tp3d.TPX;
1623 if (tp3d.Flags[
kTP3DGood]) sf.ChiDOF += delta * delta / tp3d.TPXErr2;
1643 if (pfp.
TP3Ds.empty())
return;
1648 std::vector<int> tjList;
1649 for (
auto& tp3d : pfp.
TP3Ds) {
1652 if (tp3d.TjID <= 0)
continue;
1653 if (std::find(tjList.begin(), tjList.end(), tp3d.TjID) == tjList.end())
1654 tjList.push_back(tp3d.TjID);
1658 std::vector<int> vx2List, vx3List;
1659 for (
auto tid : tjList) {
1660 auto& tj = slc.
tjs[tid - 1];
1661 for (
unsigned short end = 0;
end < 2; ++
end) {
1662 if (tj.VtxID[
end] <= 0)
continue;
1663 auto& vx2 = slc.
vtxs[tj.VtxID[
end] - 1];
1664 if (vx2.Vx3ID > 0) {
1665 if (std::find(vx3List.begin(), vx3List.end(), vx2.Vx3ID) == vx3List.end())
1666 vx3List.push_back(vx2.Vx3ID);
1671 if (std::find(vx2List.begin(), vx2List.end(), tj.VtxID[
end]) == vx2List.end())
1672 vx2List.push_back(tj.VtxID[
end]);
1677 if (vx2List.empty() && vx3List.empty())
return;
1680 myprt <<
"RV: P" << pfp.
ID <<
" ->";
1681 for (
auto tid : tjList)
1682 myprt <<
" T" << tid;
1684 for (
auto vid : vx3List)
1685 myprt <<
" 3V" << vid;
1686 if (!vx2List.empty()) {
1688 for (
auto vid : vx2List)
1689 myprt <<
" 2V" << vid;
1697 for (
auto vid : vx2List) {
1698 auto& vx2 = slc.
vtxs[vid - 1];
1707 if (!slc.
pfps.empty()) {
1708 auto& npfp = slc.
pfps[0];
1709 bool neutrinoPFP = (npfp.PDGCode == 12 || npfp.PDGCode == 14);
1710 if (neutrinoPFP) neutrinoVx = npfp.Vx3ID[0];
1712 unsigned short neutrinoVxEnd = 2;
1713 for (
unsigned short end = 0;
end < 2; ++
end) {
1716 if (pfp.
Vx3ID[
end] == neutrinoVx) neutrinoVxEnd =
end;
1718 if (std::find(vx3List.begin(), vx3List.end(), pfp.
Vx3ID[
end]) != vx3List.end())
continue;
1720 if (neutrinoVxEnd < 2 && neutrinoVxEnd != 0)
Reverse(pfp);
1737 if (pfp.
ID <= 0)
return;
1738 if (pfp.
TP3Ds.empty())
return;
1750 unsigned short nPtsAdded = 0;
1751 unsigned short fromPt = 0;
1752 unsigned short toPt = pWork.
TP3Ds.size();
1753 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
1754 CTP_t inCTP =
EncodeCTP(pWork.TPCID.Cryostat, pWork.TPCID.TPC, plane);
1755 unsigned short nWires, nAdd;
1770 if (prt)
mf::LogVerbatim(
"TC") <<
"FG3D P" << pWork.ID <<
" added " << nPtsAdded <<
" points";
1784 if (pfp.
TjIDs.size() != 2)
return false;
1785 if (slc.
nPlanes != 3)
return false;
1786 if (pfp.
TP3Ds.empty())
return false;
1789 std::vector<unsigned short> planes;
1790 for (
auto tid : pfp.
TjIDs)
1792 unsigned short thirdPlane = 3 - planes[0] - planes[1];
1796 unsigned int wire0 = 0;
1797 if (tp.Pos[0] > 0) wire0 = std::nearbyint(tp.Pos[0]);
1798 if (wire0 > slc.
nWires[thirdPlane]) wire0 = slc.
nWires[thirdPlane];
1800 unsigned short lastPt = pfp.
TP3Ds.size() - 1;
1802 unsigned int wire1 = 0;
1803 if (tp.Pos[0] > 0) wire1 = std::nearbyint(tp.Pos[0]);
1804 if (wire1 > slc.
nWires[thirdPlane]) wire1 = slc.
nWires[thirdPlane];
1805 if (wire0 == wire1)
return !
evt.
goodWire[thirdPlane][wire0];
1806 if (wire1 < wire0) std::swap(wire0, wire1);
1809 int wires = wire1 - wire0;
1810 for (
unsigned int wire = wire0; wire < wire1; ++wire)
1813 return (dead > 0.8 * wires);
1821 unsigned short fromPt,
1822 unsigned short toPt,
1825 unsigned short& nWires,
1826 unsigned short& nAdd,
1835 if (fromPt > toPt)
return;
1836 if (toPt >= pfp.
TP3Ds.size()) toPt = pfp.
TP3Ds.size() - 1;
1841 Average_dEdX(clockData, detProp, slc, pfp, dEdXAve, dEdXRms);
1842 float dEdxMin = 0.5, dEdxMax = 50.;
1843 if (dEdXAve > 0.5) {
1844 dEdxMin = dEdXAve - maxPull * dEdXRms;
1845 if (dEdxMin < 0.5) dEdxMin = 0.5;
1846 dEdxMax = dEdXAve + maxPull * dEdXRms;
1847 if (dEdxMax > 50.) dEdxMax = 50.;
1852 std::vector<TrajPoint> sfTPs;
1854 std::vector<std::pair<int, unsigned short>> tpUsed;
1855 for (
auto& tp3d : pfp.
TP3Ds) {
1856 if (tp3d.CTP != inCTP)
continue;
1857 tpUsed.push_back(std::make_pair(tp3d.TjID, tp3d.TPIndex));
1859 unsigned int toWire = 0;
1860 unsigned int fromWire = UINT_MAX;
1862 unsigned short inSF = USHRT_MAX;
1864 for (
unsigned short ipt = 0; ipt < pfp.
TP3Ds.size(); ++ipt) {
1865 auto& tp3d = pfp.
TP3Ds[ipt];
1867 if (ipt < pfp.
TP3Ds.size() - 1 && tp3d.SFIndex == inSF)
continue;
1869 if (tp3d.CTP == inCTP) {
1871 auto& tp = slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex];
1872 sfTPs.push_back(tp);
1873 wire = std::nearbyint(tp.Pos[0]);
1874 if (wire >= slc.
nWires[pln])
break;
1879 auto tp =
MakeBareTP(detProp, tp3d.Pos, tp3d.Dir, inCTP);
1880 wire = std::nearbyint(tp.Pos[0]);
1881 if (wire >= slc.
nWires[pln])
break;
1882 sfTPs.push_back(tp);
1884 if (wire < fromWire) fromWire = wire;
1885 if (wire > toWire) toWire = wire;
1886 inSF = tp3d.SFIndex;
1888 if (sfTPs.empty())
return;
1890 if (sfTPs.size() > 1 && sfTPs[0].Pos[0] > sfTPs.back().Pos[0]) {
1891 std::reverse(sfTPs.begin(), sfTPs.end());
1898 mf::LogVerbatim(
"TC") <<
"APIR: inCTP " << inCTP <<
" fromWire " << fromWire <<
" toWire " 1902 for (
unsigned short subr = 0; subr < sfTPs.size(); ++subr) {
1903 auto& fromTP = sfTPs[subr];
1904 unsigned int toWireInSF = toWire;
1905 if (subr < sfTPs.size() - 1) toWireInSF = std::nearbyint(sfTPs[subr + 1].Pos[0]);
1907 unsigned int fromWire = std::nearbyint(fromTP.Pos[0]);
1908 if (fromWire > toWire)
continue;
1910 mf::LogVerbatim(
"TC") <<
" inCTP " << inCTP <<
" subr " << subr <<
" fromWire " << fromWire
1911 <<
" toWireInSF " << toWireInSF;
1912 for (
unsigned int wire = fromWire; wire <= toWireInSF; ++wire) {
1916 float bestPull = maxPull;
1918 for (
auto iht : fromTP.Hits) {
1919 if (slc.
slHits[iht].InTraj <= 0)
continue;
1921 auto& utj = slc.
tjs[slc.
slHits[iht].InTraj - 1];
1922 unsigned short tpIndex = 0;
1923 for (tpIndex = utj.EndPt[0]; tpIndex <= utj.EndPt[1]; ++tpIndex) {
1924 auto& utp = utj.Pts[tpIndex];
1925 if (utp.Chg <= 0)
continue;
1927 if (std::find(utp.Hits.begin(), utp.Hits.end(), iht) != utp.Hits.end())
break;
1929 if (tpIndex > utj.EndPt[1])
continue;
1931 std::pair<int, unsigned short> tppr = std::make_pair(utj.ID, tpIndex);
1932 if (std::find(tpUsed.begin(), tpUsed.end(), tppr) != tpUsed.end())
continue;
1933 tpUsed.push_back(tppr);
1934 auto& utp = utj.Pts[tpIndex];
1936 if (utp.InPFP > 0)
continue;
1939 auto newTP3D =
CreateTP3D(detProp, slc, utj.
ID, tpIndex);
1940 if (!
SetSection(detProp, pfp, newTP3D))
continue;
1942 newTP3D.Dir = pfp.
SectionFits[newTP3D.SFIndex].Dir;
1944 float dedx =
dEdx(clockData, detProp, slc, newTP3D);
1946 bool useIt = (pull < bestPull && dedx > dEdxMin && dedx < dEdxMax);
1947 if (!useIt)
continue;
1951 if (bestPull < maxPull) {
1952 if (prt && bestPull < 10) {
1955 myprt <<
"APIR: P" << pfp.
ID <<
" added TP " <<
PrintPos(tp);
1956 myprt <<
" pull " << std::fixed << std::setprecision(2) << bestPull;
1957 myprt <<
" dx " << bestTP3D.
TPX - bestTP3D.
Pos[0] <<
" in section " << bestTP3D.
SFIndex;
1959 if (
InsertTP3D(pfp, bestTP3D) == USHRT_MAX)
continue;
1972 std::size_t ipt = 0;
1973 for (ipt = 0; ipt < pfp.
TP3Ds.size(); ++ipt)
1975 if (ipt == pfp.
TP3Ds.size())
return USHRT_MAX;
1977 auto lastTP3D = pfp.
TP3Ds.back();
1978 if (ipt == 0 && tp3d.
along < pfp.
TP3Ds[0].along) {
1981 else if (tp3d.
SFIndex == lastTP3D.SFIndex && tp3d.
along > lastTP3D.along) {
1983 pfp.
TP3Ds.push_back(tp3d);
1986 return pfp.
TP3Ds.size() - 1;
1989 for (std::size_t iipt = ipt; iipt < pfp.
TP3Ds.size() - 1; ++iipt) {
1991 if (pfp.
TP3Ds[iipt + 1].SFIndex != tp3d.
SFIndex)
break;
1998 pfp.
TP3Ds.insert(pfp.
TP3Ds.begin() + ipt, tp3d);
2009 if (sfIndex > pfp.
SectionFits.size() - 1)
return false;
2011 if (sf.Pos[0] == 0.0 && sf.Pos[1] == 0.0 && sf.Pos[2] == 0.0)
return false;
2014 std::vector<TP3D> temp;
2016 std::vector<unsigned short> indx;
2018 float prevAlong = 0;
2020 bool needsSort =
false;
2021 for (std::size_t ii = 0; ii < pfp.
TP3Ds.size(); ++ii) {
2022 auto& tp3d = pfp.
TP3Ds[ii];
2023 if (tp3d.SFIndex != sfIndex)
continue;
2026 prevAlong = tp3d.along;
2029 if (tp3d.along < prevAlong) needsSort =
true;
2030 prevAlong = tp3d.along;
2032 temp.push_back(tp3d);
2035 if (temp.empty())
return false;
2037 if (temp.size() == 1)
return true;
2039 sf.NeedsUpdate =
false;
2043 bool contiguous =
true;
2044 for (std::size_t ipt = 1; ipt < indx.size(); ++ipt) {
2045 if (indx[ipt] != indx[ipt - 1] + 1) contiguous =
false;
2047 if (!contiguous) {
return false; }
2049 std::vector<SortEntry> sortVec(temp.size());
2050 for (std::size_t ii = 0; ii < temp.size(); ++ii) {
2051 sortVec[ii].index = ii;
2052 sortVec[ii].val = temp[ii].along;
2055 for (std::size_t ii = 0; ii < temp.size(); ++ii) {
2057 auto& tp3d = pfp.
TP3Ds[indx[ii]];
2058 tp3d = temp[sortVec[ii].index];
2060 sf.NeedsUpdate =
false;
2073 if (pfp.
TP3Ds.size() < 20)
return;
2080 unsigned short halfPt = p2.TP3Ds.size() / 2;
2081 for (
unsigned short ipt = halfPt; ipt < p2.TP3Ds.size(); ++ipt)
2082 p2.TP3Ds[ipt].SFIndex = 1;
2085 if (toPt > p2.TP3Ds.size())
return;
2087 if (toPt > p2.TP3Ds.size())
return;
2091 myprt <<
"Recover failed MVI " << p2.MVI <<
" in TPC " << p2.TPCID.TPC;
2092 for (
auto tid : p2.TjIDs)
2093 myprt <<
" T" << tid;
2124 unsigned short nJunk = 0;
2125 unsigned short nSA = 0;
2126 for (
unsigned short itj = 0; itj < pfp.
TjIDs.size(); ++itj) {
2127 auto& tj = slc.
tjs[pfp.
TjIDs[itj] - 1];
2128 if (tj.AlgMod[
kJunkTj]) ++nJunk;
2130 unsigned short iptMin = USHRT_MAX;
2131 float posMax = -1E6;
2132 unsigned short iptMax = USHRT_MAX;
2135 for (
unsigned short ipt = tj.EndPt[0]; ipt < tj.EndPt[1]; ++ipt) {
2136 auto& tp = tj.Pts[ipt];
2137 if (tp.Chg <= 0)
continue;
2139 if (tp.InPFP > 0)
continue;
2141 if (tp.Pos[1] > posMax) {
2145 if (tp.Pos[1] < posMin) {
2152 if (npwc == 0)
continue;
2154 if (
std::abs(aveAng) < 0.05) ++nSA;
2156 if (iptMin > tj.EndPt[0] + 4 && iptMin < tj.EndPt[1] - 4) pfp.
TjUIDs[itj] = iptMin;
2157 if (iptMax > tj.EndPt[0] + 4 && iptMax < tj.EndPt[1] - 4) pfp.
TjUIDs[itj] = iptMax;
2159 if (avail < 0.8 * cnt)
return false;
2169 for (
auto tid : pfp.
TjIDs) {
2170 auto& tj = slc.
tjs[tid - 1];
2172 if (nJunk == 1 && tj.AlgMod[
kJunkTj])
continue;
2175 bool isJunk = tj.AlgMod[
kJunkTj];
2176 for (
unsigned short ipt = tj.EndPt[0]; ipt <= tj.EndPt[1]; ++ipt) {
2177 auto& tp = tj.Pts[ipt];
2178 if (tp.Chg <= 0)
continue;
2179 if (tp.InPFP > 0)
continue;
2181 auto tp3d =
CreateTP3D(detProp, slc, tid, ipt);
2182 if (tp3d.Flags[
kTP3DBad])
continue;
2184 if (isJunk) tp3d.TPXErr2 *= 4;
2187 pfp.
TP3Ds.push_back(tp3d);
2206 if (pfp.
TjIDs.size() < 2)
return false;
2208 std::vector<SortEntry> sortVec(pfp.
TjIDs.size());
2209 unsigned short sbCnt = 0;
2210 for (
unsigned short itj = 0; itj < pfp.
TjIDs.size(); ++itj) {
2211 sortVec[itj].index = itj;
2212 auto& tj = slc.
tjs[pfp.
TjIDs[itj] - 1];
2214 if (pfp.
TjUIDs[itj] > 0) ++sbCnt;
2220 unsigned short tlIndex = sortVec[0].index;
2221 unsigned short nlIndex = sortVec[1].index;
2222 auto& tlong = slc.
tjs[pfp.
TjIDs[tlIndex] - 1];
2223 auto& nlong = slc.
tjs[pfp.
TjIDs[nlIndex] - 1];
2224 bool twoSections = (sbCnt > 1 && pfp.
TjUIDs[tlIndex] > 0 && pfp.
TjUIDs[nlIndex] > 0);
2225 unsigned short tStartPt = tlong.EndPt[0];
2226 unsigned short tEndPt = tlong.EndPt[1];
2227 unsigned short nStartPt = nlong.EndPt[0];
2228 unsigned short nEndPt = nlong.EndPt[1];
2231 tEndPt = pfp.
TjUIDs[tlIndex];
2232 nEndPt = pfp.
TjUIDs[nlIndex];
2235 myprt <<
"MakeSmallAnglePFP: creating two sections using points";
2236 myprt <<
" T" << tlong.ID <<
"_" << tEndPt;
2237 myprt <<
" T" << nlong.ID <<
"_" << nEndPt;
2240 std::vector<Point3_t> sfEndPos;
2241 for (
unsigned short isf = 0; isf < pfp.
SectionFits.size(); ++isf) {
2243 auto& ltp0 = tlong.Pts[tStartPt];
2244 auto& ltp1 = tlong.Pts[tEndPt];
2245 auto& ntp0 = nlong.Pts[nStartPt];
2246 auto& ntp1 = nlong.Pts[nEndPt];
2248 auto start =
MakeTP3D(detProp, ltp0, ntp0);
2251 std::cout <<
" Start/end fail in section " << isf <<
". Add recovery code\n";
2255 mf::LogVerbatim(
"TC") <<
" Start is outside the TPC " << start.Pos[0] <<
" " << start.Pos[1]
2256 <<
" " << start.Pos[2];
2260 <<
" " <<
end.Pos[2];
2262 if (isf == 0) sfEndPos.push_back(start.Pos);
2263 sfEndPos.push_back(
end.Pos);
2266 for (
unsigned short xyz = 0; xyz < 3; ++xyz) {
2267 sf.Dir[xyz] =
end.Pos[xyz] - start.Pos[xyz];
2268 sf.Pos[xyz] = (
end.Pos[xyz] + start.Pos[xyz]) / 2.;
2274 tStartPt = tEndPt + 1;
2275 tEndPt = tlong.EndPt[1];
2276 nStartPt = nEndPt + 1;
2277 nEndPt = nlong.EndPt[1];
2281 std::vector<TP3D> sf2pts;
2282 for (
unsigned short itj = 0; itj < sortVec.size(); ++itj) {
2283 int tid = pfp.
TjIDs[sortVec[itj].index];
2286 if (twoSections && pfp.
TjUIDs[sortVec[itj].index] < 0)
continue;
2287 auto& tj = slc.
tjs[tid - 1];
2288 unsigned short sb = tj.EndPt[1];
2289 if (twoSections && pfp.
TjUIDs[sortVec[itj].index] > 0) sb = pfp.
TjUIDs[sortVec[itj].index];
2291 std::vector<double> npwc(pfp.
SectionFits.size(), 0);
2292 for (
unsigned short ipt = tj.EndPt[0]; ipt <= tj.EndPt[1]; ++ipt) {
2293 auto& tp = tj.Pts[ipt];
2294 if (tp.Chg <= 0)
continue;
2295 if (ipt > sb) { ++npwc[1]; }
2300 double length =
PosSep(sfEndPos[0], sfEndPos[1]);
2301 double step = length / npwc[0];
2302 double along = -length / 2;
2303 unsigned short sfi = 0;
2304 for (
unsigned short ipt = tj.EndPt[0]; ipt <= tj.EndPt[1]; ++ipt) {
2305 auto& tp = tj.Pts[ipt];
2306 if (tp.Chg <= 0)
continue;
2307 auto tp3d =
CreateTP3D(detProp, slc, tid, ipt);
2308 if (tp3d.Flags[
kTP3DBad])
continue;
2309 if (ipt == sb + 1) {
2311 length =
PosSep(sfEndPos[1], sfEndPos[2]);
2312 step = length / npwc[1];
2313 along = -length / 2;
2319 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
2320 tp3d.Pos[xyz] = sf.Pos[xyz] + along * sf.Dir[xyz];
2323 double delta = tp3d.Pos[0] - tp3d.TPX;
2324 sf.ChiDOF += delta * delta / tp3d.TPXErr2;
2327 if (sfi == 0) { pfp.
TP3Ds.push_back(tp3d); }
2329 sf2pts.push_back(tp3d);
2333 if (pfp.
TP3Ds.size() < 4)
return false;
2335 if (sf.NPts < 5)
return false;
2336 sf.ChiDOF /= (float)(sf.NPts - 4);
2339 if (!sf2pts.empty()) {
2341 pfp.
TP3Ds.insert(pfp.
TP3Ds.end(), sf2pts.begin(), sf2pts.end());
2348 <<
" points in " << pfp.
SectionFits.size() <<
" sections\n";
2357 std::reverse(pfp.
TP3Ds.begin(), pfp.
TP3Ds.end());
2359 for (std::size_t sfi = 0; sfi < pfp.
SectionFits.size(); ++sfi) {
2362 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
2366 for (
auto& tp3d : pfp.
TP3Ds)
2368 std::swap(pfp.
dEdx[0], pfp.
dEdx[1]);
2386 unsigned short cnt = 0;
2392 for (
auto& tj : slc.
tjs) {
2395 if (tj.AlgMod[
kMat3D])
continue;
2397 if ((
int)planeID.
Cryostat != cstat)
continue;
2398 if ((
int)planeID.
TPC != tpc)
continue;
2399 int plane = planeID.
Plane;
2400 if (tj.ID <= 0)
continue;
2401 unsigned short tjID = tj.ID;
2402 for (
unsigned short ipt = tj.EndPt[0]; ipt <= tj.EndPt[1]; ++ipt) {
2403 auto& tp = tj.Pts[ipt];
2404 if (tp.Chg <= 0)
continue;
2405 if (tp.Pos[0] < -0.4)
continue;
2407 if (tp.InPFP > 0)
continue;
2408 if (muFuzzCut && tp.Environment[
kEnvNearMuon])
continue;
2409 tj2pt.
wire = std::nearbyint(tp.Pos[0]);
2414 tj2pt.
xlo = xpos - rms;
2415 tj2pt.
xhi = xpos + rms;
2416 tj2pt.
plane = plane;
2419 tj2pt.
npts = tj.EndPt[1] - tj.EndPt[0] + 1;
2425 std::vector<SortEntry> sortVec(slc.
mallTraj.size());
2426 for (std::size_t ipt = 0; ipt < slc.
mallTraj.size(); ++ipt) {
2428 sortVec[ipt].index = ipt;
2429 sortVec[ipt].val = slc.
mallTraj[ipt].xlo;
2435 for (std::size_t ii = 0; ii < sortVec.size(); ++ii)
2436 slc.
mallTraj[ii] = tallTraj[sortVec[ii].index];
2453 tp3d.
Dir = {{0.0, 0.0, 1.0}};
2454 tp3d.
Pos = {{999.0, 999.0, 999.0}};
2457 if (iPlnID == jPlnID)
return tp3d;
2464 if (dx > 20)
return tp3d;
2465 tp3d.
Pos[0] = (ix + jx) / 2;
2480 double den = isn * jcs - ics * jsn;
2481 if (den == 0)
return tp3d;
2482 double iPos0 = itp.
Pos[0];
2483 double jPos0 = jtp.
Pos[0];
2485 tp3d.
Pos[2] = (jcs * (iPos0 - iw0) - ics * (jPos0 - jw0)) / den;
2488 if (useI) { tp3d.
Pos[1] = (iPos0 - iw0 - isn * tp3d.
Pos[2]) / ics; }
2490 tp3d.
Pos[1] = (jPos0 - jw0 - jsn * tp3d.
Pos[2]) / jcs;
2494 if (jtp.
Dir[1] == 0) {
2496 if (jtp.
Dir[0] > 0) { tp3d.
Dir[0] = 1; }
2508 double itp2_0 = itp.
Pos[0] + 100;
2509 double itp2_1 = itp.
Pos[1];
2518 double jtp2Pos0 = (jtp2Pos1 - jtp.
Pos[1]) * (jtp.
Dir[0] / jtp.
Dir[1]) + jtp.
Pos[0];
2520 pos2[2] = (jcs * (itp2_0 - iw0) - ics * (jtp2Pos0 - jw0)) / den;
2521 if (useI) { pos2[1] = (itp2_0 - iw0 - isn * pos2[2]) / ics; }
2523 pos2[1] = (jtp2Pos0 - jw0 - jsn * pos2[2]) / jcs;
2526 if (sep == 0)
return tp3d;
2527 for (
unsigned short ixyz = 0; ixyz < 3; ++ixyz)
2528 tp3d.
Dir[ixyz] = (pos2[ixyz] - tp3d.
Pos[ixyz]) / sep;
2537 if (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2])
return 0;
2546 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
2547 dir[xyz] = p2[xyz] - p1[xyz];
2548 if (dir[0] == 0 && dir[1] == 0 && dir[2] == 0)
return dir;
2560 return sqrt(
PosSep2(pos1, pos2));
2567 double d0 = pos1[0] - pos2[0];
2568 double d1 = pos1[1] - pos2[1];
2569 double d2 = pos1[2] - pos2[2];
2570 return d0 * d0 + d1 * d1 + d2 * d2;
2576 double den = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2];
2577 if (den == 0)
return false;
2595 unsigned short numEnds = 2;
2596 if (pfp.
PDGCode == 1111) numEnds = 1;
2599 for (
unsigned short end = 0;
end < numEnds; ++
end) {
2600 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane)
2608 for (
unsigned short end = 0;
end < numEnds; ++
end) {
2609 std::vector<float> cnt(slc.
nPlanes);
2612 for (std::size_t ii = 0; ii < pfp.
TP3Ds.size(); ++ii) {
2614 if (dir > 0) { ipt = ii; }
2616 ipt = pfp.
TP3Ds.size() - ii - 1;
2618 if (ipt >= pfp.
TP3Ds.size())
break;
2619 auto& tp3d = pfp.
TP3Ds[ipt];
2620 if (tp3d.Flags[
kTP3DBad])
continue;
2621 if (
PosSep2(tp3d.Pos, endPos) > maxSep2)
break;
2624 float dedx =
dEdx(clockData, detProp, slc, tp3d);
2625 if (dedx < 0.5)
continue;
2630 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
2631 if (cnt[plane] == 0)
continue;
2632 pfp.
dEdx[
end][plane] /= cnt[plane];
2654 for (
auto& tp3d : pfp.
TP3Ds) {
2656 double dedx =
dEdx(clockData, detProp, slc, tp3d);
2657 if (dedx < 0.5 || dedx > 80.)
continue;
2659 sum2 += dedx * dedx;
2662 if (cnt < 3)
return;
2663 dEdXAve = sum / cnt;
2665 dEdXRms = 0.3 * dEdXAve;
2666 double arg = sum2 - cnt * dEdXAve * dEdXAve;
2667 if (arg < 0)
return;
2668 dEdXRms = sqrt(arg) / (cnt - 1);
2670 double minRms = 0.05 * dEdXAve;
2671 if (dEdXRms < minRms) dEdXRms = minRms;
2681 if (tp3d.
TjID > (
int)slc.
slHits.size())
return 0;
2682 if (tp3d.
TjID <= 0)
return 0;
2689 for (
unsigned short ii = 0; ii < tp.Hits.size(); ++ii) {
2690 if (!tp.UseHit[ii])
continue;
2692 dQ +=
hit.Integral();
2696 if (dQ == 0)
return 0;
2699 std::abs(std::sin(angleToVert) * tp3d.
Dir[1] + std::cos(angleToVert) * tp3d.
Dir[2]);
2700 if (cosgamma < 1.
E-5)
return 0;
2702 double dQdx = dQ / dx;
2705 if (std::isinf(dedx)) dedx = 0;
2713 unsigned short tpIndex)
2721 if (tjID <= 0 || tjID > (
int)slc.
tjs.size())
return tp3d;
2722 auto& tj = slc.
tjs[tjID - 1];
2723 if (tpIndex < tj.EndPt[0] || tpIndex > tj.EndPt[1])
return tp3d;
2726 auto& tp2 = tj.Pts[tp3d.
TPIndex];
2734 if (tp2.AngleCode == 1) rms *= 2;
2736 if (tp2.AngleCode > 1) {
2737 std::vector<unsigned int> hitMultiplet;
2738 for (std::size_t ii = 0; ii < tp2.Hits.size(); ++ii) {
2739 if (!tp2.UseHit[ii])
continue;
2741 if (hitMultiplet.size() > 1)
break;
2748 tp3d.
Wire = tp2.Pos[0];
2761 if (tp3d.
Wire < 0)
return false;
2763 if (pfp.
SectionFits[0].Pos[0] == -10.0)
return false;
2772 for (std::size_t sfi = 0; sfi < pfp.
SectionFits.size(); ++sfi) {
2785 double dw = tp3d.
Wire - plnTP.Pos[0];
2787 double t = dw * plnTP.DeltaRMS;
2789 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
2790 tp3d.
Pos[xyz] = sf.Pos[xyz] + t * sf.Dir[xyz];
2809 pfp.
ID = slc.
pfps.size() + 1;
2830 if (slc.
pfps.empty())
return;
2832 for (
auto& pfp : slc.
pfps) {
2833 if (pfp.ID == 0)
continue;
2834 if (pfp.Vx3ID[0] > 0)
continue;
2835 if (pfp.SectionFits.empty())
continue;
2842 if (pfp.TP3Ds.empty()) {
2844 startPos = pfp.SectionFits[0].Pos;
2846 else if (!pfp.TP3Ds.empty()) {
2848 startPos = pfp.TP3Ds[0].Pos;
2850 vx3.
X = startPos[0];
2851 vx3.
Y = startPos[1];
2852 vx3.
Z = startPos[2];
2853 vx3.
ID = slc.
vtx3s.size() + 1;
2857 slc.
vtx3s.push_back(vx3);
2858 pfp.Vx3ID[0] = vx3.
ID;
2899 if (slc.
pfps.empty())
return;
2902 int neutrinoPFPID = 0;
2903 for (
auto& pfp : slc.
pfps) {
2904 if (pfp.ID == 0)
continue;
2905 if (!
tcc.
modes[
kTestBeam] && neutrinoPFPID == 0 && (pfp.PDGCode == 12 || pfp.PDGCode == 14)) {
2906 neutrinoPFPID = pfp.ID;
2912 constexpr
unsigned short end1 = 1;
2913 for (
auto& pfp : slc.
pfps) {
2914 if (pfp.ID == 0)
continue;
2916 if (pfp.Vx3ID[end1] > 0)
continue;
2920 unsigned short cnt3 = 0;
2921 unsigned short vx3id = 0;
2923 std::vector<int> vx2ids;
2924 for (
auto tjid : pfp.TjIDs) {
2925 auto& tj = slc.
tjs[tjid - 1];
2926 if (tj.VtxID[end1] == 0)
continue;
2927 auto& vx2 = slc.
vtxs[tj.VtxID[end1] - 1];
2928 if (vx2.Vx3ID == 0) {
2929 if (vx2.Topo == 1 && vx2.NTraj == 2) vx2ids.push_back(vx2.ID);
2932 if (vx3id == 0) vx3id = vx2.Vx3ID;
2933 if (vx2.Vx3ID == vx3id) ++cnt3;
2937 if (pfp.Vx3ID[1 - end1] == vx3id)
continue;
2938 pfp.Vx3ID[end1] = vx3id;
2943 for (
auto& pfp : slc.
pfps) {
2944 if (pfp.ID == 0)
continue;
2946 if (pfp.PDGCode == 12 || pfp.PDGCode == 14 || pfp.PDGCode == 22)
continue;
2949 int pfpParentID = INT_MAX;
2950 unsigned short nParent = 0;
2951 for (
auto tjid : pfp.TjIDs) {
2952 auto& tj = slc.
tjs[tjid - 1];
2953 if (tj.ParentID <= 0)
continue;
2954 auto parPFP =
GetAssns(slc,
"T", tj.ParentID,
"P");
2955 if (parPFP.empty())
continue;
2956 if (pfpParentID == INT_MAX) pfpParentID = parPFP[0];
2957 if (parPFP[0] == pfpParentID) ++nParent;
2960 auto& ppfp = slc.
pfps[pfpParentID - 1];
2962 pfp.ParentUID = ppfp.UID;
2964 ppfp.DtrUIDs.push_back(pfp.UID);
2968 if (neutrinoPFPID > 0) {
2969 auto& neutrinoPFP = slc.
pfps[neutrinoPFPID - 1];
2970 int vx3id = neutrinoPFP.Vx3ID[1];
2971 for (
auto& pfp : slc.
pfps) {
2972 if (pfp.ID == 0 || pfp.ID == neutrinoPFPID)
continue;
2973 if (pfp.Vx3ID[0] != vx3id)
continue;
2974 pfp.ParentUID = (size_t)neutrinoPFPID;
2975 neutrinoPFP.DtrUIDs.push_back(pfp.ID);
2976 if (pfp.PDGCode == 111) neutrinoPFP.PDGCode = 12;
2987 if (pfp.
TjIDs.empty())
return false;
2988 if (pfp.
PDGCode != 1111 && pfp.
TP3Ds.size() < 2)
return false;
2993 for (
auto& tp3d : pfp.
TP3Ds) {
2994 if (tp3d.TPIndex != USHRT_MAX) slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex].InPFP = pfp.
ID;
2999 unsigned short nNotSet = 0;
3000 for (
auto& tp3d : pfp.
TP3Ds) {
3001 if (tp3d.Flags[
kTP3DBad])
continue;
3002 auto& tp = slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex];
3003 if (tp.InPFP != pfp.
ID) ++nNotSet;
3005 if (nNotSet > 0)
return false;
3007 if (pfp.
ID != (
int)slc.
pfps.size() + 1) pfp.
ID = slc.
pfps.size() + 1;
3012 for (
auto tjid : pfp.
TjIDs) {
3013 auto& tj = slc.
tjs[tjid - 1];
3014 tj.AlgMod[
kMat3D] =
true;
3017 slc.
pfps.push_back(pfp);
3025 if (pfp.
ID <= 0)
return false;
3026 if (end > 1)
return false;
3035 if (neutrinoPFP) { pos = pfp.
SectionFits[0].Pos; }
3036 else if (end == 0) {
3037 pos = pfp.
TP3Ds[0].Pos;
3042 return (pos[0] > slc.
xLo + abit && pos[0] < slc.
xHi - abit && pos[1] > slc.
yLo + abit &&
3043 pos[1] < slc.
yHi - abit && pos[2] > slc.
zLo + abit && pos[2] < slc.
zHi - abit);
3054 auto const world = TPC.GetCenter();
3056 if (pos[0] < world.X() - TPC.HalfWidth() + abit)
continue;
3057 if (pos[0] > world.X() + TPC.HalfWidth() - abit)
continue;
3058 if (pos[1] < world.Y() - TPC.HalfHeight() + abit)
continue;
3059 if (pos[1] > world.Y() + TPC.HalfHeight() - abit)
continue;
3060 if (pos[2] < world.Z() - TPC.Length() / 2 + abit)
continue;
3061 if (pos[2] > world.Z() + TPC.Length() / 2 - abit)
continue;
3074 if (pos1[0] == pos2[0] && pos1[1] == pos2[1] && pos1[2] == pos2[2])
return;
3077 double costh =
DotProd(dir1, ptDir);
3078 if (costh > 1) costh = 1;
3079 double sep =
PosSep(pos1, pos2);
3080 alongTrans[0] = costh * sep;
3081 double sinth = sqrt(1 - costh * costh);
3082 alongTrans[1] = sinth * sep;
3095 for (
unsigned short xyz = 0; xyz < 3; ++xyz) {
3096 p1End[xyz] = p1[xyz] + 10 * p1Dir[xyz];
3097 p2End[xyz] = p2[xyz] + 10 * p2Dir[xyz];
3120 double d1343, d4321, d1321, d4343, d2121;
3121 double numer, denom;
3122 constexpr
double EPS = std::numeric_limits<double>::min();
3124 p13[0] = p1[0] - p3[0];
3125 p13[1] = p1[1] - p3[1];
3126 p13[2] = p1[2] - p3[2];
3127 p43[0] = p4[0] - p3[0];
3128 p43[1] = p4[1] - p3[1];
3129 p43[2] = p4[2] - p3[2];
3131 p21[0] = p2[0] - p1[0];
3132 p21[1] = p2[1] - p1[1];
3133 p21[2] = p2[2] - p1[2];
3136 d1343 = p13[0] * p43[0] + p13[1] * p43[1] + p13[2] * p43[2];
3137 d4321 = p43[0] * p21[0] + p43[1] * p21[1] + p43[2] * p21[2];
3138 d1321 = p13[0] * p21[0] + p13[1] * p21[1] + p13[2] * p21[2];
3139 d4343 = p43[0] * p43[0] + p43[1] * p43[1] + p43[2] * p43[2];
3140 d2121 = p21[0] * p21[0] + p21[1] * p21[1] + p21[2] * p21[2];
3142 denom = d2121 * d4343 - d4321 * d4321;
3143 if (
std::abs(denom) < EPS)
return (
false);
3144 numer = d1343 * d4321 - d1321 * d4343;
3146 double mua = numer / denom;
3147 double mub = (d1343 + d4321 * mua) / d4343;
3149 intersect[0] = p1[0] + mua * p21[0];
3150 intersect[1] = p1[1] + mua * p21[1];
3151 intersect[2] = p1[2] + mua * p21[2];
3153 pb[0] = p3[0] + mub * p43[0];
3154 pb[1] = p3[1] + mub * p43[1];
3155 pb[2] = p3[2] + mub * p43[2];
3156 doca =
PosSep(intersect, pb);
3158 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
3159 intersect[xyz] += pb[xyz];
3160 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
3161 intersect[xyz] /= 2;
3175 float sep =
PosSep(pos1, pos2);
3176 if (sep == 0)
return -1;
3182 for (
unsigned short step = 0; step < nstep; ++step) {
3183 for (
unsigned short xyz = 0; xyz < 3; ++xyz)
3185 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
3195 if (cnt == 0)
return -1;
3207 if (pfp.
ID == 0)
return 0;
3208 if (pfp.
TjIDs.empty())
return 0;
3209 if (end > 1)
return 0;
3219 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
3221 std::vector<int> tjids(1);
3222 for (
auto tjid : pfp.
TjIDs) {
3223 auto& tj = slc.
tjs[tjid - 1];
3224 if (tj.CTP != inCTP)
continue;
3229 if (pos2[0] < -0.4)
continue;
3231 unsigned int wire = std::nearbyint(pos2[0]);
3232 if (wire > slc.
nWires[plane])
continue;
3233 if (slc.
wireHitRange[plane][wire].first == UINT_MAX)
continue;
3236 if (cf < lo) lo = cf;
3237 if (cf > hi) hi = cf;
3242 if (cnt == 0)
return 0;
3243 if (cnt > 1 && lo < 0.3 && hi > 0.8) {
3253 if (end > 1 || pfp.
SectionFits.empty())
return {{0., 0., 0.}};
3261 if (end > 1 || pfp.
SectionFits.empty())
return {{0., 0., 0.}};
3264 if (end == 0)
return pfp.
TP3Ds[0].Pos;
3271 if (pfp.
TP3Ds.empty())
return 0;
3277 unsigned short sfIndex,
3278 unsigned short& startPt,
3279 unsigned short& endPt)
3282 startPt = USHRT_MAX;
3284 if (sfIndex >= pfp.
SectionFits.size())
return false;
3287 for (std::size_t ipt = 0; ipt < pfp.
TP3Ds.size(); ++ipt) {
3288 auto& tp3d = pfp.
TP3Ds[ipt];
3289 if (tp3d.SFIndex < sfIndex)
continue;
3294 if (tp3d.SFIndex > sfIndex)
break;
3305 if (pfp.
ID == 0)
return 0;
3306 if (pfp.
TP3Ds.empty())
return 0;
3307 auto& pos0 = pfp.
TP3Ds[0].Pos;
3308 auto& pos1 = pfp.
TP3Ds[pfp.
TP3Ds.size() - 1].Pos;
3321 if (pfp.
TP3Ds.empty())
return -1;
3326 Average_dEdX(clockData, detProp, slc, pfp, dEdXAve, dEdXRms);
3327 if (dEdXAve < 0)
return 0;
3330 float length =
Length(pfp);
3334 for (
auto tjid : pfp.
TjIDs) {
3335 auto& tj = slc.
tjs[tjid - 1];
3337 if (el <= 0)
continue;
3338 mcsmom +=
MCSMom(slc, tj);
3339 chgrms += tj.ChgRMS;
3342 if (cnt < 2)
return 0;
3347 if (length > 150) vote = 13;
3349 if (vote == 0 && length > 50 && dEdXAve < 2.5 && mcsmom > 500) vote = 13;
3351 if (vote == 0 && dEdXAve > 3.0 && mcsmom > 200 && chgrms < 0.4) vote = 2212;
3353 if (vote == 0 && mcsmom < 50 && chgrms > 0.4) vote = 11;
3360 std::string someText,
3365 if (pfp.
TP3Ds.empty())
return;
3367 myprt << someText <<
" pfp P" << pfp.
ID <<
" MVI " << pfp.
MVI;
3368 for (
auto tid : pfp.
TjIDs)
3369 myprt <<
" T" << tid;
3373 for (
unsigned short ib = 0; ib <
pAlgModSize; ++ib) {
3379 <<
" SFI ________Pos________ ________Dir_______ _____EndPos________ ChiDOF NPts " 3381 for (std::size_t sfi = 0; sfi < pfp.
SectionFits.size(); ++sfi) {
3382 myprt << someText << std::setw(4) << sfi;
3384 myprt << std::fixed << std::setprecision(1);
3385 unsigned short startPt = 0, endPt = 0;
3387 auto& start = pfp.
TP3Ds[startPt].Pos;
3388 myprt << std::setw(7) << start[0] << std::setw(7) << start[1] << std::setw(7) << start[2];
3391 myprt <<
" Invalid";
3393 myprt << std::fixed << std::setprecision(2);
3394 myprt << std::setw(7) << sf.Dir[0] << std::setw(7) << sf.Dir[1] << std::setw(7)
3396 myprt << std::fixed << std::setprecision(1);
3397 if (endPt < pfp.
TP3Ds.size()) {
3399 myprt << std::setw(7) <<
end[0] << std::setw(7) <<
end[1] << std::setw(7) <<
end[2];
3402 myprt <<
" Invalid";
3404 myprt << std::setprecision(1) << std::setw(6) << sf.ChiDOF;
3405 myprt << std::setw(6) << sf.NPts;
3406 myprt << std::setw(6) << sf.NeedsUpdate;
3412 myprt << someText <<
" Note: GBH = TP3D Flags. G = Good, B = Bad, H = High dE/dx \n";
3415 <<
" ipt SFI ________Pos________ Delta Pull GBH Path along dE/dx S? T_ipt_P:W:T\n";
3417 unsigned short fromPt = 0;
3418 unsigned short toPt = pfp.
TP3Ds.size() - 1;
3419 if (printPts >= 0) fromPt = toPt;
3421 std::vector<float> dang(pfp.
TP3Ds.size(), -1);
3422 for (
unsigned short ipt = fromPt; ipt <= toPt; ++ipt) {
3423 auto tp3d = pfp.
TP3Ds[ipt];
3424 myprt << someText << std::setw(4) << ipt;
3425 myprt << std::setw(4) << tp3d.SFIndex;
3426 myprt << std::fixed << std::setprecision(1);
3427 myprt << std::setw(7) << tp3d.Pos[0] << std::setw(7) << tp3d.Pos[1] << std::setw(7)
3429 myprt << std::setprecision(1) << std::setw(6) << (tp3d.Pos[0] - tp3d.TPX);
3431 myprt << std::setprecision(1) << std::setw(6) << pull;
3433 myprt << std::setw(7) << std::setprecision(1) <<
PosSep(tp3d.Pos, pfp.
TP3Ds[0].Pos);
3434 myprt << std::setw(7) << std::setprecision(1) << tp3d.along;
3435 myprt << std::setw(6) << std::setprecision(2) <<
dEdx(clockData, detProp, slc, tp3d);
3438 for (
unsigned short plane = 0; plane < slc.
nPlanes; ++plane) {
3440 auto tp =
MakeBareTP(detProp, tp3d.Pos, inCTP);
3443 if (tp3d.TjID > 0) {
3444 auto& tp = slc.
tjs[tp3d.TjID - 1].Pts[tp3d.TPIndex];
3445 myprt <<
" T" << tp3d.TjID <<
"_" << tp3d.TPIndex <<
"_" <<
PrintPos(tp) <<
" " 3449 myprt <<
" UNDEFINED";
Expect tracks entering from the front face. Don't create neutrino PFParticles.
calo::CalorimetryAlg * caloAlg
code to link reconstructed objects back to the MC truth information
details::range_type< T > Iterate() const
Initializes the specified ID with the ID of the first cryostat.
short MCSMom(const TCSlice &slc, const std::vector< int > &tjIDs)
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< Trajectory > tjs
vector of all trajectories in each plane
float Length(const PFPStruct &pfp)
bool dbgStitch
debug PFParticle stitching
unsigned int NTPC(CryostatID const &cryoid=cryostat_zero) const
Returns the total number of TPCs in the specified cryostat.
void Average_dEdX(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, PFPStruct &pfp, float &dEdXAve, float &dEdXRms)
Length_t WireCoordinate(Point_t const &pos, PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
void MakePFParticles(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, std::vector< MatchStruct > matVec, unsigned short matVec_Iter)
std::array< std::vector< float >, 2 > dEdxErr
bool MakeVertexObsolete(std::string fcnLabel, TCSlice &slc, VtxStore &vx2, bool forceKill)
int TjID
ID of the trajectory -> TP3D assn.
bool ReconcileTPs(TCSlice &slc, PFPStruct &pfp, bool prt)
bool InsideFV(const TCSlice &slc, const PFPStruct &pfp, unsigned short end)
static unsigned int kWire
const std::vector< std::string > AlgBitNames
CTP_t CTP
Cryostat, TPC, Plane code.
bool InsideTPC(const Point3_t &pos, geo::TPCID &inTPCID)
bool HasWire(WireID const &wireid) const
Returns whether we have the specified wire.
std::array< double, 3 > Point3_t
bool SignalAtTp(TrajPoint &tp)
std::vector< float > vtx3DCuts
2D vtx -> 3D vtx matching cuts
bool SortSection(PFPStruct &pfp, unsigned short sfIndex)
Declaration of signal hit object.
void FindAlongTrans(Point3_t pos1, Vector3_t dir1, Point3_t pos2, Point2_t &alongTrans)
std::bitset< pAlgModSize > AlgMod
std::vector< std::vector< std::pair< unsigned int, unsigned int > > > wireHitRange
The data type to uniquely identify a Plane.
Geometry information for a single TPC.
Point3_t Pos
center position of this section
bool StoreTraj(TCSlice &slc, Trajectory &tj)
bool LineLineIntersect(Point3_t p1, Point3_t p2, Point3_t p3, Point3_t p4, Point3_t &intersect, float &doca)
bool IsShowerLike(TCSlice const &slc, std::vector< int > const &TjIDs)
constexpr auto abs(T v)
Returns the absolute value of the argument.
CryostatID_t Cryostat
Index of cryostat.
for(Int_t i=0;i< nentries;i++)
static unsigned int kPlane
void SetAngleCode(TrajPoint &tp)
PFPStruct CreatePFP(const TCSlice &slc)
Point3_t PosAtEnd(const PFPStruct &pfp, unsigned short end)
double DeltaAngle(const Vector3_t v1, const Vector3_t v2)
bool dbgSlc
debug only in the user-defined slice? default is all slices
void Match2Planes(TCSlice &slc, std::vector< MatchStruct > &matVec)
bool CanSection(const TCSlice &slc, const PFPStruct &pfp)
std::array< int, 2 > Vx3ID
float TPHitsRMSTime(const TCSlice &slc, const TrajPoint &tp, HitStatus_t hitRequest)
unsigned int MVI
MatchVec Index for detailed 3D matching.
void FilldEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, PFPStruct &pfp)
void ReconcileVertices(TCSlice &slc, PFPStruct &pfp, bool prt)
std::string TPEnvString(const TrajPoint &tp)
std::string PrintPos(const TrajPoint &tp)
std::vector< std::array< unsigned int, 3 > > sptHits
SpacePoint -> Hits assns by plane.
float MaxTjLen(const TCSlice &slc, std::vector< int > &tjIDs)
bool Update(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, PFPStruct &pfp)
void MakePFPTjs(TCSlice &slc)
unsigned short Find3DRecoRange(const TCSlice &slc, const PFPStruct &pfp, unsigned short fromPt, unsigned short min2DPts, short dir)
bool MakeSmallAnglePFP(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, PFPStruct &pfp, bool prt)
Vector3_t DirErr
and direction error
double ThetaZ() const
Angle of the wires from positive z axis; .
void AddPointsInRange(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, PFPStruct &pfp, unsigned short fromPt, unsigned short toPt, CTP_t inCTP, float maxPull, unsigned short &nWires, unsigned short &nAdd, bool prt)
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
float HitsRMSTime(const TCSlice &slc, const std::vector< unsigned int > &hitsInMultiplet, HitStatus_t hitRequest)
Access the description of detector geometry.
std::vector< int > TjUIDs
PlaneGeo const & Plane(PlaneID const &planeid) const
Returns the specified wire.
struct of temporary 3D vertices
void PFPVertexCheck(TCSlice &slc)
Vector3_t Dir
and direction
std::vector< Tj2Pt > mallTraj
vector of trajectory points ordered by increasing X
void FillGaps3D(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, PFPStruct &pfp, bool prt)
std::array< float, 2 > Point2_t
int PDGCodeVote(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, PFPStruct &pfp)
float unitsPerTick
scale factor from Tick to WSE equivalent units
Vector3_t PointDirection(const Point3_t p1, const Point3_t p2)
void FillWireIntersections(TCSlice &slc)
bool MakeTP3Ds(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, PFPStruct &pfp, bool prt)
unsigned short TPIndex
and the TP index
void Match3Planes(TCSlice &slc, std::vector< MatchStruct > &matVec)
void GetHitMultiplet(const TCSlice &slc, unsigned int theHit, std::vector< unsigned int > &hitsInMultiplet, bool useLongPulseHits)
bool TCIntersectionPoint(unsigned int wir1, unsigned int wir2, unsigned int pln1, unsigned int pln2, float &y, float &z)
float ElectronLikelihood(const TCSlice &slc, const Trajectory &tj)
bool FitSection(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, PFPStruct &pfp, unsigned short sfIndex)
std::vector< std::vector< bool > > goodWire
Point3_t Pos
position of the trajectory
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)
float ChgFracBetween(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, Point3_t pos1, Point3_t pos2)
TrajPoint MakeBareTP(detinfo::DetectorPropertiesData const &detProp, const Point3_t &pos, CTP_t inCTP)
std::vector< VtxStore > vtxs
2D vertices
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
double ConvertXToTicks(double X, int p, int t, int c) const
void CountBadPoints(const TCSlice &slc, const PFPStruct &pfp, unsigned short fromPt, unsigned short toPt, unsigned short &nBadPts, unsigned short &firstBadPt)
bool ReSection(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, PFPStruct &pfp, bool prt)
std::vector< float > match3DCuts
3D matching cuts
std::vector< SectionFit > SectionFits
void MakeTrajectoryObsolete(TCSlice &slc, unsigned int itj)
double TPXErr2
(X position error)^2
double PosSep2(const Point3_t &pos1, const Point3_t &pos2)
const geo::GeometryCore * geom
bool SectionStartEnd(const PFPStruct &pfp, unsigned short sfIndex, unsigned short &startPt, unsigned short &endPt)
bool PointDirIntersect(Point3_t p1, Vector3_t p1Dir, Point3_t p2, Vector3_t p2Dir, Point3_t &intersect, float &doca)
The data type to uniquely identify a TPC.
PlaneID_t Plane
Index of the plane within its TPC.
constexpr unsigned int pAlgModSize
void PrintP(mf::LogVerbatim &myprt, PFPStruct const &pfp, bool &printHeader)
bool valsIncreasing(const SortEntry &c1, const SortEntry &c2)
bool SetMag(Vector3_t &v1, double mag)
Definition of data types for geometry description.
unsigned short FarEnd(const PFPStruct &pfp, const Point3_t &pos)
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
std::vector< TCSlice > slices
Detector simulation of raw signals on wires.
void GetRange(const PFPStruct &pfp, unsigned short sfIndex, unsigned short &fromPt, unsigned short &npts)
unsigned short InsertTP3D(PFPStruct &pfp, TP3D &tp3d)
SectionFit FitTP3Ds(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, const std::vector< TP3D > &tp3ds, unsigned short fromPt, short fitDir, unsigned short nPtsFit)
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
void Recover(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc, PFPStruct &pfp, bool prt)
TP3D CreateTP3D(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, int tjID, unsigned short tpIndex)
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
std::vector< int > GetAssns(TCSlice const &slc, std::string type1Name, int id, std::string type2Name)
bool ValidTwoPlaneMatch(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, const PFPStruct &pfp)
double DotProd(const Vector3_t &v1, const Vector3_t &v2)
std::vector< Vtx3Store > vtx3s
3D vertices
void FillmAllTraj(detinfo::DetectorPropertiesData const &detProp, TCSlice &slc)
std::bitset< 128 > useAlg
Max hit separation for making junk trajectories. < 0 to turn off.
Encapsulate the construction of a single detector plane.
Contains all timing reference information for the detector.
std::vector< float > pfpStitchCuts
cuts for stitching between TPCs
TP3D MakeTP3D(detinfo::DetectorPropertiesData const &detProp, const TrajPoint &itp, const TrajPoint &jtp)
geo::PlaneID DecodeCTP(CTP_t CTP)
float along
distance from the start Pos of the section
double PosSep(const Point3_t &pos1, const Point3_t &pos2)
float PointPull(const TP3D &tp3d)
std::vector< TCWireIntersection > wireIntersections
std::vector< recob::Hit > const * allHits
bool valsDecreasing(const SortEntry &c1, const SortEntry &c2)
CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
double dEdx_AREA(detinfo::DetectorClocksData const &clock_data, detinfo::DetectorPropertiesData const &det_prop, recob::Hit const &hit, double pitch, double T0=0) const
std::pair< unsigned short, unsigned short > GetSliceIndex(std::string typeName, int uID)
unsigned short MVI_Iter
MVI iteration - see FindPFParticles.
std::vector< unsigned int > nWires
std::array< double, 3 > Vector3_t
std::vector< TP3D > TP3Ds
int ID
ID of the recob::Slice (not the sub-slice)
std::array< std::vector< float >, 2 > dEdx
void Match3PlanesSpt(TCSlice &slc, std::vector< MatchStruct > &matVec)
void FindPFParticles(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, TCSlice &slc)
std::vector< PFPStruct > pfps
void MoveTPToWire(TrajPoint &tp, float wire)
unsigned short NumPtsWithCharge(const TCSlice &slc, const Trajectory &tj, bool includeDeadWires)
bool IntersectionPoint(WireID const &wid1, WireID const &wid2, double &y, double &z) const
Returns the intersection point of two wires.
unsigned short CloseEnd(const Trajectory &tj, const Point2_t &pos)
double TPX
X position of the TP or the single hit.
TPCID_t TPC
Index of the TPC within its cryostat.
bool StorePFP(TCSlice &slc, PFPStruct &pfp)
Collection of Physical constants used in LArSoft.
float ChgFracNearEnd(detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, const PFPStruct &pfp, unsigned short end)
void PrintTP3Ds(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, std::string someText, const TCSlice &slc, const PFPStruct &pfp, short printPts)
Vector3_t DirAtEnd(const PFPStruct &pfp, unsigned short end)
bool SetSection(detinfo::DetectorPropertiesData const &detProp, PFPStruct &pfp, TP3D &tp3d)
Length_t WirePitch(PlaneID const &planeid=plane_zero) const
Returns the distance between two consecutive wires.
void DefinePFPParents(TCSlice &slc)
bool AttachToAnyVertex(TCSlice &slc, PFPStruct &pfp, float maxSep, bool prt)
constexpr TPCID()=default
Default constructor: an invalid TPC ID.
Encapsulate the construction of a single detector plane.
std::array< std::bitset< 8 >, 2 > EndFlag
bool SptInTPC(const std::array< unsigned int, 3 > &sptHits, unsigned int tpc)
void Reverse(PFPStruct &pfp)
unsigned short SFIndex
and the section fit index