23 #include "messagefacility/MessageLogger/MessageLogger.h"
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) {
78 lastPt = tj.
Pts.size() - 1;
84 for(
unsigned short iwt = 0; iwt < 2; ++iwt) ltp.
Pos[iwt] += ltp.
Dir[iwt] * stepSize;
89 mf::LogVerbatim myprt(
"TC");
90 myprt<<
"StepAway "<<step<<
" Pos "<<tp.
Pos[0]<<
" "<<tp.
Pos[1]<<
" Dir "<<tp.
Dir[0]<<
" "<<tp.
Dir[1]<<
" stepSize "<<stepSize<<
" AngCode "<<tp.
AngleCode<<
" Strategy";
103 unsigned int wire = std::nearbyint(tp.
Pos[0]);
106 tj.
Pts.push_back(tp);
108 lastPt = tj.
Pts.size() - 1;
111 AddHits(slc, tj, lastPt, sigOK);
119 if(tj.
Pts[lastPt].AngleCode == 0 && lastPt == 2)
return;
129 if(tj.
Pts[lastPt].AngleCode > 0 && nMissedSteps > 4 && !sigOK)
break;
131 unsigned short lastPtWithHits = lastPt - 1;
134 float nMissedWires = tps *
std::abs(ltp.
Dir[0]) - dwc;
137 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" StepAway: no hits found at ltp "<<
PrintPos(slc, ltp)
138 <<
" nMissedWires "<<std::fixed<<std::setprecision(1)<<nMissedWires
139 <<
" dead wire count "<<dwc<<
" maxWireSkip "<<maxWireSkip<<
" tj.PDGCode "<<tj.
PDGCode;
140 if(nMissedWires > maxWireSkip) {
144 if(tj.
EndPt[1] < tj.
Pts.size() - 1 && tj.
Pts[tj.
EndPt[1]+1].Hits.size() == 1) {
145 unsigned short lastLonelyPoint = tj.
EndPt[1] + 1;
146 unsigned int iht = tj.
Pts[lastLonelyPoint].Hits[0];
147 if(slc.
slHits[iht].InTraj == 0 && tj.
Pts[lastLonelyPoint].Delta < 3 * tj.
Pts[lastLonelyPoint].DeltaRMS) {
149 tj.
Pts[lastLonelyPoint].UseHit[0] =
true;
153 mf::LogVerbatim(
"TC")<<
" Added a Last Lonely Hit before breaking ";
166 if(lastPt > 0 &&
PosSep2(tj.
Pts[lastPt].Pos, tj.
Pts[lastPt-1].Pos) < 0.1)
return;
173 if(tj.
Pts[lastPt].Chg == 0) {
178 float nMissedWires = tps *
std::abs(ltp.
Dir[0]) - dwc;
179 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Hits exist on the trajectory but are not used. Missed wires "<<std::nearbyint(nMissedWires)<<
" dead wire count "<<(int)dwc;
199 if(tj.
Pts.size() == 3) {
209 if(dang > 0.5) badTj =
false;
212 if(!badTj && tj.
Pts[2].Delta > 2) badTj =
true;
214 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Bad Tj found on the third point. Quit stepping.";
220 ltp.
Pos = tj.
Pts[lastPt].Pos;
221 ltp.
Dir = tj.
Pts[lastPt].Dir;
249 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" stop at kink";
255 if(tj.
Pts[lastPt].FitChi >
tcc.
maxChi && useMaxChiCut) {
274 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"End StepAway with tj size "<<tj.
Pts.size();
291 if(npwc > 10)
return false;
295 mf::LogVerbatim myprt(
"TC");
297 myprt<<
" ChiDOF "<<chgFit.
ChiDOF;
298 myprt<<
" chg0 "<<chgFit.
Par0<<
" +/- "<<chgFit.
ParErr;
304 if(chgFit.
ChiDOF < 2)
return false;
305 if(chgFit.
ParSlp > -20)
return false;
310 unsigned short lastHiPt = 0;
311 for(
unsigned short ipt = 0; ipt < tj.
Pts.size(); ++ipt) {
312 auto& tp = tj.
Pts[ipt];
313 if(tp.Chg <= 0)
continue;
319 if(cnt < 3)
return false;
321 if(prt) mf::LogVerbatim(
"TC")<<
" aveChg "<<(int)aveChg<<
" last TP AveChg "<<(
int)tj.
Pts[tj.
EndPt[1]].AveChg;
323 unsigned short firstLoPt = lastHiPt + 1;
324 for(
unsigned short ipt = lastHiPt + 1; ipt < tj.
Pts.size(); ++ipt) {
325 auto& tp = tj.
Pts[ipt];
326 if(tp.Chg <= 0 || tp.Chg > 0.5 * aveChg)
continue;
330 if(prt) mf::LogVerbatim(
"TC")<<
" stop tracking at "<<
PrintPos(slc, tj.
Pts[firstLoPt]);
343 if(
tjfs.empty())
return;
357 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"SetStrategy: Keep using the StiffMu strategy";
360 bool tkLike = (tjf.outlook < 1.5);
362 bool chgIncreasing = (tjf.chgSlope > 0);
364 bool shLike = (tjf.outlook > 2 && chgIncreasing);
365 if(!shLike) shLike = tjf.showerLikeFraction > 0.5;
367 if(tj.
MCSMom > 0) momRat = (float)tjf.MCSMom / (
float)tj.
MCSMom;
369 mf::LogVerbatim myprt(
"TC");
370 myprt<<
"SetStrategy: npwc "<<npwc<<
" outlook "<<tjf.outlook;
371 myprt<<
" tj MCSMom "<<tj.
MCSMom<<
" forecast MCSMom "<<tjf.MCSMom;
372 myprt<<
" momRat "<<std::fixed<<std::setprecision(2)<<momRat;
373 myprt<<
" tkLike? "<<tkLike<<
" shLike? "<<shLike;
374 myprt<<
" chgIncreasing? "<<chgIncreasing;
375 myprt<<
" leavesBeforeEnd? "<<tjf.leavesBeforeEnd<<
" endBraggPeak? "<<tjf.endBraggPeak;
376 myprt<<
" nextForecastUpdate "<<tjf.nextForecastUpdate;
378 if(tjf.outlook < 0)
return;
380 bool stiffMu = (tkLike && tjf.MCSMom > 600 && tjf.nextForecastUpdate > 100);
382 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"SetStrategy: High MCSMom, long forecast. Use the StiffMu strategy";
388 if(notStiff && !shLike && tj.
MCSMom < 100 && tjf.MCSMom < 100 && chgIncreasing) {
389 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"SetStrategy: Low MCSMom. Use the Slowing Tj strategy";
395 if(notStiff && !shLike && tj.
MCSMom < 200 && momRat < 0.7 && chgIncreasing) {
396 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"SetStrategy: Low MCSMom & low momRat. Use the Slowing Tj strategy";
402 if(!tjf.leavesBeforeEnd && tjf.endBraggPeak) {
403 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"SetStrategy: Found a Bragg peak. Use the Slowing Tj strategy";
409 if(tkLike && tjf.nextForecastUpdate > 100 && tjf.leavesBeforeEnd && tjf.MCSMom < 500) {
413 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"SetStrategy: Long track-like wandered out of forecast envelope. Reduce NTPsFit to "<<lastTP.NTPsFit;
417 if(tkLike && tjf.MCSMom > 600 && (tjf.foundShower || tjf.chgFitChiDOF > 20)) {
418 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"SetStrategy: high MCSMom "<<tjf.MCSMom<<
" and a shower ahead. Use the StiffEl strategy";
425 if(shLike && !tjf.leavesBeforeEnd) {
426 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"SetStrategy: Inside a shower. Use the StiffEl strategy";
445 if(tj.
Pts[tj.
EndPt[1]].AngleCode == 2)
return;
452 tjf.nextForecastUpdate = USHRT_MAX;
455 unsigned short istp = 0;
456 unsigned short nMissed = 0;
465 float minAveChg = 1E6;
466 for(
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
467 if(tj.
Pts[ipt].AveChg <= 0)
continue;
468 if(tj.
Pts[ipt].AveChg > minAveChg)
continue;
469 minAveChg = tj.
Pts[ipt].AveChg;
471 if(minAveChg <= 0 || minAveChg == 1E6)
return;
480 float forecastWin0 =
std::abs(ltp.Pos[1] - ltp.HitPos[1]);
481 if(forecastWin0 < 1) forecastWin0 = 1;
482 ltp.Pos = ltp.HitPos;
483 double stepSize =
std::abs(1/ltp.Dir[0]);
486 mf::LogVerbatim(
"TC")<<
"Forecast T"<<tj.
ID<<
" PDGCode "<<tj.
PDGCode<<
" npwc "<<npwc<<
" minAveChg "<<(int)minAveChg<<
" stepSize "<<std::setprecision(2)<<stepSize<<
" window "<<window;
487 mf::LogVerbatim(
"TC")<<
" stp ___Pos____ nTPH Chg ChgPull Delta DRMS chgWid nTkLk nShLk";
493 unsigned short maxChgPt = 0;
494 unsigned short leavesNear = USHRT_MAX;
495 bool leavesBeforeEnd =
false;
496 unsigned short showerStartNear = USHRT_MAX;
497 unsigned short showerEndNear = USHRT_MAX;
500 unsigned short trimPts = 0;
501 for(istp = 0; istp < 1000; ++istp) {
503 for(
unsigned short iwt = 0; iwt < 2; ++iwt) ltp.Pos[iwt] += ltp.Dir[iwt] * stepSize;
504 unsigned int wire = std::nearbyint(ltp.Pos[0]);
506 if(wire > slc.
lastWire[plane]-1)
break;
519 ltp.Delta =
PointTrajDOCA(slc, ltp.HitPos[0], ltp.HitPos[1], ltp);
520 ltp.DeltaRMS = ltp.Delta / window;
521 ltp.Environment.reset();
522 totHits += ltp.Hits.size();
523 if(ltp.Chg > maxChg) {
525 maxChgPt = fctj.
Pts.size();
529 ltp.ChgPull = (ltp.Chg / minAveChg - 1) / tj.
ChgRMS;
530 if((ltp.ChgPull > 3 && ltp.Hits.size() > 1) || ltp.ChgPull > 10) {
535 ltp.HitPosErr2 = 100;
540 if(fctj.
Pts.size() > 10) {
541 float shFrac = nShLike / (nShLike + nTkLike);
543 if(doPrt) mf::LogVerbatim(
"TC")<<
"Getting showerlike - break";
548 if(ltp.DeltaRMS > 0.8) {
549 leavesNear = npwc + fctj.
Pts.size();
550 if(doPrt) mf::LogVerbatim(
"TC")<<
"leaves before end - break";
551 leavesBeforeEnd =
true;
554 fctj.
Pts.push_back(ltp);
556 mf::LogVerbatim myprt(
"TC");
557 myprt<<std::setw(4)<<npwc + fctj.
Pts.size()<<
" "<<
PrintPos(slc, ltp);
558 myprt<<std::setw(5)<<ltp.Hits.size();
559 myprt<<std::setw(5)<<(int)ltp.Chg;
560 myprt<<std::fixed<<std::setprecision(1);
561 myprt<<std::setw(8)<<ltp.ChgPull;
562 myprt<<std::setw(8)<<ltp.Delta;
563 myprt<<std::setw(8)<<std::setprecision(2)<<ltp.DeltaRMS;
564 myprt<<std::setw(8)<<sqrt(ltp.HitPosErr2);
565 myprt<<std::setw(6)<<(int)nTkLike;
566 myprt<<std::setw(6)<<(int)nShLike;
573 if(doPrt) mf::LogVerbatim(
"TC")<<
"No hits found after 10 steps - break";
580 if(fctj.
Pts.size() < 3)
return;
584 fctj.
Pts.resize(fctj.
Pts.size() - trimPts);
587 for(
auto& tp : fctj.
Pts) fctj.
TotChg += tp.Chg;
593 if(maxChgPt > 0.3 * fctj.
Pts.size() && maxChg > 3 * tj.
AveChg) {
596 FitPar(slc, fctj, 0, maxChgPt, 1, chgFit, 1);
598 FitPar(slc, fctj, 0, fctj.
Pts.size(), 1, chgFit, 1);
600 tjf.chgSlope = chgFit.
ParSlp;
602 tjf.chgFitChiDOF = chgFit.
ChiDOF;
610 tjf.nextForecastUpdate = npwc + fctj.
Pts.size();
611 tjf.leavesBeforeEnd = leavesBeforeEnd;
612 tjf.foundShower =
false;
613 if(leavesNear < tjf.nextForecastUpdate) {
615 tjf.nextForecastUpdate = leavesNear;
616 }
else if(showerStartNear < tjf.nextForecastUpdate) {
618 tjf.nextForecastUpdate = showerStartNear;
619 tjf.foundShower =
true;
620 }
else if(showerEndNear < tjf.nextForecastUpdate) {
622 tjf.nextForecastUpdate = showerEndNear;
626 tjf.showerLikeFraction = (float)nShLike / (
float)fctj.
Pts.size();
629 mf::LogVerbatim myprt(
"TC");
630 myprt<<
"Forecast T"<<tj.
ID<<
" tj.AveChg "<<(int)tj.
AveChg;
632 myprt<<
" last pos "<<
PrintPos(slc, ltp);
633 myprt<<
" MCSMom "<<tjf.MCSMom;
634 myprt<<
" outlook "<<std::fixed<<std::setprecision(2)<<tjf.outlook;
635 myprt<<
" chgSlope "<<std::setprecision(1)<<tjf.chgSlope<<
" +/- "<<tjf.chgSlopeErr;
636 myprt<<
" chgRMS "<<std::setprecision(1)<<tjf.chgRMS;
637 myprt<<
" endBraggPeak "<<tjf.endBraggPeak;
638 myprt<<
" chiDOF "<<tjf.chgFitChiDOF;
639 myprt<<
" showerLike fraction "<<tjf.showerLikeFraction;
640 myprt<<
" nextForecastUpdate "<<tjf.nextForecastUpdate;
641 myprt<<
" leavesBeforeEnd? "<<tjf.leavesBeforeEnd;
642 myprt<<
" foundShower? "<<tjf.foundShower;
661 mf::LogVerbatim(
"TC")<<
"UpdateStiffEl: lastPt "<<tj.
EndPt[1]<<
" Delta "<<lastTP.
Delta<<
" AngleCode "<<lastTP.
AngleCode<<
" FitChi "<<lastTP.
FitChi<<
" NTPsFit "<<lastTP.
NTPsFit<<
" MCSMom "<<tj.
MCSMom;
676 if(tj.
EndPt[1] < 1)
return;
682 unsigned int lastPt = tj.
EndPt[1];
693 unsigned short prevPtWithHits = USHRT_MAX;
694 unsigned short firstFitPt = tj.
EndPt[0];
695 for(
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
696 unsigned short ipt = lastPt - ii;
697 if(tj.
Pts[ipt].Chg > 0) {
698 prevPtWithHits = ipt;
703 if(prevPtWithHits == USHRT_MAX)
return;
709 if(lastPt < 4) minPtsFit = 2;
715 minPtsFit = lastPt / 3;
723 short newMCSMom =
MCSMom(slc, tj);
724 short minMCSMom = 0.5 * tj.
MCSMom;
725 if(lastPt > 10 && newMCSMom < minMCSMom) {
726 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"UT: MCSMom took a nose-dive "<<newMCSMom;
737 mf::LogVerbatim(
"TC")<<
"UT: lastPt "<<lastPt<<
" lastTP.Delta "<<lastTP.
Delta<<
" previous point with hits "<<prevPtWithHits<<
" tj.Pts size "<<tj.
Pts.size()<<
" AngleCode "<<lastTP.
AngleCode<<
" PDGCode "<<tj.
PDGCode<<
" maxChi "<<maxChi<<
" minPtsFit "<<minPtsFit<<
" MCSMom "<<tj.
MCSMom;
749 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"UT: Second traj point pos "<<lastTP.
Pos[0]<<
" "<<lastTP.
Pos[1]<<
" dir "<<lastTP.
Dir[0]<<
" "<<lastTP.
Dir[1];
760 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"UT: Third traj point fit "<<lastTP.
FitChi;
769 if(lastPt > 20 && tj.
Pts[prevPtWithHits].FitChi > 1.5 && lastTP.
NTPsFit > minPtsFit) lastTP.
NTPsFit -= 2;
771 if(cleanMuon && lastPt > 200 && tj.
Pts[prevPtWithHits].FitChi > 1.0) lastTP.
NTPsFit -= 2;
779 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Return with lastTP.FitChi "<<lastTP.
FitChi<<
" Chg "<<lastTP.
Chg;
784 unsigned short cnt = 0;
785 for(
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
786 unsigned short ipt = lastPt - ii;
787 if(tj.
Pts[ipt].Chg > 0) {
791 if(cnt == lastTP.
NTPsFit)
break;
796 if(lastTP.
FitChi > 1.5 && tj.
Pts.size() > 6) {
801 if(ndead > 5 && !cleanMuon) {
810 if(prevPtWithHits != USHRT_MAX && tj.
Pts[prevPtWithHits].FitChi > 0) chirat = lastTP.
FitChi / tj.
Pts[prevPtWithHits].FitChi;
816 mf::LogVerbatim(
"TC")<<
" First fit chisq too large "<<lastTP.
FitChi<<
" prevPtWithHits chisq "<<tj.
Pts[prevPtWithHits].FitChi<<
" chirat "<<chirat<<
" NumPtsWithCharge "<<
NumPtsWithCharge(slc, tj,
false)<<
" tj.MaskedLastTP "<<tj.
MaskedLastTP;
828 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Muon - Reduce NTPsFit "<<lastPt;
831 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Muon - mask last point "<<lastPt;
835 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"UT: First fit "<<lastTP.
Pos[0]<<
" "<<lastTP.
Pos[1]<<
" dir "<<lastTP.
Dir[0]<<
" "<<lastTP.
Dir[1]<<
" FitChi "<<lastTP.
FitChi<<
" NTPsFit "<<lastTP.
NTPsFit<<
" ndead wires "<<ndead<<
" tj.MaskedLastTP "<<tj.
MaskedLastTP;
840 lastPt = tj.
EndPt[1];
848 unsigned short newNTPSFit = lastTP.
NTPsFit;
851 float prevChi = lastTP.
FitChi;
852 unsigned short ntry = 0;
855 while(lastTP.
FitChi > chiCut && lastTP.
NTPsFit > minPtsFit) {
857 newNTPSFit = 0.7 * newNTPSFit;
858 }
else if(lastTP.
NTPsFit > 4) {
863 if(lastTP.
NTPsFit < 3) newNTPSFit = 2;
864 if(newNTPSFit < minPtsFit) newNTPSFit = minPtsFit;
867 if(newNTPSFit == minPtsFit && tj.
MCSMom < 30) chiCut = 2;
868 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Bad FitChi "<<lastTP.
FitChi<<
" Reduced NTPsFit to "<<lastTP.
NTPsFit<<
" Pass "<<tj.
Pass<<
" chiCut "<<chiCut;
871 if(lastTP.
FitChi > prevChi) {
872 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Chisq is increasing "<<lastTP.
FitChi<<
" Try to remove an earlier bad hit";
878 if(lastTP.
NTPsFit == minPtsFit)
break;
883 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Last try. Drop last TP "<<lastTP.
FitChi<<
" NTPsFit "<<lastTP.
NTPsFit;
887 lastPt = tj.
EndPt[1];
903 float defFrac = 1 / (float)(tj.
EndPt[1]);
904 lastTP.
AngErr = defFrac * tj.
Pts[0].AngErr + (1 - defFrac) * lastTP.
AngErr;
920 mf::LogVerbatim(
"TC")<<
"inside CheckStiffTj with NumPtsWithCharge = "<<
NumPtsWithCharge(slc, tj,
false);
945 mf::LogVerbatim(
"TC")<<
"inside CheckTraj with NumPtsWithCharge = "<<
NumPtsWithCharge(slc, tj,
false);
978 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" HasDuplicateHits ";
985 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" CT: Ghost trajectory - trimmed hits ";
992 bool isVLA = (tj.
Pts[tj.
EndPt[1]].AngleCode == 2);
1017 if(tj.
EndPt[1] < 4)
return;
1022 float frac = npwc / npts;
1026 mf::LogVerbatim(
"TC")<<
"CheckTraj: fraction of points with charge "<<frac<<
" good traj? "<<tj.
IsGood;
1047 if(tj.
Pts.empty())
return;
1048 if(ipt > tj.
Pts.size() - 1)
return;
1051 if(tj.
Pts[ipt].AngleCode == 2) {
1057 std::vector<unsigned int> closeHits;
1058 unsigned int lastPtWithUsedHits = tj.
EndPt[1];
1061 unsigned int wire = std::nearbyint(tp.
Pos[0]);
1068 float dw = tp.
Pos[0] - tj.
Pts[lastPtWithUsedHits].Pos[0];
1069 float dt = tp.
Pos[1] - tj.
Pts[lastPtWithUsedHits].Pos[1];
1070 float dpos = sqrt(dw * dw + dt * dt);
1071 float projErr = dpos * tj.
Pts[lastPtWithUsedHits].AngErr;
1073 float deltaCut = 3 * (projErr + tp.
DeltaRMS);
1076 float minDeltaCut = 1.1 * tj.
Pts[lastPtWithUsedHits].Delta;
1077 if(deltaCut < minDeltaCut) deltaCut = minDeltaCut;
1080 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" AddHits: calculated deltaCut "<<deltaCut<<
" dw "<<dw<<
" dpos "<<dpos;
1082 if(deltaCut < 0.5) deltaCut = 0.5;
1083 if(deltaCut > 3) deltaCut = 3;
1090 if(passedDeadWires) deltaCut *= 2;
1095 float bigDelta = 2 * deltaCut;
1096 unsigned int imBig = UINT_MAX;
1097 tp.
Delta = deltaCut;
1099 float maxDeltaCut = 2 * bigDelta;
1101 if(!passedDeadWires && maxDeltaCut > 3) {
1109 mf::LogVerbatim(
"TC")<<
" AddHits: wire "<<wire<<
" tp.Pos[0] "<<tp.
Pos[0]<<
" projTick "<<rawProjTick<<
" deltaRMS "<<tp.
DeltaRMS<<
" tp.Dir[0] "<<tp.
Dir[0]<<
" deltaCut "<<deltaCut<<
" dpos "<<dpos<<
" projErr "<<projErr<<
" ExpectedHitsRMS "<<
ExpectedHitsRMS(slc, tp);
1112 std::vector<unsigned int> hitsInMultiplet;
1115 unsigned int ipl = planeID.
Plane;
1116 if(wire > slc.
lastWire[ipl])
return;
1119 if(slc.
wireHitRange[ipl][wire].first == UINT_MAX)
return;
1120 unsigned int firstHit = slc.
wireHitRange[ipl][wire].first;
1121 unsigned int lastHit = slc.
wireHitRange[ipl][wire].second;
1123 for(
unsigned int iht = firstHit; iht <= lastHit; ++iht) {
1124 if(slc.
slHits[iht].InTraj == tj.
ID)
continue;
1125 if(slc.
slHits[iht].InTraj == SHRT_MAX)
continue;
1127 if(rawProjTick >
hit.StartTick() && rawProjTick <
hit.EndTick()) sigOK =
true;
1133 if(delta > 3)
continue;
1135 if(delta > maxDeltaCut)
continue;
1139 if(
tcc.
dbgStp && delta < 100 && dt < 100) {
1140 mf::LogVerbatim myprt(
"TC");
1141 myprt<<
" iht "<<iht;
1143 myprt<<
" delta "<<std::fixed<<std::setprecision(2)<<delta<<
" deltaCut "<<deltaCut<<
" dt "<<dt;
1144 myprt<<
" BB Mult "<<hitsInMultiplet.size()<<
" RMS "<<std::setprecision(1)<<
hit.RMS();
1145 myprt<<
" Chi "<<std::setprecision(1)<<
hit.GoodnessOfFit();
1146 myprt<<
" InTraj "<<slc.
slHits[iht].InTraj;
1147 myprt<<
" Chg "<<(int)
hit.Integral();
1148 myprt<<
" Signal? "<<sigOK;
1150 if(slc.
slHits[iht].InTraj == 0 && delta < bigDelta && hitsInMultiplet.size() < 3 && !tj.
AlgMod[
kRvPrp]) {
1156 if(delta > 3)
continue;
1158 if(delta > deltaCut)
continue;
1161 if(std::find(closeHits.begin(), closeHits.end(), iht) != closeHits.end())
continue;
1162 closeHits.push_back(iht);
1163 if(hitsInMultiplet.size() > 1) {
1165 for(
auto& jht : hitsInMultiplet) {
1166 if(slc.
slHits[jht].InTraj == tj.
ID)
continue;
1167 if(std::find(closeHits.begin(), closeHits.end(), jht) != closeHits.end())
continue;
1168 closeHits.push_back(jht);
1174 mf::LogVerbatim myprt(
"TC");
1175 myprt<<
"closeHits ";
1177 if(imBig < slc.
slHits.size()) {
1180 myprt<<
" imBig "<<imBig;
1186 bool nearSrcHit =
false;
1187 if(!sigOK) nearSrcHit =
NearbySrcHit(planeID, wire, (
float)rawProjTick, (
float)rawProjTick);
1188 sigOK = sigOK || !closeHits.empty() || nearSrcHit;
1191 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" no signal on any wire at tp.Pos "<<tp.
Pos[0]<<
" "<<tp.
Pos[1]<<
" tick "<<(int)tp.
Pos[1]/
tcc.
unitsPerTick<<
" closeHits size "<<closeHits.size();
1194 if(imBig < slc.
slHits.size() && closeHits.empty()) {
1195 closeHits.push_back(imBig);
1196 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Added bigDelta hit "<<
PrintHit(slc.
slHits[imBig])<<
" w delta = "<<bigDelta;
1198 if(closeHits.size() > 16) closeHits.resize(16);
1200 tp.
Hits.insert(tp.
Hits.end(), closeHits.begin(), closeHits.end());
1220 if(ipt > tj.
Pts.size() - 1)
return;
1230 std::vector<int> wires(1);
1231 wires[0] = std::nearbyint(tp.
Pos[0]);
1232 if(wires[0] < 0 || wires[0] > (
int)slc.
lastWire[plane]-1)
return;
1235 mf::LogVerbatim(
"TC")<<
"AddLAHits called with a bad angle code. "<<tp.
AngleCode<<
" Don't do this";
1242 if(wires[0] < (
int)slc.
lastWire[plane]-1) wires.push_back(wires[0] + 1);
1243 if(wires[0] > 0) wires.push_back(wires[0] - 1);
1245 if(wires[0] > 0) wires.push_back(wires[0] - 1);
1246 if(wires[0] < (
int)slc.
lastWire[plane]-1) wires.push_back(wires[0] + 1);
1251 mf::LogVerbatim myprt(
"TC");
1252 myprt<<
" AddLAHits: Pos "<<
PrintPos(slc, tp)<<
" tp.AngleCode "<<tp.
AngleCode<<
" Wires under consideration";
1253 for(
auto& wire : wires) myprt<<
" "<<wire;
1262 std::array<int, 2> wireWindow;
1263 std::array<float, 2> timeWindow;
1265 timeWindow[0] = ltp.
Pos[1] - pos1Window;
1266 timeWindow[1] = ltp.
Pos[1] + pos1Window;
1270 for(
unsigned short ii = 0; ii < wires.size(); ++ii) {
1271 int wire = wires[ii];
1272 if(wire < 0 || wire > (
int)slc.
lastWire[plane])
continue;
1274 if(slc.
wireHitRange[plane][wire].first == UINT_MAX) sigOK =
true;
1275 if(slc.
wireHitRange[plane][wire].first == UINT_MAX)
continue;
1276 wireWindow[0] = wire;
1277 wireWindow[1] = wire;
1280 std::vector<unsigned int> closeHits =
FindCloseHits(slc, wireWindow, timeWindow, plane,
kAllHits,
true, hitsNear);
1281 if(hitsNear) sigOK =
true;
1282 for(
auto& iht : closeHits) {
1284 if(slc.
slHits[iht].InTraj == tj.
ID)
continue;
1286 if(std::find(oldHits.begin(), oldHits.end(), iht) != oldHits.end())
continue;
1287 tp.
Hits.push_back(iht);
1292 mf::LogVerbatim myprt(
"TC");
1298 if(tp.
Hits.empty())
return;
1300 if(tp.
Hits.size() > 16) tp.
Hits.resize(16);
1303 for(
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1304 unsigned int iht = tp.
Hits[ii];
1305 if(slc.
slHits[iht].InTraj != 0)
continue;
1323 if(tj.
Pts.size() < 6)
return;
1328 if(tj.
Pts[tj.
EndPt[0]].AngleCode == 2)
return;
1333 if(tj.
EndPt[0] > 0) {
1338 if(prt) mf::LogVerbatim(
"TC")<<
"ReversePropagate: Prepping Tj "<<tj.
ID<<
" incoming StepDir "<<tj.
StepDir;
1343 unsigned int wire0 = std::nearbyint(tj.
Pts[0].Pos[0]);
1344 unsigned int nextWire = wire0 - tj.
StepDir;
1348 unsigned short ipl = planeID.
Plane;
1353 if(nextWire == slc.
lastWire[ipl] - 1)
return;
1361 float maxDelta = 10 * tj.
Pts[tj.
EndPt[1]].DeltaRMS;
1363 if(prt) mf::LogVerbatim(
"TC")<<
" nUnused hits "<<tp.
Hits.size()<<
" at Pos "<<
PrintPos(slc, tp);
1364 if(tp.
Hits.empty())
return;
1368 mf::LogVerbatim myprt(
"TC");
1380 auto saveStrategy = tjWork.
Strategy;
1384 unsigned short lastPt = tjWork.
Pts.size() - 1;
1385 if(lastPt < 4)
return;
1389 for(
unsigned short ii = 0; ii < 4; ++ii) {
1390 unsigned short ipt = lastPt - ii;
1391 if(tjWork.
Pts[ipt].Chg == 0)
continue;
1392 chg += tjWork.
Pts[ipt].Chg;
1395 if(cnt == 0)
return;
1396 if(cnt > 1) tjWork.
Pts[lastPt].AveChg = chg / cnt;
1399 if(prt) mf::LogVerbatim(
"TC")<<
" ReversePropagate StepAway failed";
1415 void GetHitMultiplet(
const TCSlice& slc,
unsigned int theHit, std::vector<unsigned int>& hitsInMultiplet,
bool useLongPulseHits)
1424 hitsInMultiplet.clear();
1426 if(theHit >= slc.
slHits.size())
return;
1427 if(slc.
slHits[theHit].InTraj == INT_MAX)
return;
1434 short int hitMult =
hit.Multiplicity();
1435 unsigned int lIndex =
hit.LocalIndex();
1436 unsigned int firstHit = 0;
1437 if(lIndex < theHit) firstHit = theHit - lIndex;
1438 for(
unsigned int ii = firstHit; ii < firstHit + hitMult; ++ii) {
1439 if(ii >= slc.
slHits.size())
break;
1441 if(tmp.Multiplicity() == hitMult) hitsInMultiplet.push_back(ii);
1446 hitsInMultiplet.resize(1);
1447 hitsInMultiplet[0] = theHit;
1448 unsigned int theWire =
hit.WireID().Wire;
1449 unsigned short ipl =
hit.WireID().Plane;
1451 float theTime =
hit.PeakTime();
1452 float theRMS =
hit.RMS();
1454 bool theHitIsNarrow = (theRMS < narrowHitCut);
1455 float maxPeak =
hit.PeakAmplitude();
1456 unsigned int imTall = theHit;
1457 unsigned short nNarrow = 0;
1458 if(theHitIsNarrow) nNarrow = 1;
1461 for(
unsigned int iht = theHit - 1; iht != 0; --iht) {
1463 if(
hit.WireID().Wire != theWire)
break;
1464 if(
hit.WireID().Plane != ipl)
break;
1466 float rms =
hit.RMS();
1472 if(dTick > hitSep)
break;
1473 hitsInMultiplet.push_back(iht);
1474 if(rms < narrowHitCut) ++nNarrow;
1475 float peakAmp =
hit.PeakAmplitude();
1476 if(peakAmp > maxPeak) {
1480 theTime =
hit.PeakTime();
1486 if(hitsInMultiplet.size() > 1) std::reverse(hitsInMultiplet.begin(), hitsInMultiplet.end());
1488 theTime =
hit.PeakTime();
1490 for(
unsigned int iht = theHit + 1; iht < slc.
slHits.size(); ++iht) {
1492 if(
hit.WireID().Wire != theWire)
break;
1493 if(
hit.WireID().Plane != ipl)
break;
1494 if(slc.
slHits[iht].InTraj == INT_MAX)
continue;
1496 float rms =
hit.RMS();
1502 if(dTick > hitSep)
break;
1503 hitsInMultiplet.push_back(iht);
1504 if(rms < narrowHitCut) ++nNarrow;
1505 float peakAmp =
hit.PeakAmplitude();
1506 if(peakAmp > maxPeak) {
1510 theTime =
hit.PeakTime();
1512 if(hitsInMultiplet.size() == 1)
return;
1515 if(nNarrow == hitsInMultiplet.size())
return;
1516 if(nNarrow == 0)
return;
1518 if(theHitIsNarrow && theHit == imTall) {
1521 auto tmp = hitsInMultiplet;
1524 hitsInMultiplet = tmp;
1529 if(
hit.RMS() < narrowHitCut) {
1530 unsigned short killMe = 0;
1531 for(
unsigned short ii = 0; ii < hitsInMultiplet.size(); ++ii) {
1532 if(hitsInMultiplet[ii] == imTall) {
1537 hitsInMultiplet.erase(hitsInMultiplet.begin() + killMe);
1546 if(iht > slc.
slHits.size() - 1)
return 0;
1555 if(hitVec.empty())
return 0;
1572 unsigned short endPt = tj.
EndPt[1];
1574 if(tj.
Pts[endPt].AngleCode > 1)
return;
1576 if(tj.
Pts.size() - endPt > 10)
return;
1580 unsigned short plane = planeID.
Plane;
1583 unsigned short lastPt = tj.
Pts.size() - 1;
1584 for(lastPt = tj.
Pts.size() - 1; lastPt >= tj.
EndPt[1]; --lastPt)
if(!tj.
Pts[lastPt].Hits.empty())
break;
1585 auto& lastTP = tj.
Pts[lastPt];
1588 mf::LogVerbatim(
"TC")<<
"CSEP: checking "<<tj.
ID<<
" endPt "<<endPt<<
" Pts size "<<tj.
Pts.size()<<
" lastPt Pos "<<
PrintPos(slc, lastTP.Pos);
1592 ltp.
Pos = tj.
Pts[endPt].Pos;
1593 ltp.
Dir = tj.
Pts[endPt].Dir;
1595 std::array<int, 2> wireWindow;
1596 std::array<float, 2> timeWindow;
1597 std::vector<int> closeHits;
1598 bool isClean =
true;
1599 for(
unsigned short step = 0; step < 10; ++step) {
1600 for(
unsigned short iwt = 0; iwt < 2; ++iwt) ltp.
Pos[iwt] += ltp.
Dir[iwt] * stepSize;
1601 int wire = std::nearbyint(ltp.
Pos[0]);
1602 wireWindow[0] = wire;
1603 wireWindow[1] = wire;
1604 timeWindow[0] = ltp.
Pos[1] - 5;
1605 timeWindow[1] = ltp.
Pos[1] + 5;
1609 for(
auto iht : tmp)
if(slc.
slHits[iht].InTraj != tj.
ID) closeHits.push_back(iht);
1610 float nWiresPast = 0;
1612 if(ltp.
Dir[0] > 0) {
1614 nWiresPast = ltp.
Pos[0] - lastTP.Pos[0];
1617 nWiresPast = lastTP.Pos[0] - ltp.
Pos[0];
1619 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Found "<<tmp.size()<<
" hits near pos "<<
PrintPos(slc, ltp.
Pos)<<
" nWiresPast "<<nWiresPast;
1620 if(nWiresPast > 0.5) {
1621 if(!tmp.empty()) isClean =
false;
1622 if(nWiresPast > 1.5)
break;
1627 unsigned short nAvailable = 0;
1628 for(
auto iht : closeHits)
if(slc.
slHits[iht].InTraj == 0) ++nAvailable;
1631 mf::LogVerbatim myprt(
"TC");
1634 myprt<<
" nAvailable "<<nAvailable;
1635 myprt<<
" isClean "<<isClean;
1638 if(!isClean || nAvailable != closeHits.size())
return;
1640 unsigned short originalEndPt = tj.
EndPt[1] + 1;
1642 for(
unsigned short ipt = originalEndPt; ipt <= lastPt; ++ipt) {
1643 auto& tp = tj.
Pts[ipt];
1644 bool hitsAdded =
false;
1645 for(
unsigned short ii = 0; ii < tp.Hits.size(); ++ii) {
1647 if(slc.
slHits[tp.Hits[ii]].InTraj != 0)
continue;
1648 tp.UseHit[ii] =
true;
1649 slc.
slHits[tp.Hits[ii]].InTraj = tj.
ID;
1663 for(
unsigned short ipt = originalEndPt; ipt <= lastPt; ++ipt)
UnsetUsedHits(slc, tj.
Pts[ipt]);
1677 if(tp.
Hits.empty())
return;
1679 unsigned short nused = 0;
1680 unsigned int iht = 0;
1681 for(
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1682 if(!tp.
UseHit[ii])
continue;
1685 if(iht >= slc.
slHits.size())
return;
1688 if(nused == 0)
return;
1703 if(pathInv < 0.05) pathInv = 0.05;
1705 float wireErr = tp.
Dir[1] * 0.289;
1707 tp.
HitPosErr2 = wireErr * wireErr + timeErr * timeErr;
1714 std::vector<unsigned int> hitVec;
1716 std::array<float, 2> newpos;
1721 unsigned int loWire = INT_MAX;
1722 unsigned int hiWire = 0;
1723 for(
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1724 if(!tp.
UseHit[ii])
continue;
1725 unsigned int iht = tp.
Hits[ii];
1727 chg =
hit.Integral();
1728 unsigned int wire =
hit.WireID().Wire;
1729 if(wire < loWire) loWire = wire;
1730 if(wire > hiWire) hiWire = wire;
1731 newpos[0] += chg * wire;
1732 newpos[1] += chg *
hit.PeakTime();
1734 hitVec.push_back(iht);
1737 if(tp.
Chg == 0)
return;
1743 if(pathInv < 0.05) pathInv = 0.05;
1747 float dWire = 1 + hiWire - loWire;
1748 float wireErr = tp.
Dir[1] * dWire * 0.289;
1750 tp.
HitPosErr2 = wireErr * wireErr + timeErr2;
1762 if(ipt > tj.
Pts.size() - 1)
return;
1765 if(tp.
Hits.empty())
return;
1767 if(ipt < 5) useChg =
false;
1768 float chgPullCut = 1000;
1772 if(tj.
MCSMom < 30) chgPullCut *= 2;
1774 bool ignoreLongPulseHits =
false;
1775 unsigned short npts = tj.
EndPt[1] - tj.
EndPt[0] + 1;
1776 if(npts < 10 || tj.
AlgMod[
kRvPrp]) ignoreLongPulseHits =
true;
1779 mf::LogVerbatim(
"TC")<<
"FUH: maxDelta "<<maxDelta<<
" useChg requested "<<useChg<<
" Norm AveChg "<<(int)tp.
AveChg<<
" tj.ChgRMS "<<std::setprecision(2)<<tj.
ChgRMS<<
" chgPullCut "<<chgPullCut<<
" TPHitsRMS "<<(int)
TPHitsRMSTick(slc, tp,
kUnusedHits)<<
" ExpectedHitsRMS "<<(int)expectedHitsRMS<<
" AngCode "<<tp.
AngleCode;
1784 if(pathInv < 0.05) pathInv = 0.05;
1787 tp.
Delta = maxDelta;
1789 unsigned short imbest = USHRT_MAX;
1790 std::vector<float> deltas(tp.
Hits.size(), 100);
1792 float bestDelta = maxDelta;
1793 unsigned short nAvailable = 0;
1794 unsigned short firstAvailable = USHRT_MAX;
1795 unsigned short lastAvailable = USHRT_MAX;
1796 unsigned short firstUsed = USHRT_MAX;
1797 unsigned short imBadRecoHit = USHRT_MAX;
1798 bool bestHitLongPulse =
false;
1799 for(
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1801 unsigned int iht = tp.
Hits[ii];
1802 if(iht >= slc.
slHits.size())
continue;
1805 if(delta < bestDelta) bestDelta = delta;
1806 if(slc.
slHits[iht].InTraj > 0) {
1807 if(firstUsed == USHRT_MAX) firstUsed = ii;
1812 if(
hit.GoodnessOfFit() < 0 ||
hit.GoodnessOfFit() > 100) imBadRecoHit = ii;
1813 if(firstAvailable == USHRT_MAX) firstAvailable = ii;
1818 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" "<<ii<<
" "<<
PrintHit(slc.
slHits[iht])<<
" delta "<<delta<<
" Norm Chg "<<(int)(
hit.Integral() * pathInv);
1824 if(delta < tp.
Delta) {
1831 float chgWght = 0.5;
1833 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" firstAvailable "<<firstAvailable<<
" lastAvailable "<<lastAvailable<<
" firstUsed "<<firstUsed<<
" imbest "<<imbest<<
" single hit. tp.Delta "<<std::setprecision(2)<<tp.
Delta<<
" bestDelta "<<bestDelta<<
" path length "<<1 / pathInv<<
" imBadRecoHit "<<imBadRecoHit;
1834 if(imbest == USHRT_MAX || nAvailable == 0)
return;
1835 unsigned int bestDeltaHit = tp.
Hits[imbest];
1839 tp.
UseHit[imbest] =
true;
1840 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
1845 if(tp.
Hits.size() > 2 && nAvailable > 1 && firstUsed != USHRT_MAX && firstAvailable < firstUsed && lastAvailable > firstUsed) {
1846 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" A hit in the middle of the multiplet is used. Use only the best hit";
1847 tp.
UseHit[imbest] =
true;
1848 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
1854 std::vector<unsigned int> hitsInMultiplet;
1857 mf::LogVerbatim myprt(
"TC");
1859 myprt<<
" in multiplet:";
1860 for(
auto& iht : hitsInMultiplet) myprt<<
" "<<
PrintHit(slc.
slHits[iht]);
1864 if(imBadRecoHit != USHRT_MAX) {
1865 unsigned int iht = tp.
Hits[imBadRecoHit];
1869 tp.
UseHit[imBadRecoHit] =
true;
1875 for(
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1876 unsigned int iht = tp.
Hits[ii];
1877 if(slc.
slHits[iht].InTraj > 0)
continue;
1878 if(std::find(hitsInMultiplet.begin(), hitsInMultiplet.end(), iht) == hitsInMultiplet.end())
continue;
1889 if(!useChg || (useChg && (tj.
AveChg <= 0 || tj.
ChgRMS <= 0))) {
1891 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" tj.AveChg "<<tj.
AveChg<<
" or tj.ChgRMS "<<tj.
ChgRMS<<
". Use the best hit";
1892 tp.
UseHit[imbest] =
true;
1893 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
1898 if(tj.
PDGCode == 13 && bestDelta < 0.5) {
1899 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Tracking muon. Use the best hit";
1900 tp.
UseHit[imbest] =
true;
1901 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
1906 if(nAvailable == 1 || tp.
AngleCode == 0) {
1908 float aveChg = tp.
AveChg;
1909 if(aveChg <= 0) aveChg = tj.
AveChg;
1910 if(aveChg <= 0) aveChg =
hit.Integral();
1911 float chgRMS = tj.
ChgRMS;
1912 if(chgRMS < 0.2) chgRMS = 0.2;
1913 float bestDeltaHitChgPull =
std::abs(
hit.Integral() * pathInv / aveChg - 1) / chgRMS;
1914 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" bestDeltaHitChgPull "<<bestDeltaHitChgPull<<
" chgPullCut "<<chgPullCut;
1915 if(bestDeltaHitChgPull < chgPullCut || tp.
Delta < 0.1) {
1916 tp.
UseHit[imbest] =
true;
1917 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
1926 if(nAvailable == 2) {
1928 std::vector<unsigned int> tHits;
1932 unsigned short ombest = USHRT_MAX;
1933 unsigned int otherHit = INT_MAX;
1934 if(tHits.size() == 2) {
1935 unsigned short localIndex = 0;
1936 if(tHits[0] == bestDeltaHit) localIndex = 1;
1937 otherHit = tHits[1 - localIndex];
1939 for(
unsigned short ii = 0; ii < tp.
Hits.size(); ++ii) {
1940 if(slc.
slHits[tp.
Hits[ii]].InTraj > 0)
continue;
1941 if(tp.
Hits[ii] == otherHit) {
1948 mf::LogVerbatim(
"TC")<<
" Doublet: imbest "<<imbest<<
" ombest "<<ombest;
1951 if(ombest < tp.
Hits.size()) {
1955 float bestDeltaHitFOM = deltas[imbest] / bestHitDeltaErr;
1956 if(bestDeltaHitFOM < 0.5) bestDeltaHitFOM = 0.5;
1960 if(bestDeltaHitChgPull > 1) bestDeltaHitFOM *= chgWght * bestDeltaHitChgPull;
1962 float rmsRat =
hit.RMS() / expectedWidth;
1963 if(rmsRat < 1) rmsRat = 1 / rmsRat;
1964 bestDeltaHitFOM *= rmsRat;
1965 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" bestDeltaHit FOM "<<deltas[imbest]/bestHitDeltaErr<<
" bestDeltaHitChgPull "<<bestDeltaHitChgPull<<
" rmsRat "<<rmsRat<<
" bestDeltaHitFOM "<<bestDeltaHitFOM;
1968 float otherHitFOM = deltas[ombest] / otherHitDeltaErr;
1969 if(otherHitFOM < 0.5) otherHitFOM = 0.5;
1972 if(otherHitChgPull > 1) otherHitFOM *= chgWght * otherHitChgPull;
1973 rmsRat = ohit.RMS() / expectedWidth;
1974 if(rmsRat < 1) rmsRat = 1 / rmsRat;
1975 otherHitFOM *= rmsRat;
1976 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" otherHit FOM "<<deltas[ombest]/otherHitDeltaErr<<
" otherHitChgPull "<<otherHitChgPull<<
" rmsRat "<<rmsRat<<
" otherHitFOM "<<otherHitFOM;
1978 float doubletChg =
hit.Integral() + ohit.Integral();
1979 float doubletTime = (
hit.Integral() *
hit.PeakTime() + ohit.Integral() * ohit.PeakTime()) / doubletChg;
1980 doubletChg *= pathInv;
1984 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" doublet Chg "<<doubletChg<<
" doubletTime "<<doubletTime<<
" doubletRMSTimeErr "<<doubletRMSTimeErr;
1985 float doubletFOM =
PointTrajDOCA(slc, tp.
Pos[0], doubletTime, tp) / doubletRMSTimeErr;
1986 if(doubletFOM < 0.5) doubletFOM = 0.5;
1988 if(doubletChgPull > 1) doubletFOM *= chgWght * doubletChgPull;
1989 rmsRat = doubletWidthTick / expectedWidth;
1990 if(rmsRat < 1) rmsRat = 1 / rmsRat;
1991 doubletFOM *= rmsRat;
1992 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" doublet FOM "<<
PointTrajDOCA(slc, tp.
Pos[0], doubletTime, tp)/doubletRMSTimeErr<<
" doubletChgPull "<<doubletChgPull<<
" rmsRat "<<rmsRat<<
" doubletFOM "<<doubletFOM;
1993 if(doubletFOM < bestDeltaHitFOM && doubletFOM < otherHitFOM) {
1994 tp.
UseHit[imbest] =
true;
1995 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
1996 tp.
UseHit[ombest] =
true;
1997 slc.
slHits[otherHit].InTraj = tj.
ID;
2000 if(bestDeltaHitFOM < otherHitFOM) {
2001 tp.
UseHit[imbest] =
true;
2002 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
2004 tp.
UseHit[ombest] =
true;
2005 slc.
slHits[otherHit].InTraj = tj.
ID;
2010 tp.
UseHit[imbest] =
true;
2011 slc.
slHits[bestDeltaHit].InTraj = tj.
ID;
2018 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Multiplet: hitsWidth "<<hitsWidth<<
" expectedWidth "<<expectedWidth<<
" tick range "<<(int)minTick<<
" "<<(
int)maxTick;
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;
2024 if(
hit.PeakTime() < minTick)
continue;
2025 if(
hit.PeakTime() > maxTick)
continue;
2039 if(tj.
ChgRMS <= 0)
return;
2042 if(npwc < 8)
return;
2045 unsigned short toPt = tj.
EndPt[1] - 2;
2049 unsigned short cnt = 0;
2050 for(
unsigned short ipt = tj.
EndPt[1] - 2; ipt > tj.
EndPt[0]; --ipt) {
2051 auto& tp = tj.
Pts[ipt];
2054 for(
unsigned short ii = 0; ii < tp.Hits.size(); ++ii) {
2055 unsigned int iht = tp.Hits[ii];
2057 chg +=
hit.Integral();
2073 short firstPtWithChg = tj.
EndPt[0];
2077 short minMCSMom = 0.7 * tj.
MCSMom;
2078 while(firstPtWithChg < toPt) {
2079 short nextPtWithChg = firstPtWithChg + 1;
2081 for(nextPtWithChg = firstPtWithChg + 1; nextPtWithChg < tj.
EndPt[1]; ++nextPtWithChg) {
2082 if(tj.
Pts[nextPtWithChg].Chg > 0)
break;
2084 if(nextPtWithChg == firstPtWithChg + 1) {
2090 if(nextPtWithChg < (tj.
EndPt[1] - 1) && tj.
Pts[nextPtWithChg + 1].Chg == 0) {
2091 firstPtWithChg = nextPtWithChg;
2109 if(tj.
Pts.size() < 10) {
2112 short chgCutPt = tj.
EndPt[0] + 5;
2113 if(firstPtWithChg < chgCutPt) {
2118 chgCutPt = tj.
EndPt[1] - 5;
2119 if(chgCutPt < tj.
EndPt[0]) chgCutPt = tj.
EndPt[0];
2120 if(nextPtWithChg > chgCutPt) maxChg = 1E6;
2125 for(
unsigned short mpt = firstPtWithChg + 1; mpt < nextPtWithChg; ++mpt) {
2126 if(tj.
Pts[mpt].Chg > 0) {
2127 mf::LogVerbatim(
"TC")<<
"FillGaps coding error: firstPtWithChg "<<firstPtWithChg<<
" mpt "<<mpt<<
" nextPtWithChg "<<nextPtWithChg;
2131 bool filled =
false;
2133 for(
unsigned short ii = 0; ii < tj.
Pts[mpt].Hits.size(); ++ii) {
2134 unsigned int iht = tj.
Pts[mpt].Hits[ii];
2135 if(slc.
slHits[iht].InTraj > 0)
continue;
2138 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" FG: "<<
PrintPos(slc,tj.
Pts[mpt])<<
" hit "<<
PrintHit(slc.
slHits[iht])<<
" delta "<<delta<<
" maxDelta "<<maxDelta<<
" Chg "<<
hit.Integral()<<
" maxChg "<<maxChg;
2139 if(delta > maxDelta)
continue;
2140 tj.
Pts[mpt].UseHit[ii] =
true;
2142 chg +=
hit.Integral();
2145 if(chg > maxChg ||
MCSMom(slc, tj) < minMCSMom) {
2155 mf::LogVerbatim(
"TC")<<
"Check MCSMom "<<
MCSMom(slc, tj);
2159 firstPtWithChg = nextPtWithChg;
2177 if(tj.
Pts[tj.
EndPt[1]].AngleCode == 0)
return;
2182 unsigned short ii, stopPt;
2185 unsigned short lastMult1Pt = USHRT_MAX;
2187 unsigned short nHiMultPt = 0;
2189 unsigned short nHiMultPtHits = 0;
2191 unsigned short nHiMultPtUsedHits = 0;
2195 bool doBreak =
false;
2197 for(ii = 1; ii < tj.
Pts.size(); ++ii) {
2198 stopPt = tj.
EndPt[1] - ii;
2199 for(jj = 0; jj < tj.
Pts[stopPt].Hits.size(); ++jj) {
2200 iht = tj.
Pts[stopPt].Hits[jj];
2201 if(slc.
slHits[iht].InTraj > 0) {
2208 if(lastMult1Pt == USHRT_MAX && tj.
Pts[stopPt].Hits.size() == 1 && tj.
Pts[stopPt-1].Hits.size() == 1) lastMult1Pt = stopPt;
2209 if(tj.
Pts[stopPt].Hits.size() > 1) {
2211 nHiMultPtHits += tj.
Pts[stopPt].Hits.size();
2215 if(lastMult1Pt != USHRT_MAX)
break;
2216 if(stopPt == 1)
break;
2219 float fracHiMult = (float)nHiMultPt / (
float)ii;
2220 if(lastMult1Pt != USHRT_MAX) {
2221 float nchk = tj.
EndPt[1] - lastMult1Pt + 1;
2222 fracHiMult = (float)nHiMultPt / nchk;
2224 fracHiMult = (float)nHiMultPt / (
float)ii;
2226 float fracHitsUsed = 0;
2227 if(nHiMultPt > 0 && nHiMultPtHits > 0) fracHitsUsed = (float)nHiMultPtUsedHits / (
float)nHiMultPtHits;
2233 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"CHMUH: First InTraj stopPt "<<stopPt<<
" fracHiMult "<<fracHiMult<<
" fracHitsUsed "<<fracHitsUsed<<
" lastMult1Pt "<<lastMult1Pt<<
" sortaLargeAngle "<<sortaLargeAngle;
2234 if(fracHiMult < 0.3)
return;
2235 if(fracHitsUsed > 0.98)
return;
2240 mf::LogVerbatim(
"TC")<<
" Pts size "<<tj.
Pts.size()<<
" nHiMultPt "<<nHiMultPt<<
" nHiMultPtHits "<<nHiMultPtHits<<
" nHiMultPtUsedHits "<<nHiMultPtUsedHits<<
" sortaLargeAngle "<<sortaLargeAngle<<
" maxHitDelta "<<maxDelta;
2257 for(ipt = stopPt + 1; ipt < tj.
Pts.size(); ++ipt) {
2260 for(ii = 0; ii < tj.
Pts[ipt].Hits.size(); ++ii) {
2261 iht = tj.
Pts[ipt].Hits[ii];
2263 if(slc.
slHits[iht].InTraj != 0)
continue;
2265 if(delta > maxDelta)
continue;
2267 tj.
Pts[ipt].UseHit[ii] =
true;
2273 if(tj.
Pts[ipt].Chg == 0)
continue;
2276 if(sortaLargeAngle) tj.
Pts[ipt].NTPsFit = 2;
2279 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"UpdateTraj failed on point "<<ipt;
2281 for(
unsigned short jpt = stopPt + 1; jpt <= ipt; ++jpt) {
2282 for(
unsigned short jj = 0; jj < tj.
Pts[jpt].Hits.size(); ++jj) {
2283 if(tj.
Pts[jpt].UseHit[jj]) slc.
slHits[tj.
Pts[jpt].Hits[jj]].InTraj = 0;
2289 for(
unsigned short jpt = stopPt + 1; jpt <= ipt; ++jpt) {
2290 for(
unsigned short jj = 0; jj < tj.
Pts[jpt].Hits.size(); ++jj) {
2291 if(tj.
Pts[jpt].UseHit[jj]) slc.
slHits[tj.
Pts[jpt].Hits[jj]].InTraj = tj.
ID;
2314 if(tj.
Pts.size() < 10)
return;
2315 if(tj.
Pts[tj.
EndPt[1]].AngleCode == 0)
return;
2317 unsigned short aveMult= 0;
2318 unsigned short ipt, nhalf = tj.
Pts.size() / 2;
2319 unsigned short cnt = 0;
2320 for(
auto& tp : tj.
Pts) {
2321 if(tp.Chg == 0)
continue;
2322 aveMult += tp.Hits.size();
2324 if(cnt == nhalf)
break;
2326 if(cnt == 0)
return;
2328 if(aveMult == 0) aveMult = 1;
2332 for(ipt = tj.
EndPt[1]; ipt > tj.
EndPt[0]; --ipt) {
2333 if(tj.
Pts[ipt].Chg == 0)
continue;
2334 if(tj.
Pts[ipt].Hits.size() > aveMult) {
2341 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"CHMEH multiplicity cut "<<aveMult<<
" number of TPs masked off "<<cnt;
2353 unsigned int lastPt = tj.
EndPt[1];
2356 if(lastTP.
Chg == 0)
return;
2357 if(lastPt < 6)
return;
2359 unsigned short ii, ipt, cnt = 0;
2361 for(ii = 1; ii < tj.
Pts.size(); ++ii) {
2363 if(ipt > tj.
Pts.size() - 1)
break;
2364 if(tj.
Pts[ipt].Chg == 0)
continue;
2367 if(cnt == lastTP.
NTPsFit)
break;
2373 lastTP.
DeltaRMS = 1.2 * sum / (float)cnt;
2389 if(tj.
Pts.size() < 3) {
2394 unsigned short nit = 0;
2396 while(lastTP.
FitChi > maxChi && nit < 3) {
2398 unsigned short imBad = USHRT_MAX;
2399 unsigned short cnt = 0;
2400 for(
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
2401 unsigned short ipt = tj.
Pts.size() - 1 - ii;
2403 if(tp.
Chg == 0)
continue;
2404 if(tp.
Delta > maxDelta) {
2405 maxDelta = tp.
Delta;
2411 if(imBad == USHRT_MAX)
return;
2412 if(prt) mf::LogVerbatim(
"TC")<<
"MaskBadTPs: lastTP.FitChi "<<lastTP.
FitChi<<
" Mask point "<<imBad;
2416 if(prt) mf::LogVerbatim(
"TC")<<
" after FitTraj "<<lastTP.
FitChi;
2431 unsigned short lastPt = tj.
Pts.size() - 1;
2432 if(tj.
Pts[lastPt].Chg > 0)
return true;
2433 unsigned short endPt = tj.
EndPt[1];
2436 unsigned short nMasked = 0;
2437 unsigned short nOneHit = 0;
2438 unsigned short nOKChg = 0;
2439 unsigned short nOKDelta = 0;
2441 unsigned short nPosDelta = 0;
2443 unsigned short nDeltaIncreasing = 0;
2445 float prevDelta = tj.
Pts[endPt].Delta;
2446 float maxOKDelta = 10 * tj.
Pts[endPt].DeltaRMS;
2449 for(
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt)
if(tj.
Pts[ipt].Chg > maxOKChg) maxOKChg = tj.
Pts[ipt].Chg;
2450 for(
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
2451 unsigned short ipt = tj.
Pts.size() - ii;
2452 auto& tp = tj.
Pts[ipt];
2453 if(tp.Chg > 0)
break;
2454 unsigned short nUnusedHits = 0;
2456 for(
unsigned short jj = 0; jj < tp.Hits.size(); ++jj) {
2457 unsigned int iht = tp.Hits[jj];
2458 if(slc.
slHits[iht].InTraj != 0)
continue;
2461 chg +=
hit.Integral();
2463 if(chg < maxOKChg) ++nOKChg;
2464 if(nUnusedHits == 1) ++nOneHit;
2465 if(tp.Delta < maxOKDelta) ++nOKDelta;
2467 if(tp.Pos[1] > tp.HitPos[1]) ++nPosDelta;
2469 if(tp.Delta < prevDelta) ++nDeltaIncreasing;
2470 prevDelta = tp.Delta;
2477 bool driftingAway = nMasked > 2 && (nPosDelta == 0 || nPosDelta == nMasked);
2479 if(driftingAway && nDeltaIncreasing < nMasked - 1) driftingAway =
false;
2482 mf::LogVerbatim(
"TC")<<
"MHOK: nMasked "<<nMasked<<
" nOneHit "<<nOneHit<<
" nOKChg "<<nOKChg<<
" nOKDelta "<<nOKDelta<<
" nPosDelta "<<nPosDelta<<
" nDeltaIncreasing "<<nDeltaIncreasing<<
" driftingAway? "<<driftingAway;
2486 if(nMasked < 8 || nOneHit < 8)
return true;
2487 if(nOKDelta != nMasked)
return true;
2488 if(nOKChg != nMasked)
return true;
2495 if(nMasked > tj.
Pts[endPt].NTPsFit)
return false;
2499 unsigned short newNTPSFit;
2501 newNTPSFit = tj.
Pts[endPt].NTPsFit / 2;
2505 for(
unsigned ipt = endPt + 1; ipt < tj.
Pts.size(); ++ipt) {
2507 for(
unsigned short ii = 0; ii < tj.
Pts[ipt].Hits.size(); ++ii) {
2508 unsigned int iht = tp.
Hits[ii];
2509 if(slc.
slHits[iht].InTraj == 0) {
2535 if(tj.
PDGCode == 13)
return false;
2537 if(tj.
Pts.size() > 40 && tj.
MCSMom > 200)
return false;
2539 unsigned short nBadFit = 0;
2540 unsigned short nHiChg = 0;
2541 unsigned short cnt = 0;
2542 for(
unsigned short ipt = tj.
Pts.size() - 1; ipt > tj.
EndPt[1]; --ipt ) {
2543 if(tj.
Pts[ipt].FitChi > 2) ++nBadFit;
2544 if(tj.
Pts[ipt].ChgPull > 3) ++nHiChg;
2549 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"StopIfBadFits: nBadFit "<<nBadFit<<
" nHiChg "<<nHiChg;
2550 if(nBadFit > 3 && nHiChg == 0)
return true;
2576 if(npwc < 2 * nPtsFit)
return false;
2581 unsigned short fitPt = USHRT_MAX;
2582 unsigned short cnt = 0;
2583 for(
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
2584 unsigned short ipt = tj.
EndPt[1] - ii - 1;
2587 if(ipt <= tj.
EndPt[0] + 2)
break;
2588 if(tj.
Pts[ipt].Chg <= 0)
continue;
2597 if(fitPt == USHRT_MAX) {
2599 mf::LogVerbatim myprt(
"TC");
2600 myprt<<
"GKv2 fitPt not valid. Counted "<<cnt<<
" points. Need "<<nPtsFit;
2608 bool prevPtHasKink = (tj.
Pts[fitPt - 1].KinkSig >
tcc.
kinkCuts[1]);
2610 mf::LogVerbatim myprt(
"TC");
2611 myprt<<
"GKv2 fitPt "<<fitPt<<
" "<<
PrintPos(slc, tj.
Pts[fitPt]);
2612 myprt<<std::fixed<<std::setprecision(5);
2613 myprt<<
" KinkSig "<<std::setprecision(5)<<tj.
Pts[fitPt].KinkSig;
2614 myprt<<
" prevPt significance "<<tj.
Pts[fitPt - 1].KinkSig;
2615 if(!thisPtHasKink && !prevPtHasKink) myprt<<
" no kink";
2616 if(thisPtHasKink && !prevPtHasKink) myprt<<
" -> Start kink region";
2617 if(thisPtHasKink && prevPtHasKink) myprt<<
" -> Inside kink region";
2618 if(!thisPtHasKink && prevPtHasKink) myprt<<
" -> End kink region";
2623 if(thisPtHasKink)
return false;
2625 if(!prevPtHasKink)
return false;
2630 unsigned short kinkRegionLength = 0;
2631 unsigned short maxKinkPt = USHRT_MAX;
2632 for(
unsigned short ipt = fitPt - 1; ipt > tj.
EndPt[0]; --ipt) {
2633 auto& tp = tj.
Pts[ipt];
2634 if(tp.KinkSig < 0)
continue;
2635 if(tp.KinkSig > maxSig) {
2637 maxSig = tp.KinkSig;
2644 if(maxKinkPt == USHRT_MAX)
return false;
2647 unsigned short kinkRegionLengthMin = 1 + nPtsFit / 5;
2649 if(kinkRegionLength < kinkRegionLengthMin) {
2650 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"GKv2: kink region too short "<<kinkRegionLength<<
" Min "<<kinkRegionLengthMin;
2653 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"GKv2: kink at "<<
PrintPos(slc, tj.
Pts[maxKinkPt])<<std::setprecision(3)<<
" maxSig "<<maxSig<<
" kinkRegionLength "<<kinkRegionLength<<
" Min "<<kinkRegionLengthMin;
2655 if(!doTrim)
return true;
2660 float lastChg = tj.
Pts[tj.
EndPt[1]].Chg;
2661 float prevChg = tj.
Pts[tj.
EndPt[1] - 1].Chg;
2662 float chgAsym =
std::abs(lastChg - prevChg) / (lastChg + prevChg);
2663 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"GKv2: last point after trim "<<
PrintPos(slc, tj.
Pts[tj.
EndPt[1]])<<
" chgAsym "<<chgAsym;
2687 if(tj.
Pts.size() < 3)
return;
2689 unsigned short atPt = tj.
EndPt[1];
2690 unsigned short maxPtsFit = 0;
2691 unsigned short firstGoodChgPullPt = USHRT_MAX;
2692 for(
unsigned short ipt = tj.
EndPt[0]; ipt < tj.
EndPt[1]; ++ipt) {
2693 auto& tp = tj.
Pts[ipt];
2694 if(tp.Chg == 0)
continue;
2695 if(tp.AveChg > 0 && firstGoodChgPullPt == USHRT_MAX) {
2698 if(tp.NTPsFit > maxPtsFit) {
2699 maxPtsFit = tp.NTPsFit;
2702 if(maxPtsFit > 20)
break;
2706 unsigned short firstPtFit = tj.
EndPt[0];
2707 unsigned short cnt = 0;
2708 for(
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
2709 if(ii > atPt)
break;
2710 unsigned short ipt = atPt - ii;
2711 if(tj.
Pts[ipt].Chg == 0)
continue;
2713 if(cnt == maxPtsFit) {
2719 bool needsRevProp = firstPtFit > 3;
2722 needsRevProp = (nPtsLeft > 5);
2725 mf::LogVerbatim myprt(
"TC");
2726 myprt<<
"CB: firstPtFit "<<firstPtFit<<
" at "<<
PrintPos(slc, tj.
Pts[firstPtFit].Pos);
2728 myprt<<
" nPts with charge "<<nPtsLeft;
2729 myprt<<
" firstGoodChgPullPt "<<firstGoodChgPullPt;
2730 if(firstGoodChgPullPt != USHRT_MAX) myprt<<
" at "<<
PrintPos(slc,tj.
Pts[firstGoodChgPullPt]);
2731 myprt<<
" needsRevProp? "<<needsRevProp;
2734 if(!needsRevProp && firstGoodChgPullPt == USHRT_MAX) {
2746 unsigned int wire = std::nearbyint(tp.
Pos[0]);
2749 if(
tcc.
dbgStp && needsRevProp) mf::LogVerbatim(
"TC")<<
"CB: Previous wire "<<wire<<
" is dead. Call ReversePropagate";
2750 if(!needsRevProp && firstGoodChgPullPt != USHRT_MAX) {
2756 unsigned short nused = 0;
2757 for(
auto iht : tp.
Hits)
if(slc.
slHits[iht].InTraj > 0) ++nused;
2759 needsRevProp =
true;
2761 mf::LogVerbatim(
"TC")<<
"CB: Found "<<tp.
Hits.size()-nused<<
" close unused hits found near EndPt[0] "<<
PrintPos(slc, tp)<<
". Call ReversePropagate";
2769 mf::LogVerbatim(
"TC")<<
"CB: maxPtsFit "<<maxPtsFit<<
" at point "<<atPt<<
" firstPtFit "<<firstPtFit<<
" Needs ReversePropagate? "<<needsRevProp;
2774 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" clobber TPs "<<
PrintPos(slc, tj.
Pts[0])<<
" to "<<
PrintPos(slc, tj.
Pts[firstPtFit])<<
". Call TrimEndPts then ReversePropagate ";
2778 for(
unsigned short ipt = 0; ipt <= firstPtFit; ++ipt)
UnsetUsedHits(slc, tj.
Pts[ipt]);
2790 if(firstGoodChgPullPt != USHRT_MAX && firstGoodChgPullPt > atPt) atPt = firstGoodChgPullPt;
2804 if(npwc < 6)
return;
2809 unsigned short firstPt = tj.
EndPt[0];
2811 if(atPt == tj.
EndPt[0])
return;
2814 float maxDelta = 4 * tj.
Pts[tj.
EndPt[1]].DeltaRMS;
2817 float maxDeltaRMS = 0;
2818 for(
unsigned short ipt = atPt; ipt <= tj.
EndPt[1]; ++ipt) {
2819 if(tj.
Pts[ipt].DeltaRMS > maxDeltaRMS) maxDeltaRMS = tj.
Pts[ipt].DeltaRMS;
2821 maxDelta = 3 * maxDeltaRMS;
2824 mf::LogVerbatim(
"TC")<<
"FB: atPt "<<atPt<<
" firstPt "<<firstPt<<
" Stops at end 0? "<<
PrintEndFlag(tj, 0)<<
" start vertex "<<tj.
VtxID[0]<<
" maxDelta "<<maxDelta;
2829 bool maskedPts =
false;
2830 for(
unsigned short ii = 1; ii < tj.
Pts.size(); ++ii) {
2831 if(ii > atPt)
break;
2832 unsigned int ipt = atPt - ii;
2834 tp.
Dir = tj.
Pts[atPt].Dir;
2835 tp.
Ang = tj.
Pts[atPt].Ang;
2839 float dw = tp.
Pos[0] - tj.
Pts[atPt].Pos[0];
2840 if(tp.
Dir[0] != 0) tp.
Pos[1] = tj.
Pts[atPt].Pos[1] + dw * tp.
Dir[1] / tp.
Dir[0];
2842 tj.
Pts[ipt].DeltaRMS = tj.
Pts[atPt].DeltaRMS;
2843 tj.
Pts[ipt].NTPsFit = tj.
Pts[atPt].NTPsFit;
2844 tj.
Pts[ipt].FitChi = tj.
Pts[atPt].FitChi;
2845 tj.
Pts[ipt].AveChg = tj.
Pts[atPt].AveChg;
2848 bool maskThisPt = (tj.
Pts[ipt].Delta > maxDelta || badChg);
2854 mf::LogVerbatim myprt(
"TC");
2855 myprt<<
" Point "<<
PrintPos(slc, tj.
Pts[ipt].Pos)<<
" Delta "<<tj.
Pts[ipt].Delta<<
" ChgPull "<<tj.
Pts[ipt].ChgPull<<
" maskThisPt? "<<maskThisPt;
2871 if(tj.
ID > 0)
return true;
2874 if(tj.
Pts.size() < 3)
return false;
2878 std::vector<int> tID;
2879 std::vector<unsigned short> tCnt;
2881 unsigned short hitCnt = 0;
2882 unsigned short nAvailable = 0;
2883 for(
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
2884 for(
unsigned short ii = 0; ii < tj.
Pts[ipt].Hits.size(); ++ii) {
2886 if(tj.
Pts[ipt].UseHit[ii]) {
2890 unsigned int iht = tj.
Pts[ipt].Hits[ii];
2891 if(slc.
slHits[iht].InTraj > 0 && (
unsigned int)slc.
slHits[iht].InTraj <= slc.
tjs.size()) {
2892 int tjid = slc.
slHits[iht].InTraj;
2893 unsigned short indx;
2894 for(indx = 0; indx < tID.size(); ++indx)
if(tID[indx] == tjid)
break;
2895 if(indx == tID.size()) {
2896 tID.push_back(tjid);
2909 int oldTjID = INT_MAX;
2912 mf::LogVerbatim myprt(
"TC");
2913 myprt<<
"IsGhost tj hits size cut "<<hitCnt<<
" tID_tCnt";
2914 for(
unsigned short ii = 0; ii < tCnt.size(); ++ii) myprt<<
" "<<tID[ii]<<
"_"<<tCnt[ii];
2915 myprt<<
"\nAvailable hits "<<nAvailable;
2918 for(
unsigned short ii = 0; ii < tCnt.size(); ++ii) {
2919 if(tCnt[ii] > hitCnt) {
2924 if(oldTjID == INT_MAX)
return false;
2925 int oldTjIndex = oldTjID - 1;
2929 if(oTj.
PDGCode == 13 && hitCnt < 0.1 * oTj.
Pts.size())
return false;
2934 int wire0 = INT_MAX;
2936 for(
auto& otp : oTj.
Pts) {
2937 int wire = std::nearbyint(otp.Pos[0]);
2938 if(wire < wire0) wire0 = wire;
2939 if(wire > wire1) wire1 = wire;
2942 int nwires = wire1 - wire0 + 1;
2943 std::vector<float> oTjPos1(nwires, -1);
2944 unsigned short nMissedWires = 0;
2945 for(
unsigned short ipt = oTj.
EndPt[0]; ipt <= oTj.
EndPt[1]; ++ipt) {
2946 if(oTj.
Pts[ipt].Chg == 0)
continue;
2947 int wire = std::nearbyint(oTj.
Pts[ipt].Pos[0]);
2948 int indx = wire - wire0;
2949 if(indx < 0 || indx > nwires - 1)
continue;
2950 oTjPos1[indx] = oTj.
Pts[ipt].Pos[1];
2954 unsigned short ngh = 0;
2956 unsigned short nghPlus = 0;
2958 unsigned short firstPtInoTj = USHRT_MAX;
2959 unsigned short lastPtInoTj = 0;
2961 for(
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
2962 if(tj.
Pts[ipt].Chg > 0) {
2966 int wire = std::nearbyint(tj.
Pts[ipt].Pos[0]);
2967 int indx = wire - wire0;
2968 if(indx < 0 || indx > nwires - 1)
continue;
2969 if(oTjPos1[indx] > 0) {
2971 bool HitInoTj =
false;
2972 for(
unsigned short ii = 0; ii < tj.
Pts[ipt].Hits.size(); ++ii) {
2973 unsigned int iht = tj.
Pts[ipt].Hits[ii];
2974 if(slc.
slHits[iht].InTraj == oldTjID) HitInoTj =
true;
2979 if(tp.
Pos[1] > oTjPos1[indx]) ++nghPlus;
2980 if(firstPtInoTj == USHRT_MAX) firstPtInoTj = ipt;
2986 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Number of missed wires in oTj gaps "<<nMissedWires<<
" Number of ghost hits in these gaps "<<ngh<<
" nghPlus "<<nghPlus<<
" cut "<<0.2 * nMissedWires;
2988 if(ngh < 0.2 * nMissedWires)
return false;
2989 if(firstPtInoTj > lastPtInoTj)
return false;
2992 if(!(nghPlus > 0.8 * ngh || nghPlus < 0.2 * ngh) )
return false;
2994 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Trajectory is a ghost of "<<oldTjID<<
" first point in oTj "<<firstPtInoTj<<
" last point "<<lastPtInoTj;
2997 for(
unsigned short ipt = firstPtInoTj; ipt <= lastPtInoTj; ++ipt) {
2998 if(tj.
Pts[ipt].Chg == 0)
continue;
3004 for(
unsigned short ipt = lastPtInoTj; ipt <= tj.
EndPt[1]; ++ipt) {
3005 if(tj.
Pts[ipt].Chg > 0) ++ngh;
3009 for(
unsigned short ipt = lastPtInoTj; ipt <= tj.
EndPt[1]; ++ipt) {
3019 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" Failed quality cuts";
3023 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" New tj size "<<tj.
Pts.size();
3036 if(tHits.size() < 2)
return false;
3041 std::vector<unsigned int> hitsInMuliplet, nearbyHits;
3042 for(
auto iht : tHits) {
3045 for(
auto mht : hitsInMuliplet) {
3046 if(std::find(nearbyHits.begin(), nearbyHits.end(), mht) == nearbyHits.end()) {
3047 nearbyHits.push_back(mht);
3053 std::vector<unsigned int> tID, tCnt;
3054 for(
auto iht : nearbyHits) {
3055 if(slc.
slHits[iht].InTraj <= 0)
continue;
3056 unsigned int tid = slc.
slHits[iht].InTraj;
3057 unsigned short indx = 0;
3058 for(indx = 0; indx < tID.size(); ++indx)
if(tID[indx] == tid)
break;
3059 if(indx == tID.size()) {
3066 if(tCnt.empty())
return false;
3069 unsigned short tCut = 0.5 * tHits.size();
3073 mf::LogVerbatim myprt(
"TC");
3074 myprt<<
"IsGhost tHits size "<<tHits.size()<<
" cut fraction "<<tCut<<
" tID_tCnt";
3075 for(
unsigned short ii = 0; ii < tCnt.size(); ++ii) myprt<<
" "<<tID[ii]<<
"_"<<tCnt[ii];
3078 for(
unsigned short ii = 0; ii < tCnt.size(); ++ii) {
3079 if(tCnt[ii] > tCut) {
3084 if(tid > (
int)slc.
tjs.size())
return false;
3086 if(prt) mf::LogVerbatim(
"TC")<<
" is ghost of trajectory "<<tid;
3089 for(
auto& tp : slc.
tjs[tid - 1].Pts) {
3090 for(
unsigned short ii = 0; ii < tp.Hits.size(); ++ii) {
3091 unsigned int iht = tp.Hits[ii];
3092 if(slc.
slHits[iht].InTraj != 0)
continue;
3093 for(
unsigned short jj = 0; jj < tHits.size(); ++jj) {
3094 unsigned int tht = tHits[jj];
3095 if(tht != iht)
continue;
3096 tp.UseHit[ii] =
true;
3097 slc.
slHits[iht].InTraj = tid;
3112 if(slc.
tjs.size() < 2)
return;
3118 std::vector<TrajPoint> tjTP;
3119 for(
auto& tj : slc.
tjs) {
3120 if(tj.AlgMod[
kKilled])
continue;
3121 if(tj.CTP != inCTP)
continue;
3122 if(tj.Pts.size() < 10)
continue;
3123 if(tj.MCSMom < 100)
continue;
3125 if(tjtp.Chg < 0)
continue;
3126 tjTP.push_back(tjtp);
3128 if(tjTP.size() < 2)
return;
3131 mf::LogVerbatim myprt(
"TC");
3132 myprt<<
"inside LastEndMerge slice "<<
slices.size()-1<<
" inCTP "<<inCTP<<
" tjTPs";
3133 for(
auto& tjtp : tjTP) myprt<<
" T"<<tjtp.Step;
3136 for(
unsigned short pt1 = 0; pt1 < tjTP.size() - 1; ++pt1) {
3137 auto& tp1 = tjTP[pt1];
3138 auto& tj1 = slc.
tjs[tp1.Step - 1];
3139 if(tj1.AlgMod[
kKilled])
continue;
3140 for(
unsigned short pt2 = pt1 + 1; pt2 < tjTP.size(); ++pt2) {
3141 auto& tp2 = tjTP[pt2];
3142 auto& tj2 = slc.
tjs[tp2.Step - 1];
3143 if(tj2.AlgMod[
kKilled])
continue;
3146 if(prt && dang < 0.5) mf::LogVerbatim(
"TC")<<
" T"<<tj1.ID<<
" T"<<tj2.ID<<
" dang "<<dang;
3147 if(dang > 0.2)
continue;
3149 unsigned short ipt1, ipt2;
3150 float ip12 =
PointTrajDOCA(slc, tp1.Pos[0], tp1.Pos[1], tp2);
3151 float ip21 =
PointTrajDOCA(slc, tp2.Pos[0], tp2.Pos[1], tp1);
3152 if(prt) mf::LogVerbatim(
"TC")<<
" ip12 "<<ip12<<
" ip21 "<<ip21;
3153 if(ip12 > 15 && ip21 > 15)
continue;
3156 TrajTrajDOCA(slc, tj1, tj2, ipt1, ipt2, minSep,
false);
3157 if(minSep == 100)
continue;
3158 if(ipt1 >= tj1.Pts.size() || ipt2 >= tj2.Pts.size())
continue;
3159 float dwc =
DeadWireCount(slc, tj1.Pts[ipt1], tj2.Pts[ipt2]);
3160 if(prt) mf::LogVerbatim(
"TC")<<
" minSep "<<minSep<<
" dwc "<<dwc;
3162 if(minSep > 5)
continue;
3164 float sep10 =
PosSep(tj1.Pts[ipt1].Pos, tj1.Pts[tj1.EndPt[0]].Pos);
3165 float sep11 =
PosSep(tj1.Pts[ipt1].Pos, tj1.Pts[tj1.EndPt[1]].Pos);
3166 if(sep10 > 5 && sep11 > 5)
continue;
3167 unsigned short end1 = 0;
3168 if(sep11 < sep10) end1 = 1;
3169 float sep20 =
PosSep(tj2.Pts[ipt2].Pos, tj2.Pts[tj2.EndPt[0]].Pos);
3170 float sep21 =
PosSep(tj2.Pts[ipt2].Pos, tj2.Pts[tj2.EndPt[1]].Pos);
3171 if(sep20 > 5 && sep21 > 5)
continue;
3172 unsigned short end2 = 0;
3173 if(sep21 < sep20) end2 = 1;
3175 if(tj1.EndFlag[end1][
kAtKink] || tj2.EndFlag[end2][
kAtKink])
continue;
3177 mf::LogVerbatim myprt(
"TC");
3178 myprt<<
"LEM: T"<<tj1.ID<<
"_"<<
PrintPos(slc, tp1);
3179 if(tj1.VtxID[end1] > 0) myprt<<
"->2V"<<tj1.VtxID[end1];
3180 myprt<<
" T"<<tj2.ID<<
"_"<<
PrintPos(slc, tp2);
3181 if(tj2.VtxID[end2] > 0) myprt<<
"->2V"<<tj2.VtxID[end2];
3182 myprt<<
" dang "<<std::setprecision(2)<<dang<<
" ip12 "<<ip12;
3183 myprt<<
" ip21 "<<ip21;
3184 myprt<<
" minSep "<<minSep;
3185 myprt<<
" end sep1 "<<sep10<<
" "<<sep11;
3186 myprt<<
" end sep2 "<<sep20<<
" "<<sep21;
3188 if(tj1.VtxID[end1] > 0) {
3189 auto& vx2 = slc.
vtxs[tj1.VtxID[end1] - 1];
3192 if(tj2.VtxID[end2] > 0 && tj2.VtxID[end2] != tj1.VtxID[end1]) {
3193 auto& vx2 = slc.
vtxs[tj2.VtxID[end2] - 1];
3197 tj1.EndFlag[end1][
kBragg] =
false;
3198 tj2.EndFlag[end2][
kBragg] =
false;
3199 unsigned int it1 = tj1.ID - 1;
3200 unsigned int it2 = tj2.ID - 1;
3203 auto& ntj = slc.
tjs[slc.
tjs.size() - 1];
3207 if(tjtp.Chg < 0)
continue;
3208 if(prt) mf::LogVerbatim(
"TC")<<
" added T"<<ntj.ID<<
" to the merge list";
3209 tjTP.push_back(tjtp);
3233 for(
unsigned short ipt = tj.
EndPt[0]; ipt <= tj.
EndPt[1]; ++ipt) {
3234 auto& tp = tj.
Pts[ipt];
3235 if(tp.Chg <= 0)
continue;
3236 tjtp.
Pos[0] += tp.Pos[0];
3237 tjtp.
Pos[1] += tp.Pos[1];
3238 tjtp.
Dir[1] += tp.Dir[1];
3244 double arg = 1 - tjtp.
Dir[1] * tjtp.
Dir[1];
3245 if(arg < 0) arg = 0;
3246 tjtp.
Dir[0] = sqrt(arg);
3247 tjtp.
Ang = atan2(tjtp.
Dir[1], tjtp.
Dir[0]);
3257 if(slc.
tjs.size() < 2)
return;
3261 if(prt) mf::LogVerbatim(
"TC")<<
"inside EndMerge slice "<<
slices.size()-1<<
" inCTP "<<inCTP<<
" nTjs "<<slc.
tjs.size()<<
" lastPass? "<<lastPass;
3264 short tccStepDir = 1;
3266 for(
auto& tj : slc.
tjs) {
3267 if(tj.AlgMod[
kKilled])
continue;
3268 if(tj.CTP != inCTP)
continue;
3269 if(tj.StepDir != tccStepDir)
ReverseTraj(slc, tj);
3275 std::vector<int> tjlist(2);
3281 bool iterate =
true;
3284 for(
unsigned int it1 = 0; it1 < slc.
tjs.size(); ++it1) {
3285 auto& tj1 = slc.
tjs[it1];
3286 if(tj1.AlgMod[
kKilled])
continue;
3287 if(tj1.CTP != inCTP)
continue;
3289 if(tj1.PDGCode == 111)
continue;
3290 for(
unsigned short end1 = 0; end1 < 2; ++end1) {
3292 if(tj1.VtxID[end1] > 0)
continue;
3294 TrajPoint tp1 = tj1.Pts[tj1.EndPt[end1]];
3296 if(lastPass && tp1.
NTPsFit > 3) {
3298 auto ttj = slc.
tjs[it1];
3299 auto& lastTP = ttj.Pts[ttj.EndPt[end1]];
3303 tp1 = ttj.Pts[ttj.EndPt[end1]];
3307 if(isVLA) bestFOM = 20;
3309 unsigned int imbest = UINT_MAX;
3310 for(
unsigned int it2 = 0; it2 < slc.
tjs.size(); ++it2) {
3311 if(it1 == it2)
continue;
3312 auto& tj2 = slc.
tjs[it2];
3314 if(tj1.StepDir != tj2.StepDir)
continue;
3315 if(tj2.AlgMod[
kKilled])
continue;
3316 if(tj2.CTP != inCTP)
continue;
3318 if(tj2.PDGCode == 111)
continue;
3320 if(olf > 0.25)
continue;
3321 unsigned short end2 = 1 - end1;
3323 if(tj2.VtxID[end2] > 0)
continue;
3324 TrajPoint& tp2 = tj2.Pts[tj2.EndPt[end2]];
3325 TrajPoint& tp2OtherEnd = tj2.Pts[tj2.EndPt[end1]];
3329 if(tj1.StepDir > 0) {
3330 if(tp2.
Pos[0] < tp1.
Pos[0] - 2)
continue;
3332 if(tp2.
Pos[0] > tp1.
Pos[0] + 2)
continue;
3344 unsigned short ipt1, ipt2;
3351 float fom = dang * doca;
3359 if(imbest == UINT_MAX)
continue;
3362 unsigned int it2 = imbest;
3363 auto& tj2 = slc.
tjs[imbest];
3364 unsigned short end2 = 1 - end1;
3365 bool loMCSMom = (tj1.MCSMom + tj2.MCSMom) < 150;
3367 if(tj1.Pts.size() > 50 && tj1.MCSMom > 100) {
3369 tp1.
Ang = tj1.Pts[tj1.EndPt[0] + 2].Ang;
3371 tp1.
Ang = tj1.Pts[tj1.EndPt[1] - 2].Ang;
3373 }
else if(loMCSMom) {
3375 unsigned short pt1, pt2;
3387 TrajPoint tp2 = tj2.Pts[tj2.EndPt[end2]];
3388 if(tj2.Pts.size() > 50 && tj2.MCSMom > 100) {
3390 tp2.
Ang = tj2.Pts[tj2.EndPt[0] + 2].Ang;
3392 tp2.
Ang = tj2.Pts[tj2.EndPt[1] - 2].Ang;
3394 }
else if(loMCSMom) {
3396 unsigned short pt1, pt2;
3417 if(len1 < len2 && sep > 3 * len1)
continue;
3418 if(len2 < len1 && sep > 3 * len2)
continue;
3427 kinkSig =
KinkSignificance(slc, tj1, end1, tj2, end2, nPtsFit, useChg, prt);
3430 if(isVLA) docaCut = 15;
3447 bool doMerge = bestDOCA < docaCut && dang < dangCut;
3448 bool showerTjs = tj1.PDGCode == 11 || tj2.PDGCode == 11;
3449 bool hiMCSMom = tj1.MCSMom > 200 || tj2.MCSMom > 200;
3451 if(doMerge && !showerTjs && hiMCSMom && chgPull >
tcc.
chargeCuts[0] && !isVLA) doMerge =
false;
3453 if(!doMerge && tj1.MCSMom > 900 && tj2.MCSMom > 900 && dang < 0.1 && bestDOCA < docaCut) doMerge =
true;
3456 if(doMerge && chgPull > 2 * chgPullCut) doMerge =
false;
3463 auto& tp1OtherEnd = tj1.Pts[tj1.EndPt[1 - end1]];
3464 auto& tp2OtherEnd = tj2.Pts[tj2.EndPt[1 - end2]];
3465 float nwires =
std::abs(tp1OtherEnd.Pos[0] - tp2OtherEnd.Pos[0]);
3466 if(nwires == 0) nwires = 1;
3467 float hitFrac = npwc / nwires;
3472 if(sep > len1) doMerge =
false;
3474 if(sep > len2) doMerge =
false;
3476 if(prt) mf::LogVerbatim(
"TC")<<
" merge check sep "<<sep<<
" len1 "<<len1<<
" len2 "<<len2<<
" dead wire count "<<dwc<<
" Merge? "<<doMerge;
3481 tjlist[0] = slc.
tjs[it1].ID;
3482 tjlist[1] = slc.
tjs[it2].ID;
3484 if(doMerge && bestDOCA > 1 && chgFrac < chgFracCut) doMerge =
false;
3487 float momAsym =
std::abs(tj1.MCSMom - tj2.MCSMom) / (float)(tj1.MCSMom + tj2.MCSMom);
3488 if(doMerge && momAsym >
tcc.
vtx2DCuts[9]) doMerge =
false;
3489 if(doMerge && (tj1.EndFlag[end1][
kAtKink] || tj2.EndFlag[end2][
kAtKink])) {
3491 if(len1 < 40 && len2 < 40) doMerge =
false;
3493 if(tj1.EndFlag[end1][kAtKink] && tj2.EndFlag[1-end2][
kBragg]) doMerge =
false;
3494 if(tj1.EndFlag[1-end1][kBragg] && tj2.EndFlag[end2][kAtKink]) doMerge =
false;
3503 doVtx = (kinkSig > 0.5 *
tcc.
kinkCuts[1] && sep < 2);
3507 mf::LogVerbatim myprt(
"TC");
3508 myprt<<
" EM: T"<<slc.
tjs[it1].ID<<
"_"<<end1<<
" - T"<<slc.
tjs[it2].ID<<
"_"<<end2<<
" tp1-tp2 "<<
PrintPos(slc, tp1)<<
"-"<<
PrintPos(slc, tp2);
3509 myprt<<
" FOM "<<std::fixed<<std::setprecision(2)<<bestFOM;
3510 myprt<<
" DOCA "<<std::setprecision(1)<<bestDOCA;
3511 myprt<<
" cut "<<docaCut<<
" isVLA? "<<isVLA;
3512 myprt<<
" dang "<<std::setprecision(2)<<dang<<
" dangCut "<<dangCut;
3513 myprt<<
" chgPull "<<std::setprecision(1)<<chgPull<<
" Cut "<<chgPullCut;
3514 myprt<<
" chgFrac "<<std::setprecision(2)<<chgFrac;
3515 myprt<<
" momAsym "<<momAsym;
3516 myprt<<
" kinkSig "<<std::setprecision(1)<<kinkSig;
3517 myprt<<
" doMerge? "<<doMerge;
3518 myprt<<
" doVtx? "<<doVtx;
3521 if(bestDOCA > docaCut)
continue;
3524 if(prt) mf::LogVerbatim(
"TC")<<
" Merge ";
3525 bool didMerge =
false;
3533 tj1.AlgMod[
kMerge] =
true;
3534 tj2.AlgMod[
kMerge] =
true;
3538 if(prt) mf::LogVerbatim(
"TC")<<
" MergeAndStore failed ";
3543 aVtx.
CTP = slc.
tjs[it1].CTP;
3544 aVtx.
ID = slc.
vtxs.size() + 1;
3548 mf::LogVerbatim(
"TC")<<
" candidate 2V"<<aVtx.
ID<<
" dang "<<dang<<
" sep "<<
PosSep(tp1.
Pos, tp2.
Pos);
3550 bool fix2V = (
PosSep(tp1.
Pos, tp2.
Pos) < 3 || dang < 0.1);
3552 aVtx.
Pos[0] = 0.5 * (tp1.
Pos[0] + tp2.
Pos[0]);
3553 aVtx.
Pos[1] = 0.5 * (tp1.
Pos[1] + tp2.
Pos[1]);
3559 bool tj1Short = (slc.
tjs[it1].EndPt[1] - slc.
tjs[it1].EndPt[0] < maxShortTjLen);
3560 bool tj2Short = (slc.
tjs[it2].EndPt[1] - slc.
tjs[it2].EndPt[0] < maxShortTjLen);
3563 float dw = aVtx.
Pos[0] - tp1.
Pos[0];
3564 if(
std::abs(dw) > sepCut)
continue;
3565 float dt = aVtx.
Pos[1] - tp1.
Pos[1];
3566 if(
std::abs(dt) > sepCut)
continue;
3567 dw = aVtx.
Pos[0] - tp2.
Pos[0];
3568 if(
std::abs(dw) > sepCut)
continue;
3569 dt = aVtx.
Pos[1] - tp2.
Pos[1];
3570 if(
std::abs(dt) > sepCut)
continue;
3573 if(tj1Short && len1 > 4) {
3577 if(tj2Short && len2 > 4) {
3582 if(aVtx.
Pos[0] < tp1.
Pos[0] && aVtx.
Pos[0] < tp2.
Pos[0]) {
3583 aVtx.
Pos[0] = std::min(tp1.
Pos[0], tp2.
Pos[0]);
3586 if(aVtx.
Pos[0] > tp1.
Pos[0] && aVtx.
Pos[0] > tp2.
Pos[0]) {
3587 aVtx.
Pos[0] = std::max(tp1.
Pos[0], tp2.
Pos[0]);
3592 slc.
tjs[it1].VtxID[end1] = aVtx.
ID;
3593 slc.
tjs[it2].VtxID[end2] = aVtx.
ID;
3596 slc.
tjs[it1].VtxID[end1] = 0;
3597 slc.
tjs[it2].VtxID[end2] = 0;
3598 if(prt) mf::LogVerbatim(
"TC")<<
" Vertex fit failed ";
3602 aVtx.
Pass = slc.
tjs[it1].Pass;
3603 aVtx.
Topo = end1 + end2;
3604 tj1.AlgMod[
kMerge] =
true;
3605 tj2.AlgMod[
kMerge] =
true;
3609 auto& newVx = slc.
vtxs[slc.
vtxs.size() - 1];
3610 mf::LogVerbatim(
"TC")<<
" New 2V"<<newVx.ID<<
" at "<<(int)newVx.Pos[0]<<
":"<<(
int)(newVx.Pos[1]/
tcc.
unitsPerTick)<<
" Score "<<newVx.Score;
3615 auto& newVx2 = slc.
vtxs[slc.
vtxs.size() - 1];
3618 mf::LogVerbatim myprt(
"TC");
3619 myprt<<
" Bad vertex: Bad score? "<<(newVx2.Score <
tcc.
vtx2DCuts[7]);
3623 slc.
tjs[it1].VtxID[end1] = 0;
3624 slc.
tjs[it2].VtxID[end2] = 0;
3626 bool didMerge =
false;
3634 tj1.AlgMod[
kMerge] =
true;
3635 tj1.AlgMod[
kMerge] =
true;
3639 if(prt) mf::LogVerbatim(
"TC")<<
" MergeAndStore failed ";
3643 if(tj1.AlgMod[
kKilled])
break;
3659 if(tj.
Pts.size() < 3) {
3660 mf::LogError(
"TC")<<
"MaskTrajEndPoints: Trajectory ID "<<tj.
ID<<
" too short to mask hits ";
3663 if(nPts > tj.
Pts.size() - 2) {
3664 mf::LogError(
"TC")<<
"MaskTrajEndPoints: Trying to mask too many points "<<nPts<<
" Pts.size "<<tj.
Pts.size();
3669 unsigned short lastGoodPt = USHRT_MAX ;
3672 mf::LogVerbatim(
"TC")<<
"MTEP: lastGoodPt "<<lastGoodPt<<
" Pts size "<<tj.
Pts.size()<<
" tj.IsGood "<<tj.
IsGood;
3674 if(lastGoodPt == USHRT_MAX)
return;
3675 tj.
EndPt[1] = lastGoodPt;
3678 for(
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
3679 unsigned short ipt = tj.
Pts.size() - 1 - ii;
3680 if (ipt==lastGoodPt)
break;
3683 tj.
Pts[ipt].Dir = tj.
Pts[lastGoodPt].Dir;
3684 if(tj.
Pts[lastGoodPt].AngleCode == 2) {
3687 tj.
Pts[ipt].Pos[0] = tj.
Pts[lastGoodPt].Pos[0] + path * tj.
Pts[ipt].Dir[0];
3688 tj.
Pts[ipt].Pos[1] = tj.
Pts[lastGoodPt].Pos[1] + path * tj.
Pts[ipt].Dir[1];
3691 float dw = tj.
Pts[ipt].Pos[0] - tj.
Pts[lastGoodPt].Pos[0];
3693 float newpos = tj.
Pts[lastGoodPt].Pos[1] + dw * tj.
Pts[ipt].Dir[1] / tj.
Pts[ipt].Dir[0];
3694 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
"MTEP: ipt "<<ipt<<
" Pos[0] "<<tj.
Pts[ipt].Pos[0]<<
". Move Pos[1] from "<<tj.
Pts[ipt].Pos[1]<<
" to "<<newpos;
3695 tj.
Pts[ipt].Pos[1] = tj.
Pts[lastGoodPt].Pos[1] + dw * tj.
Pts[ipt].Dir[1] / tj.
Pts[ipt].Dir[0];
3698 if(
tcc.
dbgStp) mf::LogVerbatim(
"TC")<<
" masked ipt "<<ipt<<
" Pos "<<
PrintPos(slc, tj.
Pts[ipt])<<
" Chg "<<tj.
Pts[ipt].Chg;
3722 if(tj.
Pts[tj.
EndPt[0]].AngleCode == 2 || tj.
Pts[tj.
EndPt[1]].AngleCode == 2)
return;
3725 if(tj.
Pts.size() < 6)
return;
3730 mf::LogVerbatim(
"TC")<<
"ChkStop: T"<<tj.
ID<<
" requiring "<<nPtsToCheck<<
" points with charge slope > "<<
tcc.
chkStopCuts[0]<<
" Chg/WSEU";
3734 for(
unsigned short end = 0;
end < 2; ++
end) {
3738 if(endTP.Hits.size() > 2)
continue;
3743 unsigned short hiPt = 0;
3745 for(
unsigned short ii = 0; ii < 5; ++ii) {
3747 if(ipt < tj.
EndPt[0] || ipt > tj.
EndPt[1])
break;
3757 short dpt0 = hiPt - tj.
EndPt[0];
3758 short dpt1 = tj.
EndPt[1] - hiPt;
3759 if(
end == 0 && dpt1 <= dpt0)
continue;
3760 if(
end == 1 && dpt0 <= dpt1)
continue;
3761 if(prt) mf::LogVerbatim(
"TC")<<
" end "<<
end<<
" wire0 "<<wire0<<
" Chg "<<big<<
" hiPt "<<hiPt;
3762 float prevChg = big;
3766 float chgErr, chiDOF;
3768 Fit2D(0, inPt, chgErr, outVec, outVecErr, chiDOF);
3769 unsigned short cnt = 0;
3770 for(
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
3771 short ipt = hiPt + ii *
dir;
3772 if(ipt < tj.
EndPt[0] || ipt > tj.
EndPt[1])
break;
3774 if(tp.
Chg == 0)
continue;
3776 if(tp.
Chg > 1.5 * prevChg)
continue;
3782 chgErr = 0.2 * tp.
Chg;
3783 if(!
Fit2D(2, inPt, chgErr, outVec, outVecErr, chiDOF))
break;
3785 if(cnt == nPtsToCheck)
break;
3787 if(cnt < nPtsToCheck)
continue;
3789 if(!
Fit2D(-1, inPt, chgErr, outVec, outVecErr, chiDOF))
continue;
3791 if(chiDOF > 500)
continue;
3794 outVec[1] = -outVec[1];
3802 if(prt) mf::LogVerbatim(
"TC")<<
" end "<<
end<<
" fit chidof "<<chiDOF<<
" slope "<<outVec[1]<<
" +/- "<<outVecErr[1]<<
" stopping";
3804 if(prt) mf::LogVerbatim(
"TC")<<
" end "<<
end<<
" fit chidof "<<chiDOF<<
" slope "<<outVec[1]<<
" +/- "<<outVecErr[1]<<
" Not stopping";
3819 unsigned short nmichelhits = 0;
3821 unsigned short nbragghits = 0;
3824 bool isfirsthit =
true;
3825 unsigned short braggpeak = 0;
3827 for(
unsigned short ii = 0; ii < tj.
Pts.size(); ++ii) {
3828 if (ii>tj.
EndPt[1])
continue;
3829 unsigned short ipt = tj.
EndPt[1] - ii;
3830 if (tj.
Pts[ipt].Chg>0){
3833 if (tj.
Pts[ipt].ChgPull<0){
3838 if (tj.
Pts[ipt].ChgPull<0&&nmichelhits&&!nbragghits){
3844 lastChg = tj.
Pts[ipt].Chg;
3847 else if (tj.
Pts[ipt].Chg<lastChg){
3849 lastChg = tj.
Pts[ipt].Chg;
3856 if(prt) mf::LogVerbatim(
"TC")<<
"ChkMichel Michel hits: "<<nmichelhits<<
" Bragg peak hits: "<<nbragghits;
3857 if (nmichelhits>0&&nbragghits>2){
3858 lastGoodPt = braggpeak;
3873 if(tHits.size() < 2)
return false;
3877 for(
unsigned short ii = 0; ii < tHits.size(); ++ii) {
3883 if(prt)
std::cout<<
"MakeJunkTraj found debug hit\n";
3889 unsigned short pass =
tcc.
minPts.size() - 1;
3890 if(!
StartTraj(slc, work, tHits[0], tHits[tHits.size()-1], pass))
return false;
3892 work.
Pts.resize(tHits.size());
3894 for(
unsigned short ii = 0; ii < tHits.size(); ++ii) {
3895 auto& tp = work.
Pts[ii];
3896 unsigned int iht = tHits[ii];
3899 if(tp.CTP != work.
CTP)
return false;
3900 tp.Hits.push_back(iht);
3901 tp.UseHit[0] =
true;
3904 tp.HitPos[0] =
hit.WireID().Wire;
3906 tp.HitPosErr2 = 100;
3907 tp.Chg =
hit.Integral();
3909 tp.NTPsFit = tHits.size();
3914 work.
EndPt[1] = tHits.size() - 1;
3917 auto& lastTP = work.
Pts.back();
3922 for(
auto& tp : work.
Pts) {
3926 sum2 += at[1] * at[1];
3930 if(tp.Step != lastTP.Step) {
3931 tp.FitChi = lastTP.FitChi;
3932 tp.Dir = lastTP.Dir;
3933 tp.Ang = lastTP.Ang;
3934 tp.Pos[0] = lastTP.Pos[0] + at[0] * lastTP.Dir[0];
3935 tp.Pos[1] = lastTP.Pos[1] + at[0] * lastTP.Dir[1];
3938 double npts = tHits.size();
3940 double arg = sum2 - npts * sum * sum;
3941 if(arg <= 0)
return false;
3942 float rms = sqrt(arg) / (npts - 1);
3944 float transCut = sum + 3 * rms;
3945 std::vector<SortEntry> sortVec;
3949 for(
auto& tp : work.
Pts) {
3956 sortVec.push_back(se);
3960 if(sortVec.size() < 3)
return false;
3962 std::vector<TrajPoint> ntps(sortVec.size());
3963 for(
unsigned short ipt = 0; ipt < sortVec.size(); ++ipt) ntps[ipt] = work.
Pts[sortVec[ipt].index];
3965 sum = work.
TotChg / (
double)ntps.size();
3967 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)
std::vector< Trajectory > tjs
vector of all trajectories in each plane
void StepAway(TCSlice &slc, Trajectory &tj)
bool MaskedHitsOK(TCSlice &slc, Trajectory &tj)
void SetEndPoints(Trajectory &tj)
void UpdateTraj(TCSlice &slc, Trajectory &tj)
void FitPar(const TCSlice &slc, const Trajectory &tj, unsigned short originPt, unsigned short npts, short fitDir, ParFit &pFit, unsigned short usePar)
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 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)
EResult err(const char *call)
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)
void ChkBegin(TCSlice &slc, Trajectory &tj)
float maxWireSkipWithSignal
max number of wires to skip with a signal on them
std::string PrintPos(const TCSlice &slc, const TrajPoint &tp)
void FindUseHits(TCSlice &slc, Trajectory &tj, unsigned short ipt, float maxDelta, bool useChg)
void ChkChgAsymmetry(TCSlice &slc, Trajectory &tj, bool prt)
float ExpectedHitsRMS(TCSlice &slc, const TrajPoint &tp)
float TrajPointSeparation(const TrajPoint &tp1, const TrajPoint &tp2)
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
bool StartTraj(TCSlice &slc, Trajectory &tj, unsigned int fromhit, unsigned int tohit, unsigned short pass)
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 IsGood
set false if there is a failure or the Tj fails quality cuts
bool StoreVertex(TCSlice &slc, VtxStore &vx)
bool doForecast
See TCMode_t above.
std::vector< float > showerTag
shower-like trajectory tagging + shower reconstruction
unsigned short Pass
the pass on which it was created
int TDCtick_t
Type representing a TDC tick.
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
TrajPoint CreateTPFromTj(TCSlice &slc, const Trajectory &tj)
std::vector< unsigned short > maxAngleCode
max allowed angle code for each pass
float OverlapFraction(const TCSlice &slc, const Trajectory &tj1, const Trajectory &tj2)
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
bool CompatibleMerge(const TCSlice &slc, std::vector< int > &tjIDs, bool prt)
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
bool TrajIsClean(TCSlice &slc, Trajectory &tj, bool prt)
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.
float KinkSignificance(TCSlice &slc, Trajectory &tj1, unsigned short end1, Trajectory &tj2, unsigned short end2, unsigned short nPtsFit, bool useChg, bool prt)
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)
auto end(FixedBins< T, C > const &) noexcept
std::vector< VtxStore > vtxs
2D vertices
std::array< unsigned short, 2 > EndPt
First and last point in the trajectory that has charge.
unsigned short PDGCode
shower-like or track-like {default is track-like}
void TagJunkTj(TCSlice &slc, Trajectory &tj, bool prt)
short StartEnd
The starting end (-1 = don't know)
double PosSep2(const Point3_t &pos1, const Point3_t &pos2)
void FitTraj(TCSlice &slc, Trajectory &tj)
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.
void FixBegin(TCSlice &slc, Trajectory &tj, unsigned short atPt)
std::array< double, 2 > Vector2_t
Definition of data types for geometry description.
void ReverseTraj(TCSlice &slc, Trajectory &tj)
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.
void UpdateStiffEl(TCSlice &slc, Trajectory &tj)
void ChkStop(TCSlice &slc, Trajectory &tj)
void UpdateTjChgProperties(std::string inFcnLabel, TCSlice &slc, Trajectory &tj, bool prt)
std::bitset< 16 > modes
number of points to find AveChg
std::vector< TCHit > slHits
std::vector< float > chargeCuts
bool StopIfBadFits(TCSlice &slc, Trajectory &tj)
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)
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)
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)
bool SignalBetween(const TCSlice &slc, const TrajPoint &tp1, const TrajPoint &tp2, const float &MinWireSignalFraction)
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)
void MaskTrajEndPoints(TCSlice &slc, Trajectory &tj, unsigned short nPts)
void UpdateDeltaRMS(TCSlice &slc, Trajectory &tj)
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)
void ReversePropagate(TCSlice &slc, Trajectory &tj)
bool NeedsUpdate
Set true when the Tj needs to be updated.
void CheckHiMultEndHits(TCSlice &slc, Trajectory &tj)
float TPHitsRMSTick(const TCSlice &slc, const TrajPoint &tp, HitStatus_t hitRequest)
BEGIN_PROLOG could also be cout
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)
bool ChkMichel(TCSlice &slc, Trajectory &tj, unsigned short &lastGoodPt)