27 using namespace detail;
39 if (tj.
Pts.empty())
return;
43 unsigned short lastPtWithUsedHits = tj.
EndPt[1];
45 unsigned short lastPt = lastPtWithUsedHits;
50 ltp.
Pos = tj.
Pts[lastPt].Pos;
51 ltp.
Dir = tj.
Pts[lastPt].Dir;
59 unsigned short nMissedSteps = 0;
65 tjfs[0].nextForecastUpdate = 6;
67 for (
unsigned short step = 1; step < 10000; ++step) {
73 npwc ==
tjfs[
tjfs.size() - 1].nextForecastUpdate) {
79 lastPt = tj.
Pts.size() - 1;
85 for (
unsigned short iwt = 0; iwt < 2; ++iwt)
86 ltp.
Pos[iwt] += ltp.
Dir[iwt] * stepSize;
92 myprt <<
"StepAway " << step <<
" Pos " << tp.
Pos[0] <<
" " << tp.
Pos[1] <<
" Dir " 93 << tp.
Dir[0] <<
" " << tp.
Dir[1] <<
" stepSize " << stepSize <<
" AngCode " 109 unsigned int wire = std::nearbyint(tp.
Pos[0]);
112 tj.
Pts.push_back(tp);
114 lastPt = tj.
Pts.size() - 1;
117 AddHits(slc, tj, lastPt, sigOK);
125 if (tj.
Pts[lastPt].AngleCode == 0 && lastPt == 2)
return;
135 if (tj.
Pts[lastPt].AngleCode > 0 && nMissedSteps > 4 && !sigOK)
break;
137 unsigned short lastPtWithHits = lastPt - 1;
140 float nMissedWires = tps *
std::abs(ltp.
Dir[0]) - dwc;
145 <<
" nMissedWires " << std::fixed << std::setprecision(1)
146 << nMissedWires <<
" dead wire count " << dwc <<
" maxWireSkip " 147 << maxWireSkip <<
" tj.PDGCode " << tj.
PDGCode;
148 if (nMissedWires > maxWireSkip) {
152 if (tj.
EndPt[1] < tj.
Pts.size() - 1 && tj.
Pts[tj.
EndPt[1] + 1].Hits.size() == 1) {
153 unsigned short lastLonelyPoint = tj.
EndPt[1] + 1;
154 unsigned int iht = tj.
Pts[lastLonelyPoint].Hits[0];
155 if (slc.
slHits[iht].InTraj == 0 &&
156 tj.
Pts[lastLonelyPoint].Delta < 3 * tj.
Pts[lastLonelyPoint].DeltaRMS) {
158 tj.
Pts[lastLonelyPoint].UseHit[0] =
true;
175 if (lastPt > 0 &&
PosSep2(tj.
Pts[lastPt].Pos, tj.
Pts[lastPt - 1].Pos) < 0.1)
return;
182 if (tj.
Pts[lastPt].Chg == 0) {
187 float nMissedWires = tps *
std::abs(ltp.
Dir[0]) - dwc;
189 mf::LogVerbatim(
"TC") <<
" Hits exist on the trajectory but are not used. Missed wires " 190 << std::nearbyint(nMissedWires) <<
" dead wire count " << (int)dwc;
207 if (tj.
Pts.size() == 3) {
218 if (dang > 0.5) badTj =
false;
221 if (!badTj && tj.
Pts[2].Delta > 2) badTj =
true;
224 mf::LogVerbatim(
"TC") <<
" Bad Tj found on the third point. Quit stepping.";
230 ltp.
Pos = tj.
Pts[lastPt].Pos;
231 ltp.
Dir = tj.
Pts[lastPt].Dir;
263 if (tj.
Pts[lastPt].FitChi >
tcc.
maxChi && useMaxChiCut) {
300 if (npwc > 10)
return false;
306 myprt <<
" ChiDOF " << chgFit.
ChiDOF;
307 myprt <<
" chg0 " << chgFit.
Par0 <<
" +/- " << chgFit.
ParErr;
313 if (chgFit.
ChiDOF < 2)
return false;
314 if (chgFit.
ParSlp > -20)
return false;
319 unsigned short lastHiPt = 0;
320 for (
unsigned short ipt = 0; ipt < tj.
Pts.size(); ++ipt) {
321 auto& tp = tj.
Pts[ipt];
322 if (tp.Chg <= 0)
continue;
328 if (cnt < 3)
return false;
331 mf::LogVerbatim(
"TC") <<
" aveChg " << (int)aveChg <<
" last TP AveChg " 334 unsigned short firstLoPt = lastHiPt + 1;
335 for (
unsigned short ipt = lastHiPt + 1; ipt < tj.
Pts.size(); ++ipt) {
336 auto& tp = tj.
Pts[ipt];
337 if (tp.Chg <= 0 || tp.Chg > 0.5 * aveChg)
continue;
343 for (
unsigned short ipt = firstLoPt; ipt <= tj.
EndPt[1]; ++ipt)
355 if (
tjfs.empty())
return;
372 bool tkLike = (tjf.outlook < 1.5);
374 bool chgIncreasing = (tjf.chgSlope > 0);
376 bool shLike = (tjf.outlook > 2 && chgIncreasing);
377 if (!shLike) shLike = tjf.showerLikeFraction > 0.5;
379 if (tj.
MCSMom > 0) momRat = (float)tjf.MCSMom / (
float)tj.
MCSMom;
382 myprt <<
"SetStrategy: npwc " << npwc <<
" outlook " << tjf.outlook;
383 myprt <<
" tj MCSMom " << tj.
MCSMom <<
" forecast MCSMom " << tjf.MCSMom;
384 myprt <<
" momRat " << std::fixed << std::setprecision(2) << momRat;
385 myprt <<
" tkLike? " << tkLike <<
" shLike? " << shLike;
386 myprt <<
" chgIncreasing? " << chgIncreasing;
387 myprt <<
" leavesBeforeEnd? " << tjf.leavesBeforeEnd <<
" endBraggPeak? " << tjf.endBraggPeak;
388 myprt <<
" nextForecastUpdate " << tjf.nextForecastUpdate;
390 if (tjf.outlook < 0)
return;
392 bool stiffMu = (tkLike && tjf.MCSMom > 600 && tjf.nextForecastUpdate > 100);
396 <<
"SetStrategy: High MCSMom, long forecast. Use the StiffMu strategy";
402 if (notStiff && !shLike && tj.
MCSMom < 100 && tjf.MCSMom < 100 && chgIncreasing) {
404 mf::LogVerbatim(
"TC") <<
"SetStrategy: Low MCSMom. Use the Slowing Tj strategy";
410 if (notStiff && !shLike && tj.
MCSMom < 200 && momRat < 0.7 && chgIncreasing) {
413 <<
"SetStrategy: Low MCSMom & low momRat. Use the Slowing Tj strategy";
419 if (!tjf.leavesBeforeEnd && tjf.endBraggPeak) {
421 mf::LogVerbatim(
"TC") <<
"SetStrategy: Found a Bragg peak. Use the Slowing Tj strategy";
427 if (tkLike && tjf.nextForecastUpdate > 100 && tjf.leavesBeforeEnd && tjf.MCSMom < 500) {
433 <<
"SetStrategy: Long track-like wandered out of forecast envelope. Reduce NTPsFit to " 438 if (tkLike && tjf.MCSMom > 600 && (tjf.foundShower || tjf.chgFitChiDOF > 20)) {
441 <<
" and a shower ahead. Use the StiffEl strategy";
448 if (shLike && !tjf.leavesBeforeEnd) {
450 mf::LogVerbatim(
"TC") <<
"SetStrategy: Inside a shower. Use the StiffEl strategy";
469 if (tj.
Pts[tj.
EndPt[1]].AngleCode == 2)
return;
476 tjf.nextForecastUpdate = USHRT_MAX;
479 unsigned short istp = 0;
480 unsigned short nMissed = 0;
489 float minAveChg = 1E6;
490 for (
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
491 if (tj.
Pts[ipt].AveChg <= 0)
continue;
492 if (tj.
Pts[ipt].AveChg > minAveChg)
continue;
493 minAveChg = tj.
Pts[ipt].AveChg;
495 if (minAveChg <= 0 || minAveChg == 1E6)
return;
504 float forecastWin0 =
std::abs(ltp.Pos[1] - ltp.HitPos[1]);
505 if (forecastWin0 < 1) forecastWin0 = 1;
506 ltp.Pos = ltp.HitPos;
507 double stepSize =
std::abs(1 / ltp.Dir[0]);
511 << npwc <<
" minAveChg " << (int)minAveChg <<
" stepSize " 512 << std::setprecision(2) << stepSize <<
" window " << window;
514 <<
" stp ___Pos____ nTPH Chg ChgPull Delta DRMS chgWid nTkLk nShLk";
519 unsigned short maxChgPt = 0;
520 unsigned short leavesNear = USHRT_MAX;
521 bool leavesBeforeEnd =
false;
522 unsigned short showerStartNear = USHRT_MAX;
523 unsigned short showerEndNear = USHRT_MAX;
526 unsigned short trimPts = 0;
527 for (istp = 0; istp < 1000; ++istp) {
529 for (
unsigned short iwt = 0; iwt < 2; ++iwt)
530 ltp.Pos[iwt] += ltp.Dir[iwt] * stepSize;
531 unsigned int wire = std::nearbyint(ltp.Pos[0]);
533 if (wire > slc.
lastWire[plane] - 1)
break;
546 ltp.Delta =
PointTrajDOCA(ltp.HitPos[0], ltp.HitPos[1], ltp);
547 ltp.DeltaRMS = ltp.Delta / window;
548 ltp.Environment.reset();
549 if (ltp.Chg > maxChg) {
551 maxChgPt = fctj.
Pts.size();
555 ltp.ChgPull = (ltp.Chg / minAveChg - 1) / tj.
ChgRMS;
556 if ((ltp.ChgPull > 3 && ltp.Hits.size() > 1) || ltp.ChgPull > 10) {
561 ltp.HitPosErr2 = 100;
567 if (fctj.
Pts.size() > 10) {
568 float shFrac = nShLike / (nShLike + nTkLike);
575 if (ltp.DeltaRMS > 0.8) {
576 leavesNear = npwc + fctj.
Pts.size();
578 leavesBeforeEnd =
true;
581 fctj.
Pts.push_back(ltp);
584 myprt << std::setw(4) << npwc + fctj.
Pts.size() <<
" " <<
PrintPos(ltp);
585 myprt << std::setw(5) << ltp.Hits.size();
586 myprt << std::setw(5) << (int)ltp.Chg;
587 myprt << std::fixed << std::setprecision(1);
588 myprt << std::setw(8) << ltp.ChgPull;
589 myprt << std::setw(8) << ltp.Delta;
590 myprt << std::setw(8) << std::setprecision(2) << ltp.DeltaRMS;
591 myprt << std::setw(8) << sqrt(ltp.HitPosErr2);
592 myprt << std::setw(6) << (int)nTkLike;
593 myprt << std::setw(6) << (int)nShLike;
601 if (doPrt)
mf::LogVerbatim(
"TC") <<
"No hits found after 10 steps - break";
608 if (fctj.
Pts.size() < 3)
return;
612 fctj.
Pts.resize(fctj.
Pts.size() - trimPts);
615 for (
auto& tp : fctj.
Pts)
622 if (maxChgPt > 0.3 * fctj.
Pts.size() && maxChg > 3 * tj.
AveChg) {
625 FitPar(fctj, 0, maxChgPt, 1, chgFit, 1);
628 FitPar(fctj, 0, fctj.
Pts.size(), 1, chgFit, 1);
630 tjf.chgSlope = chgFit.
ParSlp;
632 tjf.chgFitChiDOF = chgFit.
ChiDOF;
640 tjf.nextForecastUpdate = npwc + fctj.
Pts.size();
641 tjf.leavesBeforeEnd = leavesBeforeEnd;
642 tjf.foundShower =
false;
643 if (leavesNear < tjf.nextForecastUpdate) {
645 tjf.nextForecastUpdate = leavesNear;
647 else if (showerStartNear < tjf.nextForecastUpdate) {
649 tjf.nextForecastUpdate = showerStartNear;
650 tjf.foundShower =
true;
652 else if (showerEndNear < tjf.nextForecastUpdate) {
654 tjf.nextForecastUpdate = showerEndNear;
657 for (
auto& tp : fctj.
Pts)
659 tjf.showerLikeFraction = (float)nShLike / (
float)fctj.
Pts.size();
663 myprt <<
"Forecast T" << tj.
ID <<
" tj.AveChg " << (int)tj.
AveChg;
665 <<
" totChg " << (int)fctj.
TotChg;
666 myprt <<
" last pos " <<
PrintPos(ltp);
667 myprt <<
" MCSMom " << tjf.MCSMom;
668 myprt <<
" outlook " << std::fixed << std::setprecision(2) << tjf.outlook;
669 myprt <<
" chgSlope " << std::setprecision(1) << tjf.chgSlope <<
" +/- " << tjf.chgSlopeErr;
670 myprt <<
" chgRMS " << std::setprecision(1) << tjf.chgRMS;
671 myprt <<
" endBraggPeak " << tjf.endBraggPeak;
672 myprt <<
" chiDOF " << tjf.chgFitChiDOF;
673 myprt <<
" showerLike fraction " << tjf.showerLikeFraction;
674 myprt <<
" nextForecastUpdate " << tjf.nextForecastUpdate;
675 myprt <<
" leavesBeforeEnd? " << tjf.leavesBeforeEnd;
676 myprt <<
" foundShower? " << tjf.foundShower;
712 if (tj.
EndPt[1] < 1)
return;
718 unsigned int lastPt = tj.
EndPt[1];
729 unsigned short prevPtWithHits = USHRT_MAX;
730 unsigned short firstFitPt = tj.
EndPt[0];
731 for (
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
732 unsigned short ipt = lastPt - ii;
733 if (tj.
Pts[ipt].Chg > 0) {
734 prevPtWithHits = ipt;
739 if (prevPtWithHits == USHRT_MAX)
return;
745 if (lastPt < 4) minPtsFit = 2;
751 minPtsFit = lastPt / 3;
759 short newMCSMom =
MCSMom(slc, tj);
760 short minMCSMom = 0.5 * tj.
MCSMom;
761 if (lastPt > 10 && newMCSMom < minMCSMom) {
774 <<
" previous point with hits " << prevPtWithHits <<
" tj.Pts size " 775 << tj.
Pts.size() <<
" AngleCode " << lastTP.
AngleCode <<
" PDGCode " 776 << tj.
PDGCode <<
" maxChi " << maxChi <<
" minPtsFit " << minPtsFit
777 <<
" MCSMom " << tj.
MCSMom;
791 << lastTP.
Pos[1] <<
" dir " << lastTP.
Dir[0] <<
" " << lastTP.
Dir[1];
811 if (lastPt > 20 && tj.
Pts[prevPtWithHits].FitChi > 1.5 && lastTP.
NTPsFit > minPtsFit)
814 if (cleanMuon && lastPt > 200 && tj.
Pts[prevPtWithHits].FitChi > 1.0) lastTP.
NTPsFit -= 2;
829 unsigned short cnt = 0;
830 for (
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
831 unsigned short ipt = lastPt - ii;
832 if (tj.
Pts[ipt].Chg > 0) {
836 if (cnt == lastTP.
NTPsFit)
break;
840 unsigned short ndead =
842 if (lastTP.
FitChi > 1.5 && tj.
Pts.size() > 6) {
847 if (ndead > 5 && !cleanMuon) {
857 if (prevPtWithHits != USHRT_MAX && tj.
Pts[prevPtWithHits].FitChi > 0)
858 chirat = lastTP.
FitChi / tj.
Pts[prevPtWithHits].FitChi;
867 <<
" prevPtWithHits chisq " << tj.
Pts[prevPtWithHits].FitChi
868 <<
" chirat " << chirat <<
" NumPtsWithCharge " 892 << lastTP.
Dir[0] <<
" " << lastTP.
Dir[1] <<
" FitChi " << lastTP.
FitChi 893 <<
" NTPsFit " << lastTP.
NTPsFit <<
" ndead wires " << ndead
899 lastPt = tj.
EndPt[1];
908 unsigned short newNTPSFit = lastTP.
NTPsFit;
911 float prevChi = lastTP.
FitChi;
912 unsigned short ntry = 0;
915 while (lastTP.
FitChi > chiCut && lastTP.
NTPsFit > minPtsFit) {
916 if (lastTP.
NTPsFit > 15) { newNTPSFit = 0.7 * newNTPSFit; }
923 if (lastTP.
NTPsFit < 3) newNTPSFit = 2;
924 if (newNTPSFit < minPtsFit) newNTPSFit = minPtsFit;
927 if (newNTPSFit == minPtsFit && tj.
MCSMom < 30) chiCut = 2;
930 << lastTP.
NTPsFit <<
" Pass " << tj.
Pass <<
" chiCut " << chiCut;
933 if (lastTP.
FitChi > prevChi) {
936 <<
" Try to remove an earlier bad hit";
939 if (ntry == 2)
break;
942 if (lastTP.
NTPsFit == minPtsFit)
break;
953 lastPt = tj.
EndPt[1];
970 float defFrac = 1 / (float)(tj.
EndPt[1]);
971 lastTP.
AngErr = defFrac * tj.
Pts[0].AngErr + (1 - defFrac) * lastTP.
AngErr;
987 mf::LogVerbatim(
"TC") <<
"inside CheckStiffTj with NumPtsWithCharge = " 1061 bool isVLA = (tj.
Pts[tj.
EndPt[1]].AngleCode == 2);
1089 if (tj.
EndPt[1] < 4)
return;
1094 float frac = npwc / npts;
1099 mf::LogVerbatim(
"TC") <<
"CheckTraj: fraction of points with charge " << frac
1100 <<
" good traj? " << tj.
IsGood;
1121 if (tj.
Pts.empty())
return;
1122 if (ipt > tj.
Pts.size() - 1)
return;
1125 if (tj.
Pts[ipt].AngleCode == 2) {
1131 std::vector<unsigned int> closeHits;
1132 unsigned int lastPtWithUsedHits = tj.
EndPt[1];
1135 unsigned int wire = std::nearbyint(tp.
Pos[0]);
1142 float dw = tp.
Pos[0] - tj.
Pts[lastPtWithUsedHits].Pos[0];
1143 float dt = tp.
Pos[1] - tj.
Pts[lastPtWithUsedHits].Pos[1];
1144 float dpos = sqrt(dw * dw + dt * dt);
1145 float projErr = dpos * tj.
Pts[lastPtWithUsedHits].AngErr;
1147 float deltaCut = 3 * (projErr + tp.
DeltaRMS);
1150 float minDeltaCut = 1.1 * tj.
Pts[lastPtWithUsedHits].Delta;
1151 if (deltaCut < minDeltaCut) deltaCut = minDeltaCut;
1155 mf::LogVerbatim(
"TC") <<
" AddHits: calculated deltaCut " << deltaCut <<
" dw " << dw
1156 <<
" dpos " << dpos;
1158 if (deltaCut < 0.5) deltaCut = 0.5;
1159 if (deltaCut > 3) deltaCut = 3;
1165 bool passedDeadWires =
1168 if (passedDeadWires) deltaCut *= 2;
1173 float bigDelta = 2 * deltaCut;
1174 unsigned int imBig = UINT_MAX;
1175 tp.
Delta = deltaCut;
1177 float maxDeltaCut = 2 * bigDelta;
1179 if (!passedDeadWires && maxDeltaCut > 3) {
1188 <<
" projTick " << rawProjTick <<
" deltaRMS " << tp.
DeltaRMS 1189 <<
" tp.Dir[0] " << tp.
Dir[0] <<
" deltaCut " << deltaCut <<
" dpos " 1190 << dpos <<
" projErr " << projErr <<
" ExpectedHitsRMS " 1194 std::vector<unsigned int> hitsInMultiplet;
1197 unsigned int ipl = planeID.
Plane;
1198 if (wire > slc.
lastWire[ipl])
return;
1201 if (slc.
wireHitRange[ipl][wire].first == UINT_MAX)
return;
1202 unsigned int firstHit = slc.
wireHitRange[ipl][wire].first;
1203 unsigned int lastHit = slc.
wireHitRange[ipl][wire].second;
1205 for (
unsigned int iht = firstHit; iht <= lastHit; ++iht) {
1206 if (slc.
slHits[iht].InTraj == tj.
ID)
continue;
1207 if (slc.
slHits[iht].InTraj == SHRT_MAX)
continue;
1209 if (rawProjTick >
hit.StartTick() && rawProjTick <
hit.EndTick()) sigOK =
true;
1215 if (delta > 3)
continue;
1218 if (delta > maxDeltaCut)
continue;
1222 if (
tcc.
dbgStp && delta < 100 && dt < 100) {
1224 myprt <<
" iht " << iht;
1226 myprt <<
" delta " << std::fixed << std::setprecision(2) << delta <<
" deltaCut " 1227 << deltaCut <<
" dt " << dt;
1228 myprt <<
" BB Mult " << hitsInMultiplet.size() <<
" RMS " << std::setprecision(1)
1230 myprt <<
" Chi " << std::setprecision(1) <<
hit.GoodnessOfFit();
1231 myprt <<
" InTraj " << slc.
slHits[iht].InTraj;
1232 myprt <<
" Chg " << (int)
hit.Integral();
1233 myprt <<
" Signal? " << sigOK;
1235 if (slc.
slHits[iht].InTraj == 0 && delta < bigDelta && hitsInMultiplet.size() < 3 &&
1242 if (delta > 3)
continue;
1245 if (delta > deltaCut)
continue;
1248 if (std::find(closeHits.begin(), closeHits.end(), iht) != closeHits.end())
continue;
1249 closeHits.push_back(iht);
1250 if (hitsInMultiplet.size() > 1) {
1252 for (
auto& jht : hitsInMultiplet) {
1253 if (slc.
slHits[jht].InTraj == tj.
ID)
continue;
1254 if (std::find(closeHits.begin(), closeHits.end(), jht) != closeHits.end())
continue;
1255 closeHits.push_back(jht);
1262 myprt <<
"closeHits ";
1263 for (
auto iht : closeHits)
1267 myprt <<
" imBig " << imBig;
1273 bool nearSrcHit =
false;
1274 if (!sigOK) nearSrcHit =
NearbySrcHit(planeID, wire, (
float)rawProjTick, (
float)rawProjTick);
1275 sigOK = sigOK || !closeHits.empty() || nearSrcHit;
1281 <<
" closeHits size " << closeHits.size();
1284 if (imBig < slc.
slHits.size() && closeHits.empty()) {
1285 closeHits.push_back(imBig);
1288 <<
" w delta = " << bigDelta;
1290 if (closeHits.size() > 16) closeHits.resize(16);
1292 tp.
Hits.insert(tp.
Hits.end(), closeHits.begin(), closeHits.end());
1304 mf::LogVerbatim(
"TC") <<
" number of close hits " << closeHits.size() <<
" used hits " 1313 if (ipt > tj.
Pts.size() - 1)
return;
1323 std::vector<int> wires(1);
1324 wires[0] = std::nearbyint(tp.
Pos[0]);
1325 if (wires[0] < 0 || wires[0] > (
int)slc.
lastWire[plane] - 1)
return;
1329 <<
" Don't do this";
1335 if (tp.
Dir[0] > 0) {
1336 if (wires[0] < (
int)slc.
lastWire[plane] - 1) wires.push_back(wires[0] + 1);
1337 if (wires[0] > 0) wires.push_back(wires[0] - 1);
1340 if (wires[0] > 0) wires.push_back(wires[0] - 1);
1341 if (wires[0] < (
int)slc.
lastWire[plane] - 1) wires.push_back(wires[0] + 1);
1348 <<
" Wires under consideration";
1349 for (
auto& wire : wires)
1350 myprt <<
" " << wire;
1359 std::array<int, 2> wireWindow;
1360 std::array<float, 2> timeWindow;
1362 timeWindow[0] = ltp.
Pos[1] - pos1Window;
1363 timeWindow[1] = ltp.
Pos[1] + pos1Window;
1367 for (
unsigned short ii = 0; ii < wires.size(); ++ii) {
1368 int wire = wires[ii];
1369 if (wire < 0 || wire > (
int)slc.
lastWire[plane])
continue;
1371 if (slc.
wireHitRange[plane][wire].first == UINT_MAX) sigOK =
true;
1372 if (slc.
wireHitRange[plane][wire].first == UINT_MAX)
continue;
1373 wireWindow[0] = wire;
1374 wireWindow[1] = wire;
1377 std::vector<unsigned int> closeHits =
1379 if (hitsNear) sigOK =
true;
1380 for (
auto& iht : closeHits) {
1382 if (slc.
slHits[iht].InTraj == tj.
ID)
continue;
1384 if (std::find(oldHits.begin(), oldHits.end(), iht) != oldHits.end())
continue;
1385 tp.
Hits.push_back(iht);
1391 myprt <<
" LAPos " <<
PrintPos(ltp) <<
" Tick window " 1394 for (
auto& iht : tp.
Hits)
1399 if (tp.
Hits.empty())
return;
1401 if (tp.
Hits.size() > 16) tp.
Hits.resize(16);
1404 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1405 unsigned int iht = tp.
Hits[ii];
1406 if (slc.
slHits[iht].InTraj != 0)
continue;
1424 if (tj.
Pts.size() < 6)
return;
1429 if (tj.
Pts[tj.
EndPt[0]].AngleCode == 2)
return;
1434 if (tj.
EndPt[0] > 0) {
1440 mf::LogVerbatim(
"TC") <<
"ReversePropagate: Prepping Tj " << tj.
ID <<
" incoming StepDir " 1446 unsigned int wire0 = std::nearbyint(tj.
Pts[0].Pos[0]);
1447 unsigned int nextWire = wire0 - tj.
StepDir;
1451 unsigned short ipl = planeID.
Plane;
1456 if (nextWire == slc.
lastWire[ipl] - 1)
return;
1465 float maxDelta = 10 * tj.
Pts[tj.
EndPt[1]].DeltaRMS;
1469 if (tp.
Hits.empty())
return;
1474 myprt <<
" tp.Hits ";
1475 for (
auto& iht : tp.
Hits)
1486 auto saveStrategy = tjWork.
Strategy;
1490 unsigned short lastPt = tjWork.
Pts.size() - 1;
1491 if (lastPt < 4)
return;
1495 for (
unsigned short ii = 0; ii < 4; ++ii) {
1496 unsigned short ipt = lastPt - ii;
1497 if (tjWork.
Pts[ipt].Chg == 0)
continue;
1498 chg += tjWork.
Pts[ipt].Chg;
1501 if (cnt == 0)
return;
1502 if (cnt > 1) tjWork.
Pts[lastPt].AveChg = chg / cnt;
1505 if (prt)
mf::LogVerbatim(
"TC") <<
" ReversePropagate StepAway failed";
1522 unsigned int theHit,
1523 std::vector<unsigned int>& hitsInMultiplet,
1524 bool useLongPulseHits)
1533 hitsInMultiplet.clear();
1535 if (theHit >= slc.
slHits.size())
return;
1536 if (slc.
slHits[theHit].InTraj == INT_MAX)
return;
1543 short int hitMult =
hit.Multiplicity();
1544 unsigned int lIndex =
hit.LocalIndex();
1545 unsigned int firstHit = 0;
1546 if (lIndex < theHit) firstHit = theHit - lIndex;
1547 for (
unsigned int ii = firstHit; ii < firstHit + hitMult; ++ii) {
1548 if (ii >= slc.
slHits.size())
break;
1550 if (
tmp.Multiplicity() == hitMult) hitsInMultiplet.push_back(ii);
1555 hitsInMultiplet.resize(1);
1556 hitsInMultiplet[0] = theHit;
1557 unsigned int theWire =
hit.WireID().Wire;
1558 unsigned short ipl =
hit.WireID().Plane;
1560 float theTime =
hit.PeakTime();
1561 float theRMS =
hit.RMS();
1563 bool theHitIsNarrow = (theRMS < narrowHitCut);
1564 float maxPeak =
hit.PeakAmplitude();
1565 unsigned int imTall = theHit;
1566 unsigned short nNarrow = 0;
1567 if (theHitIsNarrow) nNarrow = 1;
1570 for (
unsigned int iht = theHit - 1; iht != 0; --iht) {
1572 if (
hit.WireID().Wire != theWire)
break;
1573 if (
hit.WireID().Plane != ipl)
break;
1575 float rms =
hit.RMS();
1581 if (dTick > hitSep)
break;
1582 hitsInMultiplet.push_back(iht);
1583 if (rms < narrowHitCut) ++nNarrow;
1584 float peakAmp =
hit.PeakAmplitude();
1585 if (peakAmp > maxPeak) {
1589 theTime =
hit.PeakTime();
1590 if (iht == 0)
break;
1595 if (hitsInMultiplet.size() > 1) std::reverse(hitsInMultiplet.begin(), hitsInMultiplet.end());
1597 theTime =
hit.PeakTime();
1599 for (
unsigned int iht = theHit + 1; iht < slc.
slHits.size(); ++iht) {
1601 if (
hit.WireID().Wire != theWire)
break;
1602 if (
hit.WireID().Plane != ipl)
break;
1603 if (slc.
slHits[iht].InTraj == INT_MAX)
continue;
1605 float rms =
hit.RMS();
1611 if (dTick > hitSep)
break;
1612 hitsInMultiplet.push_back(iht);
1613 if (rms < narrowHitCut) ++nNarrow;
1614 float peakAmp =
hit.PeakAmplitude();
1615 if (peakAmp > maxPeak) {
1619 theTime =
hit.PeakTime();
1621 if (hitsInMultiplet.size() == 1)
return;
1624 if (nNarrow == hitsInMultiplet.size())
return;
1625 if (nNarrow == 0)
return;
1627 if (theHitIsNarrow && theHit == imTall) {
1630 auto tmp = hitsInMultiplet;
1633 hitsInMultiplet =
tmp;
1639 if (
hit.RMS() < narrowHitCut) {
1640 unsigned short killMe = 0;
1641 for (
unsigned short ii = 0; ii < hitsInMultiplet.size(); ++ii) {
1642 if (hitsInMultiplet[ii] == imTall) {
1647 hitsInMultiplet.erase(hitsInMultiplet.begin() + killMe);
1656 if (iht > slc.
slHits.size() - 1)
return 0;
1665 if (hitVec.empty())
return 0;
1681 unsigned short endPt = tj.
EndPt[1];
1683 if (tj.
Pts[endPt].AngleCode > 1)
return;
1685 if (tj.
Pts.size() - endPt > 10)
return;
1689 unsigned short plane = planeID.
Plane;
1692 unsigned short lastPt = tj.
Pts.size() - 1;
1693 for (lastPt = tj.
Pts.size() - 1; lastPt >= tj.
EndPt[1]; --lastPt)
1694 if (!tj.
Pts[lastPt].Hits.empty())
break;
1695 auto& lastTP = tj.
Pts[lastPt];
1698 mf::LogVerbatim(
"TC") <<
"CSEP: checking " << tj.
ID <<
" endPt " << endPt <<
" Pts size " 1699 << tj.
Pts.size() <<
" lastPt Pos " <<
PrintPos(lastTP.Pos);
1703 ltp.
Pos = tj.
Pts[endPt].Pos;
1704 ltp.
Dir = tj.
Pts[endPt].Dir;
1706 std::array<int, 2> wireWindow;
1707 std::array<float, 2> timeWindow;
1708 std::vector<int> closeHits;
1709 bool isClean =
true;
1710 for (
unsigned short step = 0; step < 10; ++step) {
1711 for (
unsigned short iwt = 0; iwt < 2; ++iwt)
1712 ltp.
Pos[iwt] += ltp.
Dir[iwt] * stepSize;
1713 int wire = std::nearbyint(ltp.
Pos[0]);
1714 wireWindow[0] = wire;
1715 wireWindow[1] = wire;
1716 timeWindow[0] = ltp.
Pos[1] - 5;
1717 timeWindow[1] = ltp.
Pos[1] + 5;
1721 for (
auto iht :
tmp)
1722 if (slc.
slHits[iht].InTraj != tj.
ID) closeHits.push_back(iht);
1723 float nWiresPast = 0;
1725 if (ltp.
Dir[0] > 0) {
1727 nWiresPast = ltp.
Pos[0] - lastTP.Pos[0];
1731 nWiresPast = lastTP.Pos[0] - ltp.
Pos[0];
1735 <<
" nWiresPast " << nWiresPast;
1736 if (nWiresPast > 0.5) {
1737 if (!tmp.empty()) isClean =
false;
1738 if (nWiresPast > 1.5)
break;
1743 unsigned short nAvailable = 0;
1744 for (
auto iht : closeHits)
1745 if (slc.
slHits[iht].InTraj == 0) ++nAvailable;
1749 myprt <<
"closeHits";
1750 for (
auto iht : closeHits)
1752 myprt <<
" nAvailable " << nAvailable;
1753 myprt <<
" isClean " << isClean;
1756 if (!isClean || nAvailable != closeHits.size())
return;
1758 unsigned short originalEndPt = tj.
EndPt[1] + 1;
1760 for (
unsigned short ipt = originalEndPt; ipt <= lastPt; ++ipt) {
1761 auto& tp = tj.
Pts[ipt];
1762 bool hitsAdded =
false;
1763 for (
unsigned short ii = 0; ii < tp.Hits.size(); ++ii) {
1765 if (slc.
slHits[tp.Hits[ii]].InTraj != 0)
continue;
1766 tp.UseHit[ii] =
true;
1767 slc.
slHits[tp.Hits[ii]].InTraj = tj.
ID;
1781 for (
unsigned short ipt = originalEndPt; ipt <= lastPt; ++ipt)
1796 if (tp.
Hits.empty())
return;
1798 unsigned short nused = 0;
1799 unsigned int iht = 0;
1800 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1801 if (!tp.
UseHit[ii])
continue;
1804 if (iht >= slc.
slHits.size())
return;
1807 if (nused == 0)
return;
1823 if (pathInv < 0.05) pathInv = 0.05;
1825 float wireErr = tp.
Dir[1] * 0.289;
1827 tp.
HitPosErr2 = wireErr * wireErr + timeErr * timeErr;
1830 mf::LogVerbatim(
"TC") <<
"DefineHitPos: singlet " << std::fixed << std::setprecision(1)
1832 <<
" ticks. HitPosErr " << sqrt(tp.
HitPosErr2);
1837 std::vector<unsigned int> hitVec;
1839 std::array<float, 2> newpos;
1844 unsigned int loWire = INT_MAX;
1845 unsigned int hiWire = 0;
1846 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1847 if (!tp.
UseHit[ii])
continue;
1848 unsigned int iht = tp.
Hits[ii];
1850 chg =
hit.Integral();
1851 unsigned int wire =
hit.WireID().Wire;
1852 if (wire < loWire) loWire = wire;
1853 if (wire > hiWire) hiWire = wire;
1854 newpos[0] += chg * wire;
1855 newpos[1] += chg *
hit.PeakTime();
1857 hitVec.push_back(iht);
1860 if (tp.
Chg == 0)
return;
1866 if (pathInv < 0.05) pathInv = 0.05;
1870 float dWire = 1 + hiWire - loWire;
1871 float wireErr = tp.
Dir[1] * dWire * 0.289;
1873 tp.
HitPosErr2 = wireErr * wireErr + timeErr2;
1875 mf::LogVerbatim(
"TC") <<
"DefineHitPos: multiplet " << std::fixed << std::setprecision(1)
1877 <<
" ticks. HitPosErr " << sqrt(tp.
HitPosErr2);
1887 if (ipt > tj.
Pts.size() - 1)
return;
1890 if (tp.
Hits.empty())
return;
1892 if (ipt < 5) useChg =
false;
1893 float chgPullCut = 1000;
1897 if (tj.
MCSMom < 30) chgPullCut *= 2;
1899 bool ignoreLongPulseHits =
false;
1900 unsigned short npts = tj.
EndPt[1] - tj.
EndPt[0] + 1;
1901 if (npts < 10 || tj.
AlgMod[
kRvPrp]) ignoreLongPulseHits =
true;
1904 mf::LogVerbatim(
"TC") <<
"FUH: maxDelta " << maxDelta <<
" useChg requested " << useChg
1905 <<
" Norm AveChg " << (int)tp.
AveChg <<
" tj.ChgRMS " 1906 << std::setprecision(2) << tj.
ChgRMS <<
" chgPullCut " << chgPullCut
1908 <<
" ExpectedHitsRMS " << (int)expectedHitsRMS <<
" AngCode " 1914 if (pathInv < 0.05) pathInv = 0.05;
1917 tp.
Delta = maxDelta;
1919 unsigned short imbest = USHRT_MAX;
1920 std::vector<float> deltas(tp.
Hits.size(), 100);
1922 float bestDelta = maxDelta;
1923 unsigned short nAvailable = 0;
1924 unsigned short firstAvailable = USHRT_MAX;
1925 unsigned short lastAvailable = USHRT_MAX;
1926 unsigned short firstUsed = USHRT_MAX;
1927 unsigned short imBadRecoHit = USHRT_MAX;
1928 bool bestHitLongPulse =
false;
1929 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1931 unsigned int iht = tp.
Hits[ii];
1932 if (iht >= slc.
slHits.size())
continue;
1935 if (delta < bestDelta) bestDelta = delta;
1936 if (slc.
slHits[iht].InTraj > 0) {
1937 if (firstUsed == USHRT_MAX) firstUsed = ii;
1942 if (
hit.GoodnessOfFit() < 0 ||
hit.GoodnessOfFit() > 100) imBadRecoHit = ii;
1943 if (firstAvailable == USHRT_MAX) firstAvailable = ii;
1950 << delta <<
" Norm Chg " << (int)(
hit.Integral() * pathInv);
1959 if (delta < tp.
Delta) {
1966 float chgWght = 0.5;
1969 mf::LogVerbatim(
"TC") <<
" firstAvailable " << firstAvailable <<
" lastAvailable " 1970 << lastAvailable <<
" firstUsed " << firstUsed <<
" imbest " << imbest
1971 <<
" single hit. tp.Delta " << std::setprecision(2) << tp.
Delta 1972 <<
" bestDelta " << bestDelta <<
" path length " << 1 / pathInv
1973 <<
" imBadRecoHit " << imBadRecoHit;
1974 if (imbest == USHRT_MAX || nAvailable == 0)
return;
1975 unsigned int bestDeltaHit = tp.
Hits[imbest];
1979 tp.
UseHit[imbest] =
true;
1980 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
1985 if (tp.
Hits.size() > 2 && nAvailable > 1 && firstUsed != USHRT_MAX &&
1986 firstAvailable < firstUsed && lastAvailable > firstUsed) {
1989 <<
" A hit in the middle of the multiplet is used. Use only the best hit";
1990 tp.
UseHit[imbest] =
true;
1991 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
1997 std::vector<unsigned int> hitsInMultiplet;
2002 myprt <<
" in multiplet:";
2003 for (
auto& iht : hitsInMultiplet)
2008 if (imBadRecoHit != USHRT_MAX) {
2009 unsigned int iht = tp.
Hits[imBadRecoHit];
2014 tp.
UseHit[imBadRecoHit] =
true;
2020 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
2021 unsigned int iht = tp.
Hits[ii];
2022 if (slc.
slHits[iht].InTraj > 0)
continue;
2023 if (std::find(hitsInMultiplet.begin(), hitsInMultiplet.end(), iht) == hitsInMultiplet.end())
2035 if (!useChg || (useChg && (tj.
AveChg <= 0 || tj.
ChgRMS <= 0))) {
2039 <<
". Use the best hit";
2040 tp.
UseHit[imbest] =
true;
2041 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
2046 if (tj.
PDGCode == 13 && bestDelta < 0.5) {
2048 tp.
UseHit[imbest] =
true;
2049 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
2054 if (nAvailable == 1 || tp.
AngleCode == 0) {
2056 float aveChg = tp.
AveChg;
2057 if (aveChg <= 0) aveChg = tj.
AveChg;
2058 if (aveChg <= 0) aveChg =
hit.Integral();
2059 float chgRMS = tj.
ChgRMS;
2060 if (chgRMS < 0.2) chgRMS = 0.2;
2061 float bestDeltaHitChgPull =
std::abs(
hit.Integral() * pathInv / aveChg - 1) / chgRMS;
2063 mf::LogVerbatim(
"TC") <<
" bestDeltaHitChgPull " << bestDeltaHitChgPull <<
" chgPullCut " 2065 if (bestDeltaHitChgPull < chgPullCut || tp.
Delta < 0.1) {
2066 tp.
UseHit[imbest] =
true;
2067 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
2076 if (nAvailable == 2) {
2078 std::vector<unsigned int> tHits;
2082 unsigned short ombest = USHRT_MAX;
2083 unsigned int otherHit = INT_MAX;
2084 if (tHits.size() == 2) {
2085 unsigned short localIndex = 0;
2086 if (tHits[0] == bestDeltaHit) localIndex = 1;
2087 otherHit = tHits[1 - localIndex];
2089 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
2090 if (slc.
slHits[tp.
Hits[ii]].InTraj > 0)
continue;
2091 if (tp.
Hits[ii] == otherHit) {
2098 mf::LogVerbatim(
"TC") <<
" Doublet: imbest " << imbest <<
" ombest " << ombest;
2101 if (ombest < tp.
Hits.size()) {
2103 float bestHitDeltaErr =
2106 float bestDeltaHitFOM = deltas[imbest] / bestHitDeltaErr;
2107 if (bestDeltaHitFOM < 0.5) bestDeltaHitFOM = 0.5;
2111 if (bestDeltaHitChgPull > 1) bestDeltaHitFOM *= chgWght * bestDeltaHitChgPull;
2113 float rmsRat =
hit.RMS() / expectedWidth;
2114 if (rmsRat < 1) rmsRat = 1 / rmsRat;
2115 bestDeltaHitFOM *= rmsRat;
2117 mf::LogVerbatim(
"TC") <<
" bestDeltaHit FOM " << deltas[imbest] / bestHitDeltaErr
2118 <<
" bestDeltaHitChgPull " << bestDeltaHitChgPull <<
" rmsRat " 2119 << rmsRat <<
" bestDeltaHitFOM " << bestDeltaHitFOM;
2121 float otherHitDeltaErr =
2123 float otherHitFOM = deltas[ombest] / otherHitDeltaErr;
2124 if (otherHitFOM < 0.5) otherHitFOM = 0.5;
2127 if (otherHitChgPull > 1) otherHitFOM *= chgWght * otherHitChgPull;
2128 rmsRat = ohit.RMS() / expectedWidth;
2129 if (rmsRat < 1) rmsRat = 1 / rmsRat;
2130 otherHitFOM *= rmsRat;
2132 mf::LogVerbatim(
"TC") <<
" otherHit FOM " << deltas[ombest] / otherHitDeltaErr
2133 <<
" otherHitChgPull " << otherHitChgPull <<
" rmsRat " << rmsRat
2134 <<
" otherHitFOM " << otherHitFOM;
2136 float doubletChg =
hit.Integral() + ohit.Integral();
2138 (
hit.Integral() *
hit.PeakTime() + ohit.Integral() * ohit.PeakTime()) / doubletChg;
2139 doubletChg *= pathInv;
2144 mf::LogVerbatim(
"TC") <<
" doublet Chg " << doubletChg <<
" doubletTime " << doubletTime
2145 <<
" doubletRMSTimeErr " << doubletRMSTimeErr;
2146 float doubletFOM =
PointTrajDOCA(tp.
Pos[0], doubletTime, tp) / doubletRMSTimeErr;
2147 if (doubletFOM < 0.5) doubletFOM = 0.5;
2149 if (doubletChgPull > 1) doubletFOM *= chgWght * doubletChgPull;
2150 rmsRat = doubletWidthTick / expectedWidth;
2151 if (rmsRat < 1) rmsRat = 1 / rmsRat;
2152 doubletFOM *= rmsRat;
2156 <<
" doubletChgPull " << doubletChgPull <<
" rmsRat " << rmsRat
2157 <<
" doubletFOM " << doubletFOM;
2158 if (doubletFOM < bestDeltaHitFOM && doubletFOM < otherHitFOM) {
2159 tp.
UseHit[imbest] =
true;
2160 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
2161 tp.
UseHit[ombest] =
true;
2162 slc.
slHits[otherHit].InTraj = tj.
ID;
2166 if (bestDeltaHitFOM < otherHitFOM) {
2167 tp.
UseHit[imbest] =
true;
2168 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
2171 tp.
UseHit[ombest] =
true;
2172 slc.
slHits[otherHit].InTraj = tj.
ID;
2178 tp.
UseHit[imbest] =
true;
2179 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
2187 mf::LogVerbatim(
"TC") <<
" Multiplet: hitsWidth " << hitsWidth <<
" expectedWidth " 2188 << expectedWidth <<
" tick range " << (int)minTick <<
" " 2191 for (
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
2192 unsigned int iht = tp.
Hits[ii];
2193 if (slc.
slHits[iht].InTraj > 0)
continue;
2195 if (
hit.PeakTime() < minTick)
continue;
2196 if (
hit.PeakTime() > maxTick)
continue;
2210 if (tj.
ChgRMS <= 0)
return;
2213 if (npwc < 8)
return;
2216 unsigned short toPt = tj.
EndPt[1] - 2;
2220 unsigned short cnt = 0;
2221 for (
unsigned short ipt = tj.
EndPt[1] - 2; ipt > tj.
EndPt[0]; --ipt) {
2222 auto& tp = tj.
Pts[ipt];
2225 for (
unsigned short ii = 0; ii < tp.Hits.size(); ++ii) {
2226 unsigned int iht = tp.Hits[ii];
2228 chg +=
hit.Integral();
2237 if (cnt > 20)
break;
2246 short firstPtWithChg = tj.
EndPt[0];
2250 short minMCSMom = 0.7 * tj.
MCSMom;
2251 while (firstPtWithChg < toPt) {
2252 short nextPtWithChg = firstPtWithChg + 1;
2254 for (nextPtWithChg = firstPtWithChg + 1; nextPtWithChg < tj.
EndPt[1]; ++nextPtWithChg) {
2255 if (tj.
Pts[nextPtWithChg].Chg > 0)
break;
2257 if (nextPtWithChg == firstPtWithChg + 1) {
2263 if (nextPtWithChg < (tj.
EndPt[1] - 1) && tj.
Pts[nextPtWithChg + 1].Chg == 0) {
2264 firstPtWithChg = nextPtWithChg;
2282 if (tj.
Pts.size() < 10) { maxChg = 1E6; }
2284 short chgCutPt = tj.
EndPt[0] + 5;
2285 if (firstPtWithChg < chgCutPt) {
2291 chgCutPt = tj.
EndPt[1] - 5;
2292 if (chgCutPt < tj.
EndPt[0]) chgCutPt = tj.
EndPt[0];
2293 if (nextPtWithChg > chgCutPt) maxChg = 1E6;
2298 for (
unsigned short mpt = firstPtWithChg + 1; mpt < nextPtWithChg; ++mpt) {
2299 if (tj.
Pts[mpt].Chg > 0) {
2300 mf::LogVerbatim(
"TC") <<
"FillGaps coding error: firstPtWithChg " << firstPtWithChg
2301 <<
" mpt " << mpt <<
" nextPtWithChg " << nextPtWithChg;
2305 bool filled =
false;
2307 for (
unsigned short ii = 0; ii < tj.
Pts[mpt].Hits.size(); ++ii) {
2308 unsigned int iht = tj.
Pts[mpt].Hits[ii];
2309 if (slc.
slHits[iht].InTraj > 0)
continue;
2314 <<
PrintHit(slc.
slHits[iht]) <<
" delta " << delta <<
" maxDelta " 2315 << maxDelta <<
" Chg " <<
hit.Integral() <<
" maxChg " << maxChg;
2316 if (delta > maxDelta)
continue;
2317 tj.
Pts[mpt].UseHit[ii] =
true;
2319 chg +=
hit.Integral();
2322 if (chg > maxChg ||
MCSMom(slc, tj) < minMCSMom) {
2336 firstPtWithChg = nextPtWithChg;
2354 if (tj.
Pts[tj.
EndPt[1]].AngleCode == 0)
return;
2359 unsigned short ii, stopPt;
2362 unsigned short lastMult1Pt = USHRT_MAX;
2364 unsigned short nHiMultPt = 0;
2366 unsigned short nHiMultPtHits = 0;
2368 unsigned short nHiMultPtUsedHits = 0;
2372 bool doBreak =
false;
2374 for (ii = 1; ii < tj.
Pts.size(); ++ii) {
2375 stopPt = tj.
EndPt[1] - ii;
2376 for (jj = 0; jj < tj.
Pts[stopPt].Hits.size(); ++jj) {
2377 iht = tj.
Pts[stopPt].Hits[jj];
2378 if (slc.
slHits[iht].InTraj > 0) {
2385 if (lastMult1Pt == USHRT_MAX && tj.
Pts[stopPt].Hits.size() == 1 &&
2386 tj.
Pts[stopPt - 1].Hits.size() == 1)
2387 lastMult1Pt = stopPt;
2388 if (tj.
Pts[stopPt].Hits.size() > 1) {
2390 nHiMultPtHits += tj.
Pts[stopPt].Hits.size();
2394 if (lastMult1Pt != USHRT_MAX)
break;
2395 if (stopPt == 1)
break;
2398 float fracHiMult = (float)nHiMultPt / (
float)ii;
2399 if (lastMult1Pt != USHRT_MAX) {
2400 float nchk = tj.
EndPt[1] - lastMult1Pt + 1;
2401 fracHiMult = (float)nHiMultPt / nchk;
2404 fracHiMult = (float)nHiMultPt / (
float)ii;
2406 float fracHitsUsed = 0;
2407 if (nHiMultPt > 0 && nHiMultPtHits > 0)
2408 fracHitsUsed = (float)nHiMultPtUsedHits / (
float)nHiMultPtHits;
2415 mf::LogVerbatim(
"TC") <<
"CHMUH: First InTraj stopPt " << stopPt <<
" fracHiMult " 2416 << fracHiMult <<
" fracHitsUsed " << fracHitsUsed <<
" lastMult1Pt " 2417 << lastMult1Pt <<
" sortaLargeAngle " << sortaLargeAngle;
2418 if (fracHiMult < 0.3)
return;
2419 if (fracHitsUsed > 0.98)
return;
2425 <<
" nHiMultPtHits " << nHiMultPtHits <<
" nHiMultPtUsedHits " 2426 << nHiMultPtUsedHits <<
" sortaLargeAngle " << sortaLargeAngle
2427 <<
" maxHitDelta " << maxDelta;
2440 for (ipt = stopPt + 1; ipt < tj.
Pts.size(); ++ipt)
2445 for (ipt = stopPt + 1; ipt < tj.
Pts.size(); ++ipt) {
2448 for (ii = 0; ii < tj.
Pts[ipt].Hits.size(); ++ii) {
2449 iht = tj.
Pts[ipt].Hits[ii];
2452 <<
" inTraj " << slc.
slHits[iht].InTraj <<
" delta " 2454 if (slc.
slHits[iht].InTraj != 0)
continue;
2456 if (delta > maxDelta)
continue;
2458 tj.
Pts[ipt].UseHit[ii] =
true;
2464 if (tj.
Pts[ipt].Chg == 0)
continue;
2467 if (sortaLargeAngle) tj.
Pts[ipt].NTPsFit = 2;
2472 for (
unsigned short jpt = stopPt + 1; jpt <= ipt; ++jpt) {
2473 for (
unsigned short jj = 0; jj < tj.
Pts[jpt].Hits.size(); ++jj) {
2474 if (tj.
Pts[jpt].UseHit[jj]) slc.
slHits[tj.
Pts[jpt].Hits[jj]].InTraj = 0;
2480 for (
unsigned short jpt = stopPt + 1; jpt <= ipt; ++jpt) {
2481 for (
unsigned short jj = 0; jj < tj.
Pts[jpt].Hits.size(); ++jj) {
2482 if (tj.
Pts[jpt].UseHit[jj]) slc.
slHits[tj.
Pts[jpt].Hits[jj]].InTraj = tj.
ID;
2505 if (tj.
Pts.size() < 10)
return;
2506 if (tj.
Pts[tj.
EndPt[1]].AngleCode == 0)
return;
2508 unsigned short aveMult = 0;
2509 unsigned short ipt, nhalf = tj.
Pts.size() / 2;
2510 unsigned short cnt = 0;
2511 for (
auto& tp : tj.
Pts) {
2512 if (tp.Chg == 0)
continue;
2513 aveMult += tp.Hits.size();
2515 if (cnt == nhalf)
break;
2517 if (cnt == 0)
return;
2519 if (aveMult == 0) aveMult = 1;
2523 for (ipt = tj.
EndPt[1]; ipt > tj.
EndPt[0]; --ipt) {
2524 if (tj.
Pts[ipt].Chg == 0)
continue;
2525 if (tj.
Pts[ipt].Hits.size() > aveMult) {
2533 mf::LogVerbatim(
"TC") <<
"CHMEH multiplicity cut " << aveMult <<
" number of TPs masked off " 2546 unsigned int lastPt = tj.
EndPt[1];
2549 if (lastTP.
Chg == 0)
return;
2550 if (lastPt < 6)
return;
2552 unsigned short ii, ipt, cnt = 0;
2554 for (ii = 1; ii < tj.
Pts.size(); ++ii) {
2556 if (ipt > tj.
Pts.size() - 1)
break;
2557 if (tj.
Pts[ipt].Chg == 0)
continue;
2560 if (cnt == lastTP.
NTPsFit)
break;
2561 if (ipt == 0)
break;
2563 if (cnt < 3)
return;
2566 lastTP.
DeltaRMS = 1.2 * sum / (float)cnt;
2582 if (tj.
Pts.size() < 3) {
2587 unsigned short nit = 0;
2589 while (lastTP.
FitChi > maxChi && nit < 3) {
2591 unsigned short imBad = USHRT_MAX;
2592 unsigned short cnt = 0;
2593 for (
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
2594 unsigned short ipt = tj.
Pts.size() - 1 - ii;
2596 if (tp.
Chg == 0)
continue;
2597 if (tp.
Delta > maxDelta) {
2598 maxDelta = tp.
Delta;
2604 if (imBad == USHRT_MAX)
return;
2626 unsigned short lastPt = tj.
Pts.size() - 1;
2627 if (tj.
Pts[lastPt].Chg > 0)
return true;
2628 unsigned short endPt = tj.
EndPt[1];
2631 unsigned short nMasked = 0;
2632 unsigned short nOneHit = 0;
2633 unsigned short nOKChg = 0;
2634 unsigned short nOKDelta = 0;
2636 unsigned short nPosDelta = 0;
2638 unsigned short nDeltaIncreasing = 0;
2640 float prevDelta = tj.
Pts[endPt].Delta;
2641 float maxOKDelta = 10 * tj.
Pts[endPt].DeltaRMS;
2644 for (
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt)
2645 if (tj.
Pts[ipt].Chg > maxOKChg) maxOKChg = tj.
Pts[ipt].Chg;
2646 for (
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
2647 unsigned short ipt = tj.
Pts.size() - ii;
2648 auto& tp = tj.
Pts[ipt];
2649 if (tp.Chg > 0)
break;
2650 unsigned short nUnusedHits = 0;
2652 for (
unsigned short jj = 0; jj < tp.Hits.size(); ++jj) {
2653 unsigned int iht = tp.Hits[jj];
2654 if (slc.
slHits[iht].InTraj != 0)
continue;
2657 chg +=
hit.Integral();
2659 if (chg < maxOKChg) ++nOKChg;
2660 if (nUnusedHits == 1) ++nOneHit;
2661 if (tp.Delta < maxOKDelta) ++nOKDelta;
2663 if (tp.Pos[1] > tp.HitPos[1]) ++nPosDelta;
2665 if (tp.Delta < prevDelta) ++nDeltaIncreasing;
2666 prevDelta = tp.Delta;
2673 bool driftingAway = nMasked > 2 && (nPosDelta == 0 || nPosDelta == nMasked);
2675 if (driftingAway && nDeltaIncreasing < nMasked - 1) driftingAway =
false;
2678 mf::LogVerbatim(
"TC") <<
"MHOK: nMasked " << nMasked <<
" nOneHit " << nOneHit <<
" nOKChg " 2679 << nOKChg <<
" nOKDelta " << nOKDelta <<
" nPosDelta " << nPosDelta
2680 <<
" nDeltaIncreasing " << nDeltaIncreasing <<
" driftingAway? " 2684 if (!driftingAway) {
2685 if (nMasked < 8 || nOneHit < 8)
return true;
2686 if (nOKDelta != nMasked)
return true;
2687 if (nOKChg != nMasked)
return true;
2694 if (nMasked > tj.
Pts[endPt].NTPsFit)
return false;
2698 unsigned short newNTPSFit;
2700 newNTPSFit = tj.
Pts[endPt].NTPsFit / 2;
2705 for (
unsigned ipt = endPt + 1; ipt < tj.
Pts.size(); ++ipt) {
2707 for (
unsigned short ii = 0; ii < tj.
Pts[ipt].Hits.size(); ++ii) {
2708 unsigned int iht = tp.
Hits[ii];
2709 if (slc.
slHits[iht].InTraj == 0) {
2735 if (tj.
PDGCode == 13)
return false;
2737 if (tj.
Pts.size() > 40 && tj.
MCSMom > 200)
return false;
2739 unsigned short nBadFit = 0;
2740 unsigned short nHiChg = 0;
2741 unsigned short cnt = 0;
2742 for (
unsigned short ipt = tj.
Pts.size() - 1; ipt > tj.
EndPt[1]; --ipt) {
2743 if (tj.
Pts[ipt].FitChi > 2) ++nBadFit;
2744 if (tj.
Pts[ipt].ChgPull > 3) ++nHiChg;
2746 if (cnt == 5)
break;
2750 mf::LogVerbatim(
"TC") <<
"StopIfBadFits: nBadFit " << nBadFit <<
" nHiChg " << nHiChg;
2752 return nBadFit > 3 && nHiChg == 0;
2776 if (npwc < 2 * nPtsFit)
return false;
2781 unsigned short fitPt = USHRT_MAX;
2782 unsigned short cnt = 0;
2783 for (
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
2784 unsigned short ipt = tj.
EndPt[1] - ii - 1;
2787 if (ipt <= tj.
EndPt[0] + 2)
break;
2788 if (tj.
Pts[ipt].Chg <= 0)
continue;
2792 if (cnt > nPtsFit) {
2797 if (fitPt == USHRT_MAX) {
2800 myprt <<
"GKv2 fitPt not valid. Counted " << cnt <<
" points. Need " << nPtsFit;
2808 bool prevPtHasKink = (tj.
Pts[fitPt - 1].KinkSig >
tcc.
kinkCuts[1]);
2811 myprt <<
"GKv2 fitPt " << fitPt <<
" " <<
PrintPos(tj.
Pts[fitPt]);
2812 myprt << std::fixed << std::setprecision(5);
2813 myprt <<
" KinkSig " << std::setprecision(5) << tj.
Pts[fitPt].KinkSig;
2814 myprt <<
" prevPt significance " << tj.
Pts[fitPt - 1].KinkSig;
2815 if (!thisPtHasKink && !prevPtHasKink) myprt <<
" no kink";
2816 if (thisPtHasKink && !prevPtHasKink) myprt <<
" -> Start kink region";
2817 if (thisPtHasKink && prevPtHasKink) myprt <<
" -> Inside kink region";
2818 if (!thisPtHasKink && prevPtHasKink) myprt <<
" -> End kink region";
2823 if (thisPtHasKink)
return false;
2825 if (!prevPtHasKink)
return false;
2830 unsigned short kinkRegionLength = 0;
2831 unsigned short maxKinkPt = USHRT_MAX;
2832 for (
unsigned short ipt = fitPt - 1; ipt > tj.
EndPt[0]; --ipt) {
2833 auto& tp = tj.
Pts[ipt];
2834 if (tp.KinkSig < 0)
continue;
2835 if (tp.KinkSig > maxSig) {
2837 maxSig = tp.KinkSig;
2844 if (maxKinkPt == USHRT_MAX)
return false;
2847 unsigned short kinkRegionLengthMin = 1 + nPtsFit / 5;
2849 if (kinkRegionLength < kinkRegionLengthMin) {
2851 mf::LogVerbatim(
"TC") <<
"GKv2: kink region too short " << kinkRegionLength <<
" Min " 2852 << kinkRegionLengthMin;
2857 << std::setprecision(3) <<
" maxSig " << maxSig <<
" kinkRegionLength " 2858 << kinkRegionLength <<
" Min " << kinkRegionLengthMin;
2860 if (!doTrim)
return true;
2862 for (
unsigned short ipt = maxKinkPt + 1; ipt <= tj.
EndPt[1]; ++ipt)
2866 float lastChg = tj.
Pts[tj.
EndPt[1]].Chg;
2867 float prevChg = tj.
Pts[tj.
EndPt[1] - 1].Chg;
2868 float chgAsym =
std::abs(lastChg - prevChg) / (lastChg + prevChg);
2871 <<
" chgAsym " << chgAsym;
2872 if (chgAsym > 0.1) {
2895 if (tj.
Pts.size() < 3)
return;
2897 unsigned short atPt = tj.
EndPt[1];
2898 unsigned short maxPtsFit = 0;
2899 unsigned short firstGoodChgPullPt = USHRT_MAX;
2900 for (
unsigned short ipt = tj.
EndPt[0]; ipt < tj.
EndPt[1]; ++ipt) {
2901 auto& tp = tj.
Pts[ipt];
2902 if (tp.Chg == 0)
continue;
2903 if (tp.AveChg > 0 && firstGoodChgPullPt == USHRT_MAX) {
2906 if (tp.NTPsFit > maxPtsFit) {
2907 maxPtsFit = tp.NTPsFit;
2910 if (maxPtsFit > 20)
break;
2914 unsigned short firstPtFit = tj.
EndPt[0];
2915 unsigned short cnt = 0;
2916 for (
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
2917 if (ii > atPt)
break;
2918 unsigned short ipt = atPt - ii;
2919 if (tj.
Pts[ipt].Chg == 0)
continue;
2921 if (cnt == maxPtsFit) {
2927 bool needsRevProp = firstPtFit > 3;
2929 if (needsRevProp) { needsRevProp = (nPtsLeft > 5); }
2932 myprt <<
"CB: firstPtFit " << firstPtFit <<
" at " <<
PrintPos(tj.
Pts[firstPtFit].Pos);
2934 myprt <<
" nPts with charge " << nPtsLeft;
2935 myprt <<
" firstGoodChgPullPt " << firstGoodChgPullPt;
2936 if (firstGoodChgPullPt != USHRT_MAX) myprt <<
" at " <<
PrintPos(tj.
Pts[firstGoodChgPullPt]);
2937 myprt <<
" needsRevProp? " << needsRevProp;
2940 if (!needsRevProp && firstGoodChgPullPt == USHRT_MAX) {
2952 unsigned int wire = std::nearbyint(tp.
Pos[0]);
2956 mf::LogVerbatim(
"TC") <<
"CB: Previous wire " << wire <<
" is dead. Call ReversePropagate";
2957 if (!needsRevProp && firstGoodChgPullPt != USHRT_MAX) {
2963 unsigned short nused = 0;
2964 for (
auto iht : tp.
Hits)
2965 if (slc.
slHits[iht].InTraj > 0) ++nused;
2967 needsRevProp =
true;
2970 <<
" close unused hits found near EndPt[0] " <<
PrintPos(tp)
2971 <<
". Call ReversePropagate";
2979 mf::LogVerbatim(
"TC") <<
"CB: maxPtsFit " << maxPtsFit <<
" at point " << atPt
2980 <<
" firstPtFit " << firstPtFit <<
" Needs ReversePropagate? " 2989 <<
". Call TrimEndPts then ReversePropagate ";
2993 for (
unsigned short ipt = 0; ipt <= firstPtFit; ++ipt)
3006 if (firstGoodChgPullPt != USHRT_MAX && firstGoodChgPullPt > atPt) atPt = firstGoodChgPullPt;
3020 if (npwc < 6)
return;
3025 unsigned short firstPt = tj.
EndPt[0];
3027 if (atPt == tj.
EndPt[0])
return;
3030 float maxDelta = 4 * tj.
Pts[tj.
EndPt[1]].DeltaRMS;
3033 float maxDeltaRMS = 0;
3034 for (
unsigned short ipt = atPt; ipt <= tj.
EndPt[1]; ++ipt) {
3035 if (tj.
Pts[ipt].DeltaRMS > maxDeltaRMS) maxDeltaRMS = tj.
Pts[ipt].DeltaRMS;
3037 maxDelta = 3 * maxDeltaRMS;
3040 mf::LogVerbatim(
"TC") <<
"FB: atPt " << atPt <<
" firstPt " << firstPt <<
" Stops at end 0? " 3042 <<
" maxDelta " << maxDelta;
3047 bool maskedPts =
false;
3048 for (
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
3049 if (ii > atPt)
break;
3050 unsigned int ipt = atPt - ii;
3052 tp.
Dir = tj.
Pts[atPt].Dir;
3053 tp.
Ang = tj.
Pts[atPt].Ang;
3057 float dw = tp.
Pos[0] - tj.
Pts[atPt].Pos[0];
3058 if (tp.
Dir[0] != 0) tp.
Pos[1] = tj.
Pts[atPt].Pos[1] + dw * tp.
Dir[1] / tp.
Dir[0];
3060 tj.
Pts[ipt].DeltaRMS = tj.
Pts[atPt].DeltaRMS;
3061 tj.
Pts[ipt].NTPsFit = tj.
Pts[atPt].NTPsFit;
3062 tj.
Pts[ipt].FitChi = tj.
Pts[atPt].FitChi;
3063 tj.
Pts[ipt].AveChg = tj.
Pts[atPt].AveChg;
3066 bool maskThisPt = (tj.
Pts[ipt].Delta > maxDelta || badChg);
3073 myprt <<
" Point " <<
PrintPos(tj.
Pts[ipt].Pos) <<
" Delta " << tj.
Pts[ipt].Delta
3074 <<
" ChgPull " << tj.
Pts[ipt].ChgPull <<
" maskThisPt? " << maskThisPt;
3076 if (ipt == 0)
break;
3090 if (tj.
ID > 0)
return true;
3093 if (tj.
Pts.size() < 3)
return false;
3097 std::vector<int> tID;
3098 std::vector<unsigned short> tCnt;
3100 unsigned short hitCnt = 0;
3101 unsigned short nAvailable = 0;
3102 for (
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
3103 for (
unsigned short ii = 0; ii < tj.
Pts[ipt].Hits.size(); ++ii) {
3105 if (tj.
Pts[ipt].UseHit[ii]) {
3109 unsigned int iht = tj.
Pts[ipt].Hits[ii];
3110 if (slc.
slHits[iht].InTraj > 0 && (
unsigned int)slc.
slHits[iht].InTraj <= slc.
tjs.size()) {
3111 int tjid = slc.
slHits[iht].InTraj;
3112 unsigned short indx;
3113 for (indx = 0; indx < tID.size(); ++indx)
3114 if (tID[indx] == tjid)
break;
3115 if (indx == tID.size()) {
3116 tID.push_back(tjid);
3131 int oldTjID = INT_MAX;
3135 myprt <<
"IsGhost tj hits size cut " << hitCnt <<
" tID_tCnt";
3136 for (
unsigned short ii = 0; ii < tCnt.size(); ++ii)
3137 myprt <<
" " << tID[ii] <<
"_" << tCnt[ii];
3138 myprt <<
"\nAvailable hits " << nAvailable;
3141 for (
unsigned short ii = 0; ii < tCnt.size(); ++ii) {
3142 if (tCnt[ii] > hitCnt) {
3147 if (oldTjID == INT_MAX)
return false;
3148 int oldTjIndex = oldTjID - 1;
3152 if (oTj.
PDGCode == 13 && hitCnt < 0.1 * oTj.
Pts.size())
return false;
3157 int wire0 = INT_MAX;
3159 for (
auto& otp : oTj.
Pts) {
3160 int wire = std::nearbyint(otp.Pos[0]);
3161 if (wire < wire0) wire0 = wire;
3162 if (wire > wire1) wire1 = wire;
3165 int nwires = wire1 - wire0 + 1;
3166 std::vector<float> oTjPos1(nwires, -1);
3167 unsigned short nMissedWires = 0;
3168 for (
unsigned short ipt = oTj.
EndPt[0]; ipt <= oTj.
EndPt[1]; ++ipt) {
3169 if (oTj.
Pts[ipt].Chg == 0)
continue;
3170 int wire = std::nearbyint(oTj.
Pts[ipt].Pos[0]);
3171 int indx = wire - wire0;
3172 if (indx < 0 || indx > nwires - 1)
continue;
3173 oTjPos1[indx] = oTj.
Pts[ipt].Pos[1];
3177 unsigned short ngh = 0;
3179 unsigned short nghPlus = 0;
3181 unsigned short firstPtInoTj = USHRT_MAX;
3182 unsigned short lastPtInoTj = 0;
3184 for (
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
3185 if (tj.
Pts[ipt].Chg > 0) {
3189 int wire = std::nearbyint(tj.
Pts[ipt].Pos[0]);
3190 int indx = wire - wire0;
3191 if (indx < 0 || indx > nwires - 1)
continue;
3192 if (oTjPos1[indx] > 0) {
3194 bool HitInoTj =
false;
3195 for (
unsigned short ii = 0; ii < tj.
Pts[ipt].Hits.size(); ++ii) {
3196 unsigned int iht = tj.
Pts[ipt].Hits[ii];
3197 if (slc.
slHits[iht].InTraj == oldTjID) HitInoTj =
true;
3202 if (tp.
Pos[1] > oTjPos1[indx]) ++nghPlus;
3203 if (firstPtInoTj == USHRT_MAX) firstPtInoTj = ipt;
3210 mf::LogVerbatim(
"TC") <<
" Number of missed wires in oTj gaps " << nMissedWires
3211 <<
" Number of ghost hits in these gaps " << ngh <<
" nghPlus " 3212 << nghPlus <<
" cut " << 0.2 * nMissedWires;
3214 if (ngh < 0.2 * nMissedWires)
return false;
3215 if (firstPtInoTj > lastPtInoTj)
return false;
3218 if (!(nghPlus > 0.8 * ngh || nghPlus < 0.2 * ngh))
return false;
3221 mf::LogVerbatim(
"TC") <<
" Trajectory is a ghost of " << oldTjID <<
" first point in oTj " 3222 << firstPtInoTj <<
" last point " << lastPtInoTj;
3225 for (
unsigned short ipt = firstPtInoTj; ipt <= lastPtInoTj; ++ipt) {
3226 if (tj.
Pts[ipt].Chg == 0)
continue;
3232 for (
unsigned short ipt = lastPtInoTj; ipt <= tj.
EndPt[1]; ++ipt) {
3233 if (tj.
Pts[ipt].Chg > 0) ++ngh;
3237 for (
unsigned short ipt = lastPtInoTj; ipt <= tj.
EndPt[1]; ++ipt) {
3264 if (tHits.size() < 2)
return false;
3269 std::vector<unsigned int> hitsInMuliplet, nearbyHits;
3270 for (
auto iht : tHits) {
3273 for (
auto mht : hitsInMuliplet) {
3274 if (std::find(nearbyHits.begin(), nearbyHits.end(), mht) == nearbyHits.end()) {
3275 nearbyHits.push_back(mht);
3281 std::vector<unsigned int> tID, tCnt;
3282 for (
auto iht : nearbyHits) {
3283 if (slc.
slHits[iht].InTraj <= 0)
continue;
3284 unsigned int tid = slc.
slHits[iht].InTraj;
3285 unsigned short indx = 0;
3286 for (indx = 0; indx < tID.size(); ++indx)
3287 if (tID[indx] == tid)
break;
3288 if (indx == tID.size()) {
3296 if (tCnt.empty())
return false;
3299 unsigned short tCut = 0.5 * tHits.size();
3304 myprt <<
"IsGhost tHits size " << tHits.size() <<
" cut fraction " << tCut <<
" tID_tCnt";
3305 for (
unsigned short ii = 0; ii < tCnt.size(); ++ii)
3306 myprt <<
" " << tID[ii] <<
"_" << tCnt[ii];
3309 for (
unsigned short ii = 0; ii < tCnt.size(); ++ii) {
3310 if (tCnt[ii] > tCut) {
3315 if (tid > (
int)slc.
tjs.size())
return false;
3320 for (
auto& tp : slc.
tjs[tid - 1].Pts) {
3321 for (
unsigned short ii = 0; ii < tp.Hits.size(); ++ii) {
3322 unsigned int iht = tp.Hits[ii];
3323 if (slc.
slHits[iht].InTraj != 0)
continue;
3324 for (
unsigned short jj = 0; jj < tHits.size(); ++jj) {
3325 unsigned int tht = tHits[jj];
3326 if (tht != iht)
continue;
3327 tp.UseHit[ii] =
true;
3328 slc.
slHits[iht].InTraj = tid;
3343 if (slc.
tjs.size() < 2)
return;
3349 std::vector<TrajPoint> tjTP;
3350 for (
auto& tj : slc.
tjs) {
3351 if (tj.AlgMod[
kKilled])
continue;
3352 if (tj.CTP != inCTP)
continue;
3353 if (tj.Pts.size() < 10)
continue;
3354 if (tj.MCSMom < 100)
continue;
3356 if (tjtp.Chg < 0)
continue;
3357 tjTP.push_back(tjtp);
3359 if (tjTP.size() < 2)
return;
3363 myprt <<
"inside LastEndMerge slice " <<
slices.size() - 1 <<
" inCTP " << inCTP <<
" tjTPs";
3364 for (
auto& tjtp : tjTP)
3365 myprt <<
" T" << tjtp.Step;
3368 for (
unsigned short pt1 = 0;
pt1 < tjTP.size() - 1; ++
pt1) {
3369 auto& tp1 = tjTP[
pt1];
3370 auto& tj1 = slc.
tjs[tp1.Step - 1];
3371 if (tj1.AlgMod[
kKilled])
continue;
3372 for (
unsigned short pt2 =
pt1 + 1;
pt2 < tjTP.size(); ++
pt2) {
3373 auto& tp2 = tjTP[
pt2];
3374 auto& tj2 = slc.
tjs[tp2.Step - 1];
3375 if (tj2.AlgMod[
kKilled])
continue;
3378 if (prt && dang < 0.5)
3379 mf::LogVerbatim(
"TC") <<
" T" << tj1.ID <<
" T" << tj2.ID <<
" dang " << dang;
3380 if (dang > 0.2)
continue;
3382 unsigned short ipt1, ipt2;
3385 if (prt)
mf::LogVerbatim(
"TC") <<
" ip12 " << ip12 <<
" ip21 " << ip21;
3386 if (ip12 > 15 && ip21 > 15)
continue;
3389 TrajTrajDOCA(slc, tj1, tj2, ipt1, ipt2, minSep,
false);
3390 if (minSep == 100)
continue;
3391 if (ipt1 >= tj1.Pts.size() || ipt2 >= tj2.Pts.size())
continue;
3392 float dwc =
DeadWireCount(slc, tj1.Pts[ipt1], tj2.Pts[ipt2]);
3393 if (prt)
mf::LogVerbatim(
"TC") <<
" minSep " << minSep <<
" dwc " << dwc;
3395 if (minSep > 5)
continue;
3397 float sep10 =
PosSep(tj1.Pts[ipt1].Pos, tj1.Pts[tj1.EndPt[0]].Pos);
3398 float sep11 =
PosSep(tj1.Pts[ipt1].Pos, tj1.Pts[tj1.EndPt[1]].Pos);
3399 if (sep10 > 5 && sep11 > 5)
continue;
3400 unsigned short end1 = 0;
3401 if (sep11 < sep10) end1 = 1;
3402 float sep20 =
PosSep(tj2.Pts[ipt2].Pos, tj2.Pts[tj2.EndPt[0]].Pos);
3403 float sep21 =
PosSep(tj2.Pts[ipt2].Pos, tj2.Pts[tj2.EndPt[1]].Pos);
3404 if (sep20 > 5 && sep21 > 5)
continue;
3405 unsigned short end2 = 0;
3406 if (sep21 < sep20) end2 = 1;
3408 if (tj1.EndFlag[end1][
kAtKink] || tj2.EndFlag[end2][
kAtKink])
continue;
3411 myprt <<
"LEM: T" << tj1.ID <<
"_" <<
PrintPos(tp1);
3412 if (tj1.VtxID[end1] > 0) myprt <<
"->2V" << tj1.VtxID[end1];
3413 myprt <<
" T" << tj2.ID <<
"_" <<
PrintPos(tp2);
3414 if (tj2.VtxID[end2] > 0) myprt <<
"->2V" << tj2.VtxID[end2];
3415 myprt <<
" dang " << std::setprecision(2) << dang <<
" ip12 " << ip12;
3416 myprt <<
" ip21 " << ip21;
3417 myprt <<
" minSep " << minSep;
3418 myprt <<
" end sep1 " << sep10 <<
" " << sep11;
3419 myprt <<
" end sep2 " << sep20 <<
" " << sep21;
3421 if (tj1.VtxID[end1] > 0) {
3422 auto& vx2 = slc.
vtxs[tj1.VtxID[end1] - 1];
3425 if (tj2.VtxID[end2] > 0 && tj2.VtxID[end2] != tj1.VtxID[end1]) {
3426 auto& vx2 = slc.
vtxs[tj2.VtxID[end2] - 1];
3430 tj1.EndFlag[end1][
kBragg] =
false;
3431 tj2.EndFlag[end2][
kBragg] =
false;
3432 unsigned int it1 = tj1.ID - 1;
3433 unsigned int it2 = tj2.ID - 1;
3436 auto& ntj = slc.
tjs[slc.
tjs.size() - 1];
3440 if (tjtp.Chg < 0)
continue;
3441 if (prt)
mf::LogVerbatim(
"TC") <<
" added T" << ntj.ID <<
" to the merge list";
3442 tjTP.push_back(tjtp);
3466 for (
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
3467 auto& tp = tj.
Pts[ipt];
3468 if (tp.Chg <= 0)
continue;
3469 tjtp.
Pos[0] += tp.Pos[0];
3470 tjtp.
Pos[1] += tp.Pos[1];
3471 tjtp.
Dir[1] += tp.Dir[1];
3477 double arg = 1 - tjtp.
Dir[1] * tjtp.
Dir[1];
3478 if (arg < 0) arg = 0;
3479 tjtp.
Dir[0] = sqrt(arg);
3480 tjtp.
Ang = atan2(tjtp.
Dir[1], tjtp.
Dir[0]);
3490 if (slc.
tjs.size() < 2)
return;
3496 <<
" nTjs " << slc.
tjs.size() <<
" lastPass? " << lastPass;
3499 short tccStepDir = 1;
3501 for (
auto& tj : slc.
tjs) {
3502 if (tj.AlgMod[
kKilled])
continue;
3503 if (tj.CTP != inCTP)
continue;
3510 std::vector<int> tjlist(2);
3516 bool iterate =
true;
3519 for (
unsigned int it1 = 0; it1 < slc.
tjs.size(); ++it1) {
3520 auto* tj1 = &slc.
tjs[it1];
3521 if (tj1->AlgMod[
kKilled])
continue;
3522 if (tj1->CTP != inCTP)
continue;
3524 if (tj1->PDGCode == 111)
continue;
3525 for (
unsigned short end1 = 0; end1 < 2; ++end1) {
3527 if (tj1->VtxID[end1] > 0)
continue;
3529 TrajPoint tp1 = tj1->Pts[tj1->EndPt[end1]];
3531 if (lastPass && tp1.
NTPsFit > 3) {
3533 auto ttj = slc.
tjs[it1];
3534 auto& lastTP = ttj.Pts[ttj.EndPt[end1]];
3538 tp1 = ttj.Pts[ttj.EndPt[end1]];
3542 if (isVLA) bestFOM = 20;
3544 unsigned int imbest = UINT_MAX;
3545 for (
unsigned int it2 = 0; it2 < slc.
tjs.size(); ++it2) {
3546 if (it1 == it2)
continue;
3547 auto& tj2 = slc.
tjs[it2];
3549 if (tj1->StepDir != tj2.StepDir)
continue;
3550 if (tj2.AlgMod[
kKilled])
continue;
3551 if (tj2.CTP != inCTP)
continue;
3553 if (tj2.PDGCode == 111)
continue;
3555 if (olf > 0.25)
continue;
3556 unsigned short end2 = 1 - end1;
3558 if (tj2.VtxID[end2] > 0)
continue;
3559 TrajPoint& tp2 = tj2.Pts[tj2.EndPt[end2]];
3560 TrajPoint& tp2OtherEnd = tj2.Pts[tj2.EndPt[end1]];
3565 if (tj1->StepDir > 0) {
3566 if (tp2.
Pos[0] < tp1.
Pos[0] - 2)
continue;
3569 if (tp2.
Pos[0] > tp1.
Pos[0] + 2)
continue;
3579 unsigned short ipt1, ipt2;
3586 float fom = dang * doca;
3587 if (fom < bestFOM) {
3594 if (imbest == UINT_MAX)
continue;
3597 unsigned int it2 = imbest;
3598 auto* tj2 = &slc.
tjs[imbest];
3599 unsigned short end2 = 1 - end1;
3600 bool loMCSMom = (tj1->MCSMom + tj2->MCSMom) < 150;
3602 if (tj1->Pts.size() > 50 && tj1->MCSMom > 100) {
3603 if (end1 == 0) { tp1.
Ang = tj1->Pts[tj1->EndPt[0] + 2].Ang; }
3605 tp1.
Ang = tj1->Pts[tj1->EndPt[1] - 2].Ang;
3608 else if (loMCSMom) {
3612 pt1 = tj1->EndPt[0];
3616 pt2 = tj1->EndPt[1];
3623 TrajPoint tp2 = tj2->Pts[tj2->EndPt[end2]];
3624 if (tj2->Pts.size() > 50 && tj2->MCSMom > 100) {
3625 if (end1 == 0) { tp2.
Ang = tj2->Pts[tj2->EndPt[0] + 2].Ang; }
3627 tp2.
Ang = tj2->Pts[tj2->EndPt[1] - 2].Ang;
3630 else if (loMCSMom) {
3634 pt1 = tj2->EndPt[0];
3638 pt2 = tj2->EndPt[1];
3654 if (len1 < len2 && sep > 3 * len1)
continue;
3655 if (len2 < len1 && sep > 3 * len2)
continue;
3664 kinkSig =
KinkSignificance(slc, *tj1, end1, *tj2, end2, nPtsFit, useChg, prt);
3667 if (isVLA) docaCut = 15;
3683 bool doMerge = bestDOCA < docaCut && dang < dangCut;
3684 bool showerTjs = tj1->PDGCode == 11 || tj2->PDGCode == 11;
3685 bool hiMCSMom = tj1->MCSMom > 200 || tj2->MCSMom > 200;
3687 if (doMerge && !showerTjs && hiMCSMom && chgPull >
tcc.
chargeCuts[0] && !isVLA)
3690 if (!doMerge && tj1->MCSMom > 900 && tj2->MCSMom > 900 && dang < 0.1 &&
3695 if (doMerge && chgPull > 2 * chgPullCut) doMerge =
false;
3702 auto& tp1OtherEnd = tj1->Pts[tj1->EndPt[1 - end1]];
3703 auto& tp2OtherEnd = tj2->Pts[tj2->EndPt[1 - end2]];
3704 float nwires =
std::abs(tp1OtherEnd.Pos[0] - tp2OtherEnd.Pos[0]);
3705 if (nwires == 0) nwires = 1;
3706 float hitFrac = npwc / nwires;
3712 if (sep > len1) doMerge =
false;
3715 if (sep > len2) doMerge =
false;
3719 <<
" merge check sep " << sep <<
" len1 " << len1 <<
" len2 " << len2
3720 <<
" dead wire count " << dwc <<
" Merge? " << doMerge;
3725 tjlist[0] = slc.
tjs[it1].ID;
3726 tjlist[1] = slc.
tjs[it2].ID;
3728 if (doMerge && bestDOCA > 1 && chgFrac < chgFracCut) doMerge =
false;
3731 float momAsym =
std::abs(tj1->MCSMom - tj2->MCSMom) / (float)(tj1->MCSMom + tj2->MCSMom);
3732 if (doMerge && momAsym >
tcc.
vtx2DCuts[9]) doMerge =
false;
3733 if (doMerge && (tj1->EndFlag[end1][
kAtKink] || tj2->EndFlag[end2][
kAtKink])) {
3735 if (len1 < 40 && len2 < 40) doMerge =
false;
3737 if (tj1->EndFlag[end1][kAtKink] && tj2->EndFlag[1 - end2][
kBragg]) doMerge =
false;
3738 if (tj1->EndFlag[1 - end1][kBragg] && tj2->EndFlag[end2][kAtKink]) doMerge =
false;
3747 doVtx = (kinkSig > 0.5 *
tcc.
kinkCuts[1] && sep < 2);
3752 myprt <<
" EM: T" << slc.
tjs[it1].ID <<
"_" << end1 <<
" - T" << slc.
tjs[it2].ID <<
"_" 3754 myprt <<
" FOM " << std::fixed << std::setprecision(2) << bestFOM;
3755 myprt <<
" DOCA " << std::setprecision(1) << bestDOCA;
3756 myprt <<
" cut " << docaCut <<
" isVLA? " << isVLA;
3757 myprt <<
" dang " << std::setprecision(2) << dang <<
" dangCut " << dangCut;
3758 myprt <<
" chgPull " << std::setprecision(1) << chgPull <<
" Cut " << chgPullCut;
3759 myprt <<
" chgFrac " << std::setprecision(2) << chgFrac;
3760 myprt <<
" momAsym " << momAsym;
3761 myprt <<
" kinkSig " << std::setprecision(1) << kinkSig;
3762 myprt <<
" doMerge? " << doMerge;
3763 myprt <<
" doVtx? " << doVtx;
3766 if (bestDOCA > docaCut)
continue;
3770 bool didMerge =
false;
3778 tj1 = &slc.
tjs[it1];
3779 tj2 = &slc.
tjs[it2];
3782 tj1->AlgMod[
kMerge] =
true;
3783 tj2->AlgMod[
kMerge] =
true;
3793 aVtx.
CTP = slc.
tjs[it1].CTP;
3794 aVtx.
ID = slc.
vtxs.size() + 1;
3798 mf::LogVerbatim(
"TC") <<
" candidate 2V" << aVtx.
ID <<
" dang " << dang <<
" sep " 3801 bool fix2V = (
PosSep(tp1.
Pos, tp2.
Pos) < 3 || dang < 0.1);
3803 aVtx.
Pos[0] = 0.5 * (tp1.
Pos[0] + tp2.
Pos[0]);
3804 aVtx.
Pos[1] = 0.5 * (tp1.
Pos[1] + tp2.
Pos[1]);
3811 bool tj1Short = (slc.
tjs[it1].EndPt[1] - slc.
tjs[it1].EndPt[0] < maxShortTjLen);
3812 bool tj2Short = (slc.
tjs[it2].EndPt[1] - slc.
tjs[it2].EndPt[0] < maxShortTjLen);
3815 float dw = aVtx.
Pos[0] - tp1.
Pos[0];
3816 if (
std::abs(dw) > sepCut)
continue;
3817 float dt = aVtx.
Pos[1] - tp1.
Pos[1];
3818 if (
std::abs(dt) > sepCut)
continue;
3819 dw = aVtx.
Pos[0] - tp2.
Pos[0];
3820 if (
std::abs(dw) > sepCut)
continue;
3821 dt = aVtx.
Pos[1] - tp2.
Pos[1];
3822 if (
std::abs(dt) > sepCut)
continue;
3825 if (tj1Short && len1 > 4) {
3829 if (tj2Short && len2 > 4) {
3834 if (aVtx.
Pos[0] < tp1.
Pos[0] && aVtx.
Pos[0] < tp2.
Pos[0]) {
3835 aVtx.
Pos[0] = std::min(tp1.
Pos[0], tp2.
Pos[0]);
3838 if (aVtx.
Pos[0] > tp1.
Pos[0] && aVtx.
Pos[0] > tp2.
Pos[0]) {
3839 aVtx.
Pos[0] = std::max(tp1.
Pos[0], tp2.
Pos[0]);
3844 slc.
tjs[it1].VtxID[end1] = aVtx.
ID;
3845 slc.
tjs[it2].VtxID[end2] = aVtx.
ID;
3848 slc.
tjs[it1].VtxID[end1] = 0;
3849 slc.
tjs[it2].VtxID[end2] = 0;
3854 aVtx.
Pass = slc.
tjs[it1].Pass;
3855 aVtx.
Topo = end1 + end2;
3856 tj1->AlgMod[
kMerge] =
true;
3857 tj2->AlgMod[
kMerge] =
true;
3861 auto& newVx = slc.
vtxs[slc.
vtxs.size() - 1];
3863 <<
" New 2V" << newVx.ID <<
" at " << (int)newVx.Pos[0] <<
":" 3864 << (
int)(newVx.Pos[1] /
tcc.
unitsPerTick) <<
" Score " << newVx.Score;
3869 auto& newVx2 = slc.
vtxs[slc.
vtxs.size() - 1];
3873 myprt <<
" Bad vertex: Bad score? " << (newVx2.Score <
tcc.
vtx2DCuts[7]);
3877 slc.
tjs[it1].VtxID[end1] = 0;
3878 slc.
tjs[it2].VtxID[end2] = 0;
3880 bool didMerge =
false;
3888 tj1 = &slc.
tjs[it1];
3889 tj2 = &slc.
tjs[it2];
3892 tj1->AlgMod[
kMerge] =
true;
3893 tj2->AlgMod[
kMerge] =
true;
3901 if (tj1->AlgMod[
kKilled])
break;
3917 if (tj.
Pts.size() < 3) {
3918 mf::LogError(
"TC") <<
"MaskTrajEndPoints: Trajectory ID " << tj.
ID 3919 <<
" too short to mask hits ";
3922 if (nPts > tj.
Pts.size() - 2) {
3923 mf::LogError(
"TC") <<
"MaskTrajEndPoints: Trying to mask too many points " << nPts
3924 <<
" Pts.size " << tj.
Pts.size();
3929 unsigned short lastGoodPt = USHRT_MAX;
3932 mf::LogVerbatim(
"TC") <<
"MTEP: lastGoodPt " << lastGoodPt <<
" Pts size " << tj.
Pts.size()
3933 <<
" tj.IsGood " << tj.
IsGood;
3935 if (lastGoodPt == USHRT_MAX)
return;
3936 tj.
EndPt[1] = lastGoodPt;
3939 for (
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
3940 unsigned short ipt = tj.
Pts.size() - 1 - ii;
3941 if (ipt == lastGoodPt)
break;
3944 tj.
Pts[ipt].Dir = tj.
Pts[lastGoodPt].Dir;
3945 if (tj.
Pts[lastGoodPt].AngleCode == 2) {
3948 tj.
Pts[ipt].Pos[0] = tj.
Pts[lastGoodPt].Pos[0] + path * tj.
Pts[ipt].Dir[0];
3949 tj.
Pts[ipt].Pos[1] = tj.
Pts[lastGoodPt].Pos[1] + path * tj.
Pts[ipt].Dir[1];
3953 float dw = tj.
Pts[ipt].Pos[0] - tj.
Pts[lastGoodPt].Pos[0];
3955 float newpos = tj.
Pts[lastGoodPt].Pos[1] + dw * tj.
Pts[ipt].Dir[1] / tj.
Pts[ipt].Dir[0];
3958 <<
". Move Pos[1] from " << tj.
Pts[ipt].Pos[1] <<
" to " << newpos;
3959 tj.
Pts[ipt].Pos[1] =
3960 tj.
Pts[lastGoodPt].Pos[1] + dw * tj.
Pts[ipt].Dir[1] / tj.
Pts[ipt].Dir[0];
3965 <<
" Chg " << tj.
Pts[ipt].Chg;
3989 if (tj.
Pts[tj.
EndPt[0]].AngleCode == 2 || tj.
Pts[tj.
EndPt[1]].AngleCode == 2)
return;
3992 if (tj.
Pts.size() < 6)
return;
3998 <<
" points with charge slope > " <<
tcc.
chkStopCuts[0] <<
" Chg/WSEU";
4002 for (
unsigned short end = 0;
end < 2; ++
end) {
4006 if (endTP.Hits.size() > 2)
continue;
4011 unsigned short hiPt = 0;
4013 for (
unsigned short ii = 0; ii < 5; ++ii) {
4015 if (ipt < tj.
EndPt[0] || ipt > tj.
EndPt[1])
break;
4025 short dpt0 = hiPt - tj.
EndPt[0];
4026 short dpt1 = tj.
EndPt[1] - hiPt;
4027 if (
end == 0 && dpt1 <= dpt0)
continue;
4028 if (
end == 1 && dpt0 <= dpt1)
continue;
4030 mf::LogVerbatim(
"TC") <<
" end " <<
end <<
" wire0 " << wire0 <<
" Chg " << big <<
" hiPt " 4032 float prevChg = big;
4036 float chgErr, chiDOF;
4038 Fit2D(0, inPt, chgErr, outVec, outVecErr, chiDOF);
4039 unsigned short cnt = 0;
4040 for (
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
4041 short ipt = hiPt + ii *
dir;
4042 if (ipt < tj.
EndPt[0] || ipt > tj.
EndPt[1])
break;
4044 if (tp.
Chg == 0)
continue;
4046 if (tp.
Chg > 1.5 * prevChg)
continue;
4052 chgErr = 0.2 * tp.
Chg;
4053 if (!
Fit2D(2, inPt, chgErr, outVec, outVecErr, chiDOF))
break;
4055 if (cnt == nPtsToCheck)
break;
4057 if (cnt < nPtsToCheck)
continue;
4059 if (!
Fit2D(-1, inPt, chgErr, outVec, outVecErr, chiDOF))
continue;
4061 if (chiDOF > 500)
continue;
4064 outVec[1] = -outVec[1];
4066 outVec[1] > 2.5 * outVecErr[1]);
4075 << outVec[1] <<
" +/- " << outVecErr[1] <<
" stopping";
4080 << outVec[1] <<
" +/- " << outVecErr[1] <<
" Not stopping";
4096 unsigned short nmichelhits = 0;
4098 unsigned short nbragghits = 0;
4101 bool isfirsthit =
true;
4102 unsigned short braggpeak = 0;
4104 for (
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
4105 if (ii > tj.
EndPt[1])
continue;
4106 unsigned short ipt = tj.
EndPt[1] - ii;
4107 if (tj.
Pts[ipt].Chg > 0) {
4110 if (tj.
Pts[ipt].ChgPull < 0) { ++nmichelhits; }
4113 if (tj.
Pts[ipt].ChgPull < 0 && nmichelhits && !nbragghits) {
4119 lastChg = tj.
Pts[ipt].Chg;
4122 else if (tj.
Pts[ipt].Chg < lastChg) {
4124 lastChg = tj.
Pts[ipt].Chg;
4134 <<
" Bragg peak hits: " << nbragghits;
4135 if (nmichelhits > 0 && nbragghits > 2) {
4136 lastGoodPt = braggpeak;
4151 if (tHits.size() < 2)
return false;
4155 for (
unsigned short ii = 0; ii < tHits.size(); ++ii) {
4161 if (prt) std::cout <<
"MakeJunkTraj found debug hit\n";
4167 unsigned short pass =
tcc.
minPts.size() - 1;
4168 if (!
StartTraj(slc, work, tHits[0], tHits[tHits.size() - 1], pass))
return false;
4170 work.
Pts.resize(tHits.size());
4172 for (
unsigned short ii = 0; ii < tHits.size(); ++ii) {
4173 auto& tp = work.
Pts[ii];
4174 unsigned int iht = tHits[ii];
4177 if (tp.CTP != work.
CTP)
return false;
4178 tp.Hits.push_back(iht);
4179 tp.UseHit[0] =
true;
4182 tp.HitPos[0] =
hit.WireID().Wire;
4184 tp.HitPosErr2 = 100;
4185 tp.Chg =
hit.Integral();
4187 tp.NTPsFit = tHits.size();
4192 work.
EndPt[1] = tHits.size() - 1;
4195 auto& lastTP = work.
Pts.back();
4200 for (
auto& tp : work.
Pts) {
4204 sum2 += at[1] * at[1];
4208 if (tp.Step != lastTP.Step) {
4209 tp.FitChi = lastTP.FitChi;
4210 tp.Dir = lastTP.Dir;
4211 tp.Ang = lastTP.Ang;
4212 tp.Pos[0] = lastTP.Pos[0] + at[0] * lastTP.Dir[0];
4213 tp.Pos[1] = lastTP.Pos[1] + at[0] * lastTP.Dir[1];
4216 double npts = tHits.size();
4218 double arg = sum2 - npts * sum *
sum;
4219 if (arg <= 0)
return false;
4220 float rms = sqrt(arg) / (npts - 1);
4222 float transCut = sum + 3 * rms;
4223 std::vector<SortEntry> sortVec;
4227 for (
auto& tp : work.
Pts) {
4234 sortVec.push_back(se);
4238 if (sortVec.size() < 3)
return false;
4240 std::vector<TrajPoint> ntps(sortVec.size());
4241 for (
unsigned short ipt = 0; ipt < sortVec.size(); ++ipt)
4242 ntps[ipt] = work.
Pts[sortVec[ipt].index];
4244 sum = work.
TotChg / (
double)ntps.size();
4246 work.
EndPt[1] = work.
Pts.size() - 1;
void Forecast(TCSlice &slc, const Trajectory &tj)
float AveChg
Calculated using ALL hits.
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
void FitTraj(TCSlice const &slc, Trajectory &tj)
void ChkStop(Trajectory &tj)
void StepAway(TCSlice &slc, Trajectory &tj)
bool MaskedHitsOK(TCSlice &slc, Trajectory &tj)
void SetEndPoints(Trajectory &tj)
void UpdateTraj(TCSlice &slc, Trajectory &tj)
bool MakeVertexObsolete(std::string fcnLabel, TCSlice &slc, VtxStore &vx2, bool forceKill)
std::vector< float > kinkCuts
kink finder algorithm
bool IsGhost(TCSlice &slc, Trajectory &tj)
struct of temporary 2D vertices (end points)
std::vector< unsigned int > PutTrajHitsInVector(const Trajectory &tj, HitStatus_t hitRequest)
CTP_t CTP
Cryostat, TPC, Plane code.
std::vector< float > maxPos0
std::vector< unsigned short > minPtsFit
Reconstruct in several passes.
bool SignalAtTp(TrajPoint &tp)
bool FitVertex(TCSlice &slc, VtxStore &vx, bool prt)
std::vector< float > qualityCuts
Min points/wire, min consecutive pts after a gap.
void UpdateDeltaRMS(Trajectory &tj)
void SetPDGCode(TCSlice &slc, unsigned short itj)
void AddHits(TCSlice &slc, Trajectory &tj, unsigned short ipt, bool &sigOK)
vertex position fixed manually - no fitting done
Declaration of signal hit object.
void FindAlongTrans(Point3_t pos1, Vector3_t dir1, Point3_t pos2, Point2_t &alongTrans)
void PrintTrajectory(std::string someText, const TCSlice &slc, const Trajectory &tj, unsigned short tPoint)
bool StartTraj(TCSlice const &slc, Trajectory &tj, unsigned int fromhit, unsigned int tohit, unsigned short pass)
void PrintTP(std::string someText, const TCSlice &slc, unsigned short ipt, short dir, unsigned short pass, const TrajPoint &tp)
std::vector< std::vector< std::pair< unsigned int, unsigned int > > > wireHitRange
The data type to uniquely identify a Plane.
void UnsetUsedHits(TCSlice &slc, TrajPoint &tp)
std::vector< unsigned int > Hits
step from US -> DS (true) or DS -> US (false)
std::string PrintEndFlag(const PFPStruct &pfp, unsigned short end)
bool StopShort(TCSlice &slc, Trajectory &tj, bool prt)
void SetStrategy(TCSlice &slc, Trajectory &tj)
bool StoreTraj(TCSlice &slc, Trajectory &tj)
float TotChg
Total including an estimate for dead wires.
short MCSMom
Normalized RMS using ALL hits. Assume it is 50% to start.
void FillGaps(TCSlice &slc, Trajectory &tj)
float HitTimeErr(const TCSlice &slc, unsigned int iht)
constexpr auto abs(T v)
Returns the absolute value of the argument.
void ChkBegin(TCSlice &slc, Trajectory &tj)
float maxWireSkipWithSignal
max number of wires to skip with a signal on them
void FindUseHits(TCSlice &slc, Trajectory &tj, unsigned short ipt, float maxDelta, bool useChg)
void ChkChgAsymmetry(TCSlice &slc, Trajectory &tj, bool prt)
float TrajPointSeparation(const TrajPoint &tp1, const TrajPoint &tp2)
bool CompatibleMerge(const TCSlice &slc, std::vector< int > const &tjIDs, bool prt)
void SetAngleCode(TrajPoint &tp)
bool MakeJunkTraj(TCSlice &slc, std::vector< unsigned int > tHits)
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
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
bool MakeBareTrajPoint(const TCSlice &slc, unsigned int fromHit, unsigned int toHit, TrajPoint &tp)
std::vector< unsigned int > lastWire
the last wire with a hit
bool LongPulseHit(const recob::Hit &hit)
bool ChkMichel(Trajectory &tj, unsigned short &lastGoodPt)
bool IsGood
set false if there is a failure or the Tj fails quality cuts
std::string PrintPos(const TrajPoint &tp)
bool StoreVertex(TCSlice &slc, VtxStore &vx)
bool doForecast
See TCMode_t above.
void UpdateStiffEl(TCSlice const &slc, Trajectory &tj)
std::vector< float > showerTag
shower-like trajectory tagging + shower reconstruction
unsigned short Pass
the pass on which it was created
bool SignalBetween(const TrajPoint &tp1, const TrajPoint &tp2, const float MinWireSignalFraction)
int TDCtick_t
Type representing a TDC tick.
float OverlapFraction(const Trajectory &tj1, const Trajectory &tj2)
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
std::vector< unsigned short > maxAngleCode
max allowed angle code for each pass
float projectionErrFactor
float HitsRMSTime(const TCSlice &slc, const std::vector< unsigned int > &hitsInMultiplet, HitStatus_t hitRequest)
unsigned int Hit
set to the hit index in evt.allHits if a Plane:Wire:Tick match is found
void FitPar(const Trajectory &tj, unsigned short originPt, unsigned short npts, short fitDir, ParFit &pFit, unsigned short usePar)
const std::vector< std::string > StrategyBitNames
float HitsTimeErr2(const TCSlice &slc, const std::vector< unsigned int > &hitVec)
float HitsRMSTick(const TCSlice &slc, const std::vector< unsigned int > &hitsInMultiplet, HitStatus_t hitRequest)
bool dbgStp
debug stepping using debug.Cryostat, debug.TPC, etc
std::array< float, 2 > Point2_t
std::vector< float > maxPos1
float unitsPerTick
scale factor from Tick to WSE equivalent units
use the slowing-down strategy
std::vector< short > minMCSMom
Min MCSMom for each pass.
float DeadWireCount(const TCSlice &slc, const TrajPoint &tp1, const TrajPoint &tp2)
void DefineHitPos(TCSlice &slc, TrajPoint &tp)
TP is near a hit in the srcHit collection but no allHit hit exists (DUNE disambiguation error) ...
CTP_t CTP
Cryostat, TPC, Plane code.
void CheckStiffEl(TCSlice &slc, Trajectory &tj)
void GetHitMultiplet(const TCSlice &slc, unsigned int theHit, std::vector< unsigned int > &hitsInMultiplet, bool useLongPulseHits)
std::vector< float > aveHitRMS
average RMS of an isolated hit
std::vector< TrajPoint > Pts
Trajectory points.
std::vector< std::vector< bool > > goodWire
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)
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}
short StartEnd
The starting end (-1 = don't know)
double PosSep2(const Point3_t &pos1, const Point3_t &pos2)
std::string PrintHit(const TCHit &tch)
bool Fit2D(short mode, Point2_t inPt, float &inPtErr, Vector2_t &outVec, Vector2_t &outVecErr, float &chiDOF)
std::vector< unsigned short > minPts
min number of Pts required to make a trajectory
PlaneID_t Plane
Index of the plane within its TPC.
float ExpectedHitsRMS(const TrajPoint &tp)
void FixBegin(TCSlice &slc, Trajectory &tj, unsigned short atPt)
std::array< double, 2 > Vector2_t
Definition of data types for geometry description.
unsigned short NumHitsInTP(const TrajPoint &tp, HitStatus_t hitRequest)
void TrimEndPts(std::string fcnLabel, TCSlice &slc, Trajectory &tj, const std::vector< float > &fQualityCuts, bool prt)
std::vector< unsigned int > firstWire
the first wire with a hit
int ID
ID that is local to one slice.
std::vector< TCSlice > slices
std::array< unsigned short, 2 > VtxID
ID of 2D vertex.
Detector simulation of raw signals on wires.
std::bitset< 16 > modes
number of points to find AveChg
std::vector< TCHit > slHits
std::vector< float > chargeCuts
bool MergeAndStore(TCSlice &slc, unsigned int itj1, unsigned int itj2, bool doPrt)
void MaskBadTPs(TCSlice &slc, Trajectory &tj, float const &maxChi)
std::bitset< 16 > Stat
Vertex status bits using kVtxBit_t.
std::vector< TrajPoint > seeds
float maxWireSkipNoSignal
max number of wires to skip w/o a signal on them
void TrajIntersection(TrajPoint const &tp1, TrajPoint const &tp2, Point2_t &pos)
void CheckTraj(TCSlice &slc, Trajectory &tj)
double DotProd(const Vector3_t &v1, const Vector3_t &v2)
void UpdateTjChgProperties(std::string inFcnLabel, TCSlice const &slc, Trajectory &tj, bool prt)
float KinkSignificance(TCSlice const &slc, Trajectory const &tj1, unsigned short end1, Trajectory const &tj2, unsigned short end2, unsigned short nPtsFit, bool useChg, bool prt)
std::vector< TjForecast > tjfs
void AddLAHits(TCSlice &slc, Trajectory &tj, unsigned short ipt, bool &sigOK)
std::bitset< 128 > useAlg
Max hit separation for making junk trajectories. < 0 to turn off.
void CheckHiMultUnusedHits(TCSlice &slc, Trajectory &tj)
short StepDir
-1 = going US (-> small wire#), 1 = going DS (-> large wire#)
float MaxHitDelta(TCSlice &slc, Trajectory &tj)
float TrajLength(const Trajectory &tj)
std::bitset< 128 > AlgMod
Bit set if algorithm AlgBit_t modifed the trajectory.
void LastEndMerge(TCSlice &slc, CTP_t inCTP)
std::vector< short > muonTag
geo::PlaneID DecodeCTP(CTP_t CTP)
void TagJunkTj(Trajectory &tj, bool prt)
bool GottaKink(TCSlice &slc, Trajectory &tj, bool doTrim)
double PosSep(const Point3_t &pos1, const Point3_t &pos2)
void TrimHiChgEndPts(TCSlice &slc, Trajectory &tj, bool prt)
std::bitset< 128 > dbgAlg
Allow user to turn on debug printing in algorithms (that print...)
std::bitset< 8 > Environment
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)
std::vector< unsigned int > nWires
use the stiff electron strategy
std::array< std::bitset< 8 >, 2 > EndFlag
std::vector< float > chkStopCuts
Bragg peak finder configuration.
void EndMerge(TCSlice &slc, CTP_t inCTP, bool lastPass)
void SetVx2Score(TCSlice &slc)
std::vector< float > vtx2DCuts
Max position pull, max Position error rms.
std::bitset< 8 > Strategy
bool NearbySrcHit(geo::PlaneID plnID, unsigned int wire, float loTick, float hiTick)
float multHitSep
preferentially "merge" hits with < this separation
void MoveTPToWire(TrajPoint &tp, float wire)
unsigned short NumPtsWithCharge(const TCSlice &slc, const Trajectory &tj, bool includeDeadWires)
bool TrajIsClean(Trajectory const &tj, bool prt)
void MaskTrajEndPoints(TCSlice &slc, Trajectory &tj, unsigned short nPts)
void ChkStopEndPts(TCSlice &slc, Trajectory &tj, bool prt)
bool TrajTrajDOCA(const TCSlice &slc, const Trajectory &tj1, const Trajectory &tj2, unsigned short &ipt1, unsigned short &ipt2, float &minSep)
bool StopIfBadFits(Trajectory &tj)
void ReversePropagate(TCSlice &slc, Trajectory &tj)
bool NeedsUpdate
Set true when the Tj needs to be updated.
void CheckHiMultEndHits(TCSlice &slc, Trajectory &tj)
TrajPoint CreateTPFromTj(const Trajectory &tj)
float TPHitsRMSTick(const TCSlice &slc, const TrajPoint &tp, HitStatus_t hitRequest)
CTP_t CTP
set to an invalid CTP
unsigned short AngleRange(TrajPoint const &tp)
use the stiff muon strategy
bool HasDuplicateHits(const TCSlice &slc, Trajectory const &tj, bool prt)
void ReverseTraj(Trajectory &tj)