35 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h" 36 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h" 47 return c1.length > c2.length;
56 fNumPass = pset.
get<
unsigned short>(
"NumPass", 0);
57 fMaxHitsFit = pset.
get<std::vector<unsigned short>>(
"MaxHitsFit");
58 fMinHits = pset.
get<std::vector<unsigned short>>(
"MinHits");
59 fNHitsAve = pset.
get<std::vector<unsigned short>>(
"NHitsAve");
60 fChgCut = pset.
get<std::vector<float>>(
"ChgCut");
61 fChiCut = pset.
get<std::vector<float>>(
"ChiCut");
62 fMaxWirSkip = pset.
get<std::vector<unsigned short>>(
"MaxWirSkip");
63 fMinWirAfterSkip = pset.
get<std::vector<unsigned short>>(
"MinWirAfterSkip");
64 fKinkChiRat = pset.
get<std::vector<float>>(
"KinkChiRat");
65 fKinkAngCut = pset.
get<std::vector<float>>(
"KinkAngCut");
66 fDoMerge = pset.
get<std::vector<bool>>(
"DoMerge");
67 fTimeDelta = pset.
get<std::vector<float>>(
"TimeDelta");
68 fMergeChgCut = pset.
get<std::vector<float>>(
"MergeChgCut");
69 fFindVertices = pset.
get<std::vector<bool>>(
"FindVertices");
70 fLACrawl = pset.
get<std::vector<bool>>(
"LACrawl");
71 fMinAmp = pset.
get<std::vector<float>>(
"MinAmp", {5, 5, 5});
72 fChgNearWindow = pset.
get<
float>(
"ChgNearWindow");
73 fChgNearCut = pset.
get<
float>(
"ChgNearCut");
75 fChkClusterDS = pset.
get<
bool>(
"ChkClusterDS",
false);
76 fVtxClusterSplit = pset.
get<
bool>(
"VtxClusterSplit",
false);
77 fFindStarVertices = pset.
get<
bool>(
"FindStarVertices",
false);
78 if (pset.
has_key(
"HammerCluster")) {
80 <<
"fcl setting HammerCluster is replaced by FindHammerClusters. Ignoring...";
82 fFindHammerClusters = pset.
get<
bool>(
"FindHammerClusters",
false);
83 fKillGarbageClusters = pset.
get<
float>(
"KillGarbageClusters", 0);
84 fRefineVertexClusters = pset.
get<
bool>(
"RefineVertexClusters",
false);
85 fHitErrFac = pset.
get<
float>(
"HitErrFac", 0.2);
86 fHitMinAmp = pset.
get<
float>(
"HitMinAmp", 0.2);
87 fClProjErrFac = pset.
get<
float>(
"ClProjErrFac", 4);
88 fMinHitFrac = pset.
get<
float>(
"MinHitFrac", 0.6);
90 fLAClusAngleCut = pset.
get<
float>(
"LAClusAngleCut", 45);
91 fLAClusMaxHitsFit = pset.
get<
unsigned short>(
"LAClusMaxHitsFit");
92 fMergeAllHits = pset.
get<
bool>(
"MergeAllHits",
false);
93 fHitMergeChiCut = pset.
get<
float>(
"HitMergeChiCut", 2.5);
94 fMergeOverlapAngCut = pset.
get<
float>(
"MergeOverlapAngCut");
95 fAllowNoHitWire = pset.
get<
unsigned short>(
"AllowNoHitWire", 0);
96 fVertex2DCut = pset.
get<
float>(
"Vertex2DCut", 5);
97 fVertex2DWireErrCut = pset.
get<
float>(
"Vertex2DWireErrCut", 5);
98 fVertex3DCut = pset.
get<
float>(
"Vertex3DCut", 5);
100 fDebugPlane = pset.
get<
int>(
"DebugPlane", -1);
101 fDebugWire = pset.
get<
int>(
"DebugWire", -1);
102 fDebugHit = pset.
get<
int>(
"DebugHit", -1);
105 bool badinput =
false;
106 if (fNumPass > fMaxHitsFit.size()) badinput =
true;
107 if (fNumPass > fMinHits.size()) badinput =
true;
108 if (fNumPass > fNHitsAve.size()) badinput =
true;
109 if (fNumPass > fChgCut.size()) badinput =
true;
110 if (fNumPass > fChiCut.size()) badinput =
true;
111 if (fNumPass > fMaxWirSkip.size()) badinput =
true;
112 if (fNumPass > fMinWirAfterSkip.size()) badinput =
true;
113 if (fNumPass > fKinkChiRat.size()) badinput =
true;
114 if (fNumPass > fKinkAngCut.size()) badinput =
true;
115 if (fNumPass > fDoMerge.size()) badinput =
true;
116 if (fNumPass > fTimeDelta.size()) badinput =
true;
117 if (fNumPass > fMergeChgCut.size()) badinput =
true;
118 if (fNumPass > fFindVertices.size()) badinput =
true;
119 if (fNumPass > fLACrawl.size()) badinput =
true;
123 <<
"ClusterCrawlerAlg: Bad input from fcl file";
137 if (cmp_res != 0)
return cmp_res < 0;
145 void ClusterCrawlerAlg::ClearResults()
155 void ClusterCrawlerAlg::CrawlInit()
181 WireHitRange.clear();
187 void ClusterCrawlerAlg::ClusterInit()
203 std::vector<recob::Hit>
const& srchits)
211 if (fHits.size() < 3)
return;
212 if (fHits.size() > UINT_MAX) {
213 mf::LogWarning(
"CC") <<
"Too many hits for ClusterCrawler " << fHits.size();
218 if (fNumPass == 0)
return;
223 std::sort(fHits.begin(), fHits.end(), &SortByMultiplet);
225 inClus.resize(fHits.size());
226 mergeAvailable.resize(fHits.size());
227 for (
unsigned int iht = 0; iht < inClus.size(); ++iht) {
229 mergeAvailable[iht] =
false;
234 cstat = tpcid.Cryostat;
237 plane = planeid.Plane;
238 WireHitRange.clear();
240 clCTP =
EncodeCTP(tpcid.Cryostat, tpcid.TPC, planeid.Plane);
241 cstat = tpcid.Cryostat;
248 if (WireHitRange.empty() || (fFirstWire == fLastWire))
continue;
252 float wirePitch = geom->WirePitch(geom->View(channel));
255 fScaleF = tickToDist / wirePitch;
257 if (fLAClusAngleCut > 0)
258 fLAClusSlopeCut = std::tan(3.142 * fLAClusAngleCut / 180.) / fScaleF;
260 fNumWires = geom->Nwires(planeid);
262 if (fNumPass > 0) ClusterLoop();
264 if (fVertex3DCut > 0) {
266 VtxMatch(det_prop, tpcid);
267 Vtx3ClusterMatch(det_prop, tpcid);
268 if (fFindHammerClusters) FindHammerClusters(det_prop);
270 Vtx3ClusterSplit(det_prop, tpcid);
272 if (fDebugPlane >= 0) {
279 WireHitRange.clear();
286 RemoveObsoleteHits();
291 void ClusterCrawlerAlg::ClusterLoop()
295 unsigned int nHitsUsed = 0, iwire, jwire, kwire;
296 bool AllDone =
false, SigOK =
false, HitOK =
false;
297 unsigned int ihit, jhit;
298 for (
unsigned short thispass = 0; thispass < fNumPass; ++thispass) {
301 unsigned int span = 3;
302 if (fMinHits[pass] < span) span = fMinHits[pass];
303 for (iwire = fLastWire; iwire > fFirstWire +
span; --iwire) {
305 if (WireHitRange[iwire].first < 0)
continue;
306 auto ifirsthit = (
unsigned int)WireHitRange[iwire].first;
307 auto ilasthit = (
unsigned int)WireHitRange[iwire].
second;
308 for (ihit = ifirsthit; ihit < ilasthit; ++ihit) {
309 bool ClusterAdded =
false;
312 if (ihit > fHits.size() - 1) {
313 mf::LogError(
"CC") <<
"ClusterLoop bad ihit " << ihit <<
" fHits size " << fHits.size();
317 if (inClus[ihit] != 0)
continue;
319 if (fHits[ihit].PeakAmplitude() < fHitMinAmp)
continue;
320 if ((iwire + 1) < span)
continue;
321 jwire = iwire - span + 1;
325 if (WireHitRange[jwire].first == -2)
continue;
326 if (WireHitRange[jwire].first == -1) {
328 unsigned int nmissed = 0;
329 while (WireHitRange[jwire].first == -1 && jwire > 1 && nmissed < fMaxWirSkip[pass]) {
335 <<
" new jwire " << jwire <<
" dead? " << WireHitRange[jwire].first;
336 if (WireHitRange[jwire].first < 0)
continue;
340 unsigned int useHit = 0;
341 bool doConstrain =
false;
342 VtxConstraint(iwire, ihit, jwire, useHit, doConstrain);
343 unsigned int jfirsthit = (
unsigned int)WireHitRange[jwire].first;
344 unsigned int jlasthit = (
unsigned int)WireHitRange[jwire].
second;
345 if (jfirsthit > fHits.size() - 1 || jfirsthit > fHits.size() - 1)
347 <<
"ClusterLoop jwire " << jwire <<
" bad firsthit " << jfirsthit <<
" lasthit " 348 << jlasthit <<
" fhits size " << fHits.size();
349 for (jhit = jfirsthit; jhit < jlasthit; ++jhit) {
350 if (jhit > fHits.size() - 1)
352 <<
"ClusterLoop bad jhit " << jhit <<
" firsthit " << jfirsthit <<
" lasthit " 353 << jlasthit <<
" fhits size" << fHits.size();
355 if (doConstrain && jhit != useHit)
continue;
358 if (inClus[jhit] != 0)
continue;
360 if (fHits[jhit].PeakAmplitude() < fHitMinAmp)
continue;
363 fcl2hits.push_back(ihit);
364 chifits.push_back(0.);
365 hitNear.push_back(0);
366 chgNear.push_back(0);
368 fcl2hits.push_back(jhit);
369 chifits.push_back(0.);
370 hitNear.push_back(0);
371 chgNear.push_back(0);
376 clparerr[1] = 0.2 *
std::abs(clpar[1]);
377 clpar[2] = fHits[jhit].WireID().Wire;
381 for (kwire = jwire + 1; kwire < iwire; ++kwire) {
383 if (CrawlVtxChk(kwire)) {
387 AddHit(kwire, HitOK, SigOK);
389 mf::LogVerbatim(
"CC") <<
" HitOK " << HitOK <<
" clChisq " << clChisq <<
" cut " 390 << fChiCut[pass] <<
" ClusterHitsOK " << ClusterHitsOK(-1);
394 if (clChisq > 2)
break;
396 if (!ClusterHitsOK(-1))
continue;
401 prt = (fDebugPlane == (int)plane && (
int)iwire == fDebugWire &&
405 <<
"ADD >>>>> Starting cluster with hits " <<
PrintHit(fcl2hits[0]) <<
" " 406 <<
PrintHit(fcl2hits[1]) <<
" " <<
PrintHit(fcl2hits[2]) <<
" on pass " << pass;
410 clBeginSlp = clpar[1];
413 if (!fLACrawl[pass] &&
std::abs(clBeginSlp) > fLAClusSlopeCut)
continue;
416 if (CrawlVtxChk2())
continue;
417 clBeginSlpErr = clparerr[1];
421 for (
unsigned short kk = 0; kk < fcl2hits.size(); ++kk) {
422 fAveHitWidth += fHits[fcl2hits[kk]].EndTick() - fHits[fcl2hits[kk]].StartTick();
424 fAveHitWidth /= (float)fcl2hits.size();
430 if (fLACrawl[pass] && fLAClusSlopeCut > 0) {
432 if (
std::abs(clBeginSlp) > fLAClusSlopeCut) { LACrawlUS(); }
441 if (fcl2hits.size() >= fMinHits[pass]) {
444 clEndSlpErr = clparerr[1];
447 mf::LogError(
"CC") <<
"Failed to store cluster in plane " << plane;
451 nHitsUsed += fcl2hits.size();
452 AllDone = (nHitsUsed == fHits.size());
459 if (ClusterAdded || AllDone)
break;
467 if (fDoMerge[pass]) ChkMerge();
469 if (fFindVertices[pass]) FindVertices();
476 if (fKillGarbageClusters > 0 && !tcl.empty()) KillGarbageClusters();
480 if (fChkClusterDS) ChkClusterDS();
482 if (fVtxClusterSplit) {
483 bool didSomething = VtxClusterSplit();
485 if (didSomething) VtxClusterSplit();
488 if (fFindStarVertices) FindStarVertices();
490 if (fDebugPlane == (
int)plane) {
495 CheckHitClusterAssociations();
500 void ClusterCrawlerAlg::KillGarbageClusters()
504 if (tcl.size() < 2)
return;
506 unsigned short icl, jcl;
509 std::vector<float> iHits, jHits;
513 float sepcut = 0, iFrac, jFrac;
515 unsigned short iLoIndx, jLoIndx, olapSize, iop, ii, jj;
516 unsigned short nclose;
519 std::vector<unsigned short> killMe;
521 for (icl = 0; icl < tcl.size() - 1; ++icl) {
522 if (tcl[icl].ID < 0)
continue;
523 if (tcl[icl].CTP != clCTP)
continue;
527 iHits.resize(tcl[icl].BeginWir - tcl[icl].EndWir + 1, 1000);
529 for (
auto iht : tcl[icl].tclhits) {
530 indx = fHits[iht].WireID().Wire - tcl[icl].EndWir;
531 if (indx > iHits.size() - 1) {
532 mf::LogWarning(
"CC") <<
"KillGarbageClusters: icl ID " << tcl[icl].ID <<
" Bad indx " 533 << indx <<
" " << iHits.size() <<
"\n";
536 iHits[indx] = fHits[iht].PeakTime();
537 iChg += fHits[iht].Integral();
538 if (first) sepcut += fHits[iht].RMS();
541 sepcut /= (float)tcl[icl].tclhits.size();
547 for (jcl = icl + 1; jcl < tcl.size(); ++jcl) {
548 if (tcl[jcl].ID < 0)
continue;
549 if (tcl[jcl].CTP != clCTP)
continue;
551 if (tcl[icl].BeginWir < tcl[jcl].EndWir)
continue;
552 if (tcl[icl].EndWir > tcl[jcl].BeginWir)
continue;
554 if (
std::abs(tcl[icl].BeginAng - tcl[jcl].BeginAng) > fKillGarbageClusters)
continue;
556 if (tcl[icl].EndWir < tcl[jcl].EndWir) {
560 iLoIndx = tcl[jcl].EndWir - tcl[icl].EndWir;
562 if (tcl[icl].BeginWir < tcl[jcl].BeginWir) {
566 olapSize = tcl[icl].BeginWir - tcl[jcl].EndWir + 1;
572 olapSize = tcl[jcl].BeginWir - tcl[jcl].EndWir + 1;
580 jLoIndx = tcl[icl].EndWir - tcl[icl].EndWir;
581 if (tcl[icl].BeginWir < tcl[jcl].BeginWir) {
585 olapSize = tcl[icl].BeginWir - tcl[icl].EndWir + 1;
591 olapSize = tcl[jcl].BeginWir - tcl[icl].EndWir + 1;
596 jHits.resize(tcl[jcl].BeginWir - tcl[jcl].EndWir + 1, -1000);
598 for (
auto jht : tcl[jcl].tclhits) {
599 indx = fHits[jht].WireID().Wire - tcl[jcl].EndWir;
600 if (indx > jHits.size() - 1) {
601 mf::LogWarning(
"CC") <<
"KillGarbageClusters: jcl ID " << tcl[jcl].ID <<
" Bad indx " 602 << indx <<
" " << jHits.size() <<
"\n";
605 jHits[indx] = fHits[jht].PeakTime();
606 jChg += fHits[jht].Integral();
610 for (iop = 0; iop < olapSize; ++iop) {
612 if (ii > iHits.size() - 1)
continue;
614 if (jj > jHits.size() - 1)
continue;
615 if (
std::abs(iHits[ii] - jHits[jj]) < sepcut) ++nclose;
617 iFrac = (float)nclose / (
float)iHits.size();
618 jFrac = (float)nclose / (
float)jHits.size();
619 if (iFrac < 0.5 && jFrac < 0.5)
continue;
620 doKill = (iFrac < jFrac && iChg > jChg);
621 if (doKill) killMe.push_back(jcl);
625 if (killMe.size() == 0)
return;
626 for (
auto icl : killMe) {
628 if (tcl[icl].ID < 0)
continue;
629 tcl[icl].ProcCode = 666;
630 MakeClusterObsolete(icl);
649 unsigned short icl, jcl;
651 bool chkprt = (fDebugWire == 666);
652 if (chkprt)
mf::LogVerbatim(
"CC") <<
"Inside MergeOverlap using clCTP " << clCTP;
654 unsigned short minLen = 6;
655 unsigned short minOvrLap = 2;
658 float maxDTick = fTimeDelta[fTimeDelta.size() - 1];
660 unsigned int overlapSize, ii, indx, bWire, eWire;
661 unsigned int iht, jht;
662 float dang, prtime, dTick;
663 for (icl = 0; icl < tcl.size(); ++icl) {
664 if (tcl[icl].ID < 0)
continue;
665 if (tcl[icl].CTP != clCTP)
continue;
666 prt = chkprt && fDebugPlane == (int)clCTP;
667 if (tcl[icl].BeginVtx >= 0)
continue;
668 if (tcl[icl].tclhits.size() < minLen)
continue;
669 for (jcl = 0; jcl < tcl.size(); ++jcl) {
670 if (icl == jcl)
continue;
671 if (tcl[jcl].ID < 0)
continue;
672 if (tcl[jcl].CTP != clCTP)
continue;
673 if (tcl[jcl].EndVtx >= 0)
continue;
674 if (tcl[jcl].tclhits.size() < minLen)
continue;
676 if (tcl[icl].BeginWir < tcl[jcl].EndWir + minOvrLap)
continue;
678 if (tcl[icl].BeginWir > tcl[jcl].BeginWir - minOvrLap)
continue;
680 if (tcl[jcl].EndWir < tcl[icl].EndWir + minOvrLap)
continue;
681 dang =
std::abs(tcl[icl].BeginAng - tcl[jcl].EndAng);
683 mf::LogVerbatim(
"CC") <<
"MergeOverlap icl ID " << tcl[icl].ID <<
" jcl ID " 684 << tcl[jcl].ID <<
" dang " << dang;
685 if (dang > 0.5)
continue;
686 overlapSize = tcl[icl].BeginWir - tcl[jcl].EndWir + 1;
687 eWire = tcl[jcl].EndWir;
688 bWire = tcl[icl].BeginWir;
690 mf::LogVerbatim(
"CC") <<
" Candidate icl ID " << tcl[icl].ID <<
" " << tcl[icl].EndWir
691 <<
"-" << tcl[icl].BeginWir <<
" jcl ID " << tcl[jcl].ID <<
" " 692 << tcl[jcl].EndWir <<
"-" << tcl[jcl].BeginWir <<
" overlapSize " 693 << overlapSize <<
" bWire " << bWire <<
" eWire " << eWire;
696 for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
697 iht = tcl[icl].tclhits[ii];
698 if (fHits[iht].
WireID().Wire < eWire)
break;
701 dTick =
std::abs(fHits[iht].PeakTime() - tcl[jcl].EndTim);
702 if (dTick > maxDTick)
continue;
705 << tcl[jcl].EndTim <<
" dTick " << dTick;
706 for (ii = 0; ii < tcl[jcl].tclhits.size(); ++ii) {
707 jht = tcl[jcl].tclhits[tcl[jcl].tclhits.size() - ii - 1];
708 if (fHits[jht].
WireID().Wire > bWire)
break;
710 dTick =
std::abs(fHits[jht].PeakTime() - tcl[icl].BeginTim);
711 if (dTick > maxDTick)
continue;
714 << tcl[icl].BeginTim <<
" dTick " << dTick;
716 clpar[0] = fHits[iht].PeakTime();
717 clpar[2] = fHits[iht].WireID().Wire;
718 clpar[1] = (fHits[jht].PeakTime() - fHits[iht].PeakTime()) /
719 ((
float)fHits[jht].WireID().Wire - clpar[2]);
721 std::vector<unsigned int> oWireHits(overlapSize, INT_MAX);
722 std::vector<float> delta(overlapSize, maxDTick);
723 for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
724 iht = tcl[icl].tclhits[ii];
725 if (fHits[iht].
WireID().Wire < eWire)
break;
726 prtime = clpar[0] + clpar[1] * ((float)fHits[iht].
WireID().Wire - clpar[2]);
727 dTick =
std::abs(fHits[iht].PeakTime() - prtime);
728 indx = fHits[iht].WireID().Wire - eWire;
729 if (dTick > delta[indx])
continue;
731 oWireHits[indx] = iht;
734 for (ii = 0; ii < tcl[jcl].tclhits.size(); ++ii) {
735 jht = tcl[jcl].tclhits[tcl[jcl].tclhits.size() - ii - 1];
736 if (fHits[jht].
WireID().Wire > bWire)
break;
737 prtime = clpar[0] + clpar[1] * ((float)fHits[jht].
WireID().Wire - clpar[2]);
738 dTick =
std::abs(fHits[jht].PeakTime() - prtime);
739 indx = fHits[jht].WireID().Wire - eWire;
740 if (dTick > delta[indx])
continue;
742 oWireHits[indx] = jht;
746 for (ii = 0; ii < oWireHits.size(); ++ii) {
747 if (oWireHits[ii] == INT_MAX)
continue;
749 fcl2hits.push_back(iht);
752 if (fcl2hits.size() < 0.5 * overlapSize)
continue;
753 if (fcl2hits.size() < 3)
continue;
754 std::sort(fcl2hits.begin(), fcl2hits.end(),
SortByLowHit);
757 mf::LogVerbatim(
"CC") <<
" Overlap size " << overlapSize <<
" fit chisq " << clChisq
758 <<
" nhits " << fcl2hits.size();
759 if (clChisq > 20)
continue;
761 std::vector<unsigned int> oHits = fcl2hits;
765 unsigned short jclNewSize;
766 for (jclNewSize = 0; jclNewSize < fcl2hits.size(); ++jclNewSize) {
767 iht = fcl2hits[jclNewSize];
768 if (fHits[iht].
WireID().Wire <= bWire)
break;
771 mf::LogVerbatim(
"CC") <<
"jcl old size " << fcl2hits.size() <<
" newSize " << jclNewSize;
772 iht = fcl2hits[fcl2hits.size() - 1];
773 unsigned int iiht = fcl2hits[jclNewSize - 1];
774 mf::LogVerbatim(
"CC") <<
"jcl old last wire " << fHits[iht].WireID().Wire
775 <<
" After resize last wire " << fHits[iiht].WireID().Wire;
777 fcl2hits.resize(jclNewSize);
779 fcl2hits.insert(fcl2hits.end(), oHits.begin(), oHits.end());
781 for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
782 iht = tcl[icl].tclhits[ii];
783 if ((
unsigned int)fHits[iht].WireID().Wire >= eWire)
continue;
784 fcl2hits.insert(fcl2hits.end(), tcl[icl].tclhits.begin() + ii, tcl[icl].tclhits.end());
787 clBeginSlp = tcl[jcl].BeginSlp;
788 clBeginSlpErr = tcl[jcl].BeginSlpErr;
789 clBeginAng = tcl[jcl].BeginAng;
790 clBeginWir = tcl[jcl].BeginWir;
791 clBeginTim = tcl[jcl].BeginTim;
792 clBeginChg = tcl[jcl].BeginChg;
793 clBeginChgNear = tcl[jcl].BeginChgNear;
795 clEndSlp = tcl[icl].EndSlp;
796 clEndSlpErr = tcl[icl].EndSlpErr;
797 clEndAng = tcl[icl].EndAng;
798 clEndWir = tcl[icl].EndWir;
799 clEndTim = tcl[icl].EndTim;
800 clEndChg = tcl[icl].EndChg;
801 clEndChgNear = tcl[icl].EndChgNear;
802 clStopCode = tcl[icl].StopCode;
803 clProcCode = tcl[icl].ProcCode + 500;
804 MakeClusterObsolete(icl);
805 MakeClusterObsolete(jcl);
808 RestoreObsoleteCluster(icl);
809 RestoreObsoleteCluster(jcl);
810 CheckHitClusterAssociations();
813 CheckHitClusterAssociations();
814 tcl[tcl.size() - 1].BeginVtx = tcl[jcl].BeginVtx;
815 tcl[tcl.size() - 1].EndVtx = tcl[icl].BeginVtx;
818 mf::LogVerbatim(
"CC") <<
"MergeOverlap new long cluster ID " << tcl[tcl.size() - 1].ID
819 <<
" in clCTP " << clCTP;
821 if (tcl[icl].ID < 0)
break;
828 void ClusterCrawlerAlg::MakeClusterObsolete(
unsigned short icl)
830 short& ID = tcl[icl].ID;
832 mf::LogError(
"CC") <<
"Trying to make already-obsolete cluster obsolete ID = " << ID;
838 for (
unsigned int iht = 0; iht < tcl[icl].tclhits.size(); ++iht)
839 inClus[tcl[icl].tclhits[iht]] = 0;
844 void ClusterCrawlerAlg::RestoreObsoleteCluster(
unsigned short icl)
846 short& ID = tcl[icl].ID;
848 mf::LogError(
"CC") <<
"Trying to restore non-obsolete cluster ID = " << ID;
853 for (
unsigned short iht = 0; iht < tcl[icl].tclhits.size(); ++iht)
854 inClus[tcl[icl].tclhits[iht]] = ID;
859 void ClusterCrawlerAlg::FclTrimUS(
unsigned short nTrim)
863 if (nTrim == 0)
return;
865 if (nTrim >= fcl2hits.size()) nTrim = fcl2hits.size();
868 for (
unsigned short ii = 0; ii < nTrim; ++ii) {
878 void ClusterCrawlerAlg::CheckHitClusterAssociations()
882 if (fHits.size() != inClus.size()) {
883 mf::LogError(
"CC") <<
"CHCA: Sizes wrong " << fHits.size() <<
" " << inClus.size();
887 unsigned int iht, nErr = 0;
891 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
892 if (tcl[icl].ID < 0)
continue;
894 for (
unsigned short ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
895 iht = tcl[icl].tclhits[ii];
896 if (iht > fHits.size() - 1) {
897 mf::LogError(
"CC") <<
"CHCA: Bad tclhits index " << iht <<
" fHits size " << fHits.size();
900 if (inClus[iht] != clID) {
901 mf::LogError(
"CC") <<
"CHCA: Bad cluster -> hit association. clID " << clID
902 <<
" hit inClus " << inClus[iht] <<
" ProcCode " << tcl[icl].ProcCode
903 <<
" CTP " << tcl[icl].CTP;
905 if (nErr > 10)
return;
912 for (iht = 0; iht < fHits.size(); ++iht) {
913 if (inClus[iht] <= 0)
continue;
914 icl = inClus[iht] - 1;
916 if (tcl[icl].ID < 0) {
917 mf::LogError(
"CC") <<
"CHCA: Hit associated with an obsolete cluster. hit W:T " 918 << fHits[iht].WireID().Wire <<
":" << (int)fHits[iht].PeakTime()
919 <<
" tcl[icl].ID " << tcl[icl].ID;
921 if (nErr > 10)
return;
923 if (std::find(tcl[icl].tclhits.begin(), tcl[icl].tclhits.end(), iht) ==
924 tcl[icl].tclhits.end()) {
925 mf::LogError(
"CC") <<
"CHCA: Bad hit -> cluster association. hit index " << iht <<
" W:T " 926 << fHits[iht].WireID().Wire <<
":" << (int)fHits[iht].PeakTime()
927 <<
" inClus " << inClus[iht];
929 if (nErr > 10)
return;
936 void ClusterCrawlerAlg::RemoveObsoleteHits()
939 unsigned int destHit = 0;
941 if (fHits.size() != inClus.size()) {
942 mf::LogError(
"CC") <<
"RemoveObsoleteHits size mis-match " << fHits.size() <<
" " 948 for (
unsigned int srcHit = 0; srcHit < fHits.size(); ++srcHit) {
949 if (inClus[srcHit] < 0)
continue;
950 if (srcHit != destHit) {
951 fHits[destHit] = std::move(fHits[srcHit]);
952 inClus[destHit] = inClus[srcHit];
953 if (inClus[destHit] > 0) {
955 icl = inClus[destHit] - 1;
956 auto&
hits = tcl[icl].tclhits;
957 auto iHitIndex = std::find(
hits.begin(),
hits.end(), srcHit);
958 if (iHitIndex ==
hits.end()) {
959 mf::LogError(
"CC") <<
"RemoveObsoleteHits: Hit #" << srcHit
960 <<
" not found in cluster ID " << inClus[destHit];
963 *iHitIndex = destHit;
970 fHits.resize(destHit);
971 inClus.resize(destHit);
976 void ClusterCrawlerAlg::ChkClusterDS()
983 prt = (fDebugPlane == 3);
986 float dThCut = fKinkAngCut[fNumPass - 1];
989 mf::LogVerbatim(
"CC") <<
"ChkClusterDS clCTP " << clCTP <<
" kink angle cut " << dThCut;
991 const unsigned short tclsize = tcl.size();
992 bool didMerge, skipit;
993 unsigned short icl, ii, nhm, iv;
997 for (icl = 0; icl < tclsize; ++icl) {
998 if (tcl[icl].ID < 0)
continue;
999 if (tcl[icl].CTP != clCTP)
continue;
1001 if (tcl[icl].BeginVtx >= 0)
continue;
1004 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1005 if (vtx[iv].CTP != clCTP)
continue;
1006 if (
std::abs(vtx[iv].Wire - tcl[icl].BeginWir) > 4)
continue;
1007 if (
std::abs(vtx[iv].Time - tcl[icl].BeginTim) > 20)
continue;
1011 if (skipit)
continue;
1014 for (ii = 0; ii < 3; ++ii) {
1016 if (fHits[iht].Multiplicity() > 1) {
1017 MergeHits(iht, didMerge);
1018 if (didMerge) ++nhm;
1023 FitClusterMid(icl, 0, 3);
1024 tcl[icl].BeginTim = clpar[0];
1025 tcl[icl].BeginSlp = clpar[1];
1026 tcl[icl].BeginAng = atan(fScaleF * clpar[1]);
1027 tcl[icl].BeginSlpErr = clparerr[1];
1028 tcl[icl].BeginChg = fAveChg;
1029 tcl[icl].ProcCode += 5000;
1030 if (prt)
mf::LogVerbatim(
"CC") <<
"ChkClusterDS: Merge hits on cluster " << tcl[icl].ID;
1034 float thhits, prevth, hitrms, rmsrat;
1036 std::vector<unsigned int> dshits;
1037 for (icl = 0; icl < tclsize; ++icl) {
1038 if (tcl[icl].ID < 0)
continue;
1039 if (tcl[icl].CTP != clCTP)
continue;
1041 if (tcl[icl].BeginVtx >= 0)
continue;
1044 for (iv = 0; iv < vtx.size(); ++iv) {
1045 if (vtx[iv].CTP != clCTP)
continue;
1046 if (
std::abs(vtx[iv].Wire - tcl[icl].BeginWir) > 4)
continue;
1047 if (
std::abs(vtx[iv].Time - tcl[icl].BeginTim) > 20)
continue;
1051 if (skipit)
continue;
1053 unsigned int ih0 = tcl[icl].tclhits[1];
1054 unsigned int ih1 = tcl[icl].tclhits[0];
1055 const float slp = (fHits[ih1].PeakTime() - fHits[ih0].PeakTime()) /
1056 (fHits[ih1].
WireID().Wire - fHits[ih0].WireID().Wire);
1057 prevth = std::atan(fScaleF * slp);
1060 unsigned int wire = fHits[ih0].WireID().Wire;
1061 hitrms = fHits[ih0].RMS();
1062 float time0 = fHits[ih0].PeakTime();
1067 for (ii = 0; ii < 4; ++ii) {
1069 if (wire > fLastWire)
break;
1070 prtime = time0 + slp;
1072 mf::LogVerbatim(
"CC") <<
"ChkClusterDS: Try to extend " << tcl[icl].ID <<
" to W:T " 1073 << wire <<
" hitrms " << hitrms <<
" prevth " << prevth
1074 <<
" prtime " << (int)prtime;
1076 if (WireHitRange[wire].first == -2)
break;
1077 unsigned int firsthit = WireHitRange[wire].first;
1078 unsigned int lasthit = WireHitRange[wire].second;
1079 bool hitAdded =
false;
1080 for (ih1 = firsthit; ih1 < lasthit; ++ih1) {
1081 if (inClus[ih1] != 0)
continue;
1082 if (prtime < fHits[ih1].PeakTimeMinusRMS(5))
continue;
1083 if (prtime > fHits[ih1].PeakTimePlusRMS(5))
continue;
1084 const float slp = (fHits[ih1].PeakTime() - fHits[ih0].PeakTime()) /
1085 (fHits[ih1].
WireID().Wire - fHits[ih0].WireID().Wire);
1086 thhits = std::atan(fScaleF * slp);
1088 mf::LogVerbatim(
"CC") <<
" theta " << thhits <<
" prevth " << prevth <<
" cut " 1090 if (
std::abs(thhits - prevth) > dThCut)
continue;
1093 if (
std::abs(slp) < fLAClusSlopeCut) {
1094 rmsrat = fHits[ih1].RMS() / hitrms;
1095 ratOK = rmsrat > 0.3 && rmsrat < 3;
1100 MergeHits(ih1, didMerge);
1102 if (prt)
mf::LogVerbatim(
"CC") <<
" rmsrat " << rmsrat <<
" OK? " << ratOK;
1107 dshits.push_back(ih1);
1112 mf::LogVerbatim(
"CC") <<
" Add hit " << fHits[ih1].WireID().Wire <<
":" 1113 << (int)fHits[ih1].PeakTime() <<
" rmsrat " << rmsrat;
1118 if (!hitAdded)
break;
1121 if (dshits.size() > 0) {
1127 if (dshits.size() > 1) std::sort(dshits.begin(), dshits.end(),
SortByLowHit);
1131 for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
1133 iht = tcl[icl].tclhits[ii];
1135 fcl2hits.push_back(iht);
1138 pass = fNumPass - 1;
1140 clBeginChg = fAveChg;
1142 MakeClusterObsolete(icl);
1145 mf::LogError(
"CC") <<
"ChkClusterDS TmpStore failed while extending cluster ID " 1149 const size_t newcl = tcl.size() - 1;
1151 tcl[newcl].BeginVtx = tcl[icl].BeginVtx;
1152 tcl[newcl].EndVtx = tcl[icl].EndVtx;
1158 bool ClusterCrawlerAlg::CrawlVtxChk2()
1164 if (vtx.size() == 0)
return false;
1165 if (fcl2hits.size() == 0)
return false;
1167 unsigned int iht = fcl2hits.size() - 1;
1169 float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1171 float thclus = std::atan(fScaleF * clpar[1]);
1173 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1174 if (vtx[iv].CTP != clCTP)
continue;
1175 if (wire0 < vtx[iv].Wire)
continue;
1176 if (wire0 > vtx[iv].Wire + 10)
continue;
1177 dt = clpar[0] + (vtx[iv].Wire - wire0) * clpar[1] - vtx[iv].Time;
1181 for (icl = 0; icl < tcl.size(); ++icl) {
1182 if (tcl[icl].CTP != clCTP)
continue;
1183 if (tcl[icl].EndVtx != iv)
continue;
1184 if (
std::abs(tcl[icl].EndAng - thclus) < fKinkAngCut[pass])
return true;
1193 bool ClusterCrawlerAlg::CrawlVtxChk(
unsigned int kwire)
1197 if (vtx.size() == 0)
return false;
1198 unsigned int iht = fcl2hits.size() - 1;
1199 float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1200 float prtime = clpar[0] + (kwire - wire0) * clpar[1];
1201 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1202 if (vtx[iv].CTP != clCTP)
continue;
1203 if ((
unsigned int)(0.5 + vtx[iv].Wire) != kwire)
continue;
1204 if (
std::abs(prtime - vtx[iv].Time) < 10)
return true;
1210 void ClusterCrawlerAlg::VtxConstraint(
unsigned int iwire,
1213 unsigned int& useHit,
1219 doConstrain =
false;
1220 if (vtx.size() == 0)
return;
1222 if (pass == 0)
return;
1224 if (!fFindVertices[pass - 1])
return;
1226 if (jwire > WireHitRange.size() - 1) {
1227 mf::LogError(
"CC") <<
"VtxConstraint fed bad jwire " << jwire <<
" WireHitRange size " 1228 << WireHitRange.size();
1232 unsigned int jfirsthit = WireHitRange[jwire].first;
1233 unsigned int jlasthit = WireHitRange[jwire].second;
1234 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1235 if (vtx[iv].CTP != clCTP)
continue;
1237 if (vtx[iv].Wire > jwire)
continue;
1239 if (vtx[iv].Wire < jwire - 10)
continue;
1242 clpar[1] = (vtx[iv].Time - hit.
PeakTime()) / (vtx[iv].Wire - iwire);
1244 float prtime = clpar[0] + clpar[1] * (jwire - iwire);
1245 for (
unsigned int jhit = jfirsthit; jhit < jlasthit; ++jhit) {
1246 if (inClus[jhit] != 0)
continue;
1247 const float tdiff =
std::abs(fHits[jhit].TimeDistanceAsRMS(prtime));
1259 void ClusterCrawlerAlg::RefineVertexClusters(
unsigned short iv)
1264 std::vector<unsigned short> begClusters;
1265 std::vector<short> begdW;
1266 std::vector<unsigned short> endClusters;
1267 std::vector<short> enddW;
1269 unsigned int vWire = (
unsigned int)(vtx[iv].Wire + 0.5);
1270 unsigned int vWireErr = (
unsigned int)(2 * vtx[iv].WireErr);
1271 unsigned int vWireLo = vWire - vWireErr;
1272 unsigned int vWireHi = vWire + vWireErr;
1274 unsigned short icl, ii;
1276 bool needsWork =
false;
1279 for (icl = 0; icl < tcl.size(); ++icl) {
1280 if (tcl[icl].ID < 0)
continue;
1281 if (tcl[icl].CTP != vtx[iv].CTP)
continue;
1282 if (tcl[icl].BeginVtx == iv) {
1283 dW = vWire - tcl[icl].BeginWir;
1284 if (dW > maxdW) maxdW = dW;
1285 if (dW < mindW) mindW = dW;
1286 if (
std::abs(dW) > 1) needsWork =
true;
1288 begClusters.push_back(icl);
1289 begdW.push_back(dW);
1291 if (tcl[icl].EndVtx == iv) {
1292 dW = vWire - tcl[icl].EndWir;
1293 if (dW > maxdW) maxdW = dW;
1294 if (dW < mindW) mindW = dW;
1295 if (
std::abs(dW) > 1) needsWork =
true;
1296 endClusters.push_back(icl);
1297 enddW.push_back(dW);
1302 mf::LogVerbatim(
"CC") <<
"RefineVertexClusters: vertex " << iv <<
" needsWork " << needsWork
1303 <<
" mindW " << mindW <<
" maxdW " << maxdW <<
" vWireErr " << vWireErr;
1305 if (!needsWork)
return;
1309 if (((
unsigned int)
std::abs(mindW) < vWireErr) && ((
unsigned int)
std::abs(maxdW) < vWireErr) &&
1311 if (vtxprt)
mf::LogVerbatim(
"CC") <<
" Move vtx wire " << vtx[iv].Wire;
1312 vtx[iv].Wire -= (float)(maxdW + mindW) / 2;
1315 vtx[iv].Fixed =
true;
1322 unsigned short newSize;
1323 for (ii = 0; ii < endClusters.size(); ++ii) {
1324 icl = endClusters[ii];
1326 mf::LogVerbatim(
"CC") <<
" endCluster " << tcl[icl].ID <<
" dW " << enddW[ii] <<
" vWire " 1328 if (tcl[icl].EndWir < vWire) {
1331 newSize = fcl2hits.size();
1332 for (
auto hiter = fcl2hits.rbegin(); hiter < fcl2hits.rend(); ++hiter) {
1333 if (fHits[*hiter].
WireID().Wire > vWire)
break;
1337 for (
auto hiter = fcl2hits.begin(); hiter < fcl2hits.end(); ++hiter)
1340 fcl2hits.resize(newSize);
1341 MakeClusterObsolete(icl);
1347 tcl[tcl.size() - 1].EndVtx = iv;
1350 mf::LogVerbatim(
"CC") <<
" modified cluster " << tcl[icl].ID <<
" -> " 1351 << tcl[tcl.size() - 1].ID;
1353 else if (tcl[icl].EndWir > vWire) {
1354 mf::LogVerbatim(
"CC") <<
"RefineVertexClusters: Write some EndVtx code";
1358 if (begClusters.size() > 0)
1359 mf::LogVerbatim(
"CC") <<
"RefineVertexClusters: Write some BeginVtx code";
1361 if (mindW < 0 && maxdW > 0) {
1366 unsigned short clsBigChg = 0;
1371 for (ii = 0; ii < begClusters.size(); ++ii) {
1372 icl = begClusters[ii];
1373 for (iht = 0; iht < tcl[icl].tclhits.size(); ++iht) {
1374 ihit = tcl[icl].tclhits[iht];
1375 if (fHits[ihit].Integral() > bigChg) {
1376 bigChg = fHits[ihit].Integral();
1380 if (fHits[ihit].
WireID().Wire < vWireLo)
break;
1384 for (ii = 0; ii < endClusters.size(); ++ii) {
1385 icl = endClusters[ii];
1386 for (iht = 0; iht < tcl[icl].tclhits.size(); ++iht) {
1387 ihit = tcl[icl].tclhits[tcl[icl].tclhits.size() - 1 - iht];
1388 if (fHits[ihit].Integral() > bigChg) {
1389 bigChg = fHits[ihit].Integral();
1393 if (fHits[ihit].
WireID().Wire > vWireHi)
break;
1398 mf::LogVerbatim(
"CC") <<
" moving vertex location to hit " << fHits[vtxHit].WireID().Wire
1399 <<
":" << (int)fHits[vtxHit].PeakTime() <<
" on cluster " 1400 << tcl[clsBigChg].ID;
1401 vtx[iv].Wire = fHits[vtxHit].WireID().Wire;
1402 vtx[iv].Time = fHits[vtxHit].PeakTime();
1403 vtx[iv].Fixed =
true;
1412 bool ClusterCrawlerAlg::VtxClusterSplit()
1417 vtxprt = (fDebugPlane >= 0 && fDebugWire == 5555);
1421 if (vtx.size() == 0)
return false;
1422 unsigned short tclsize = tcl.size();
1423 if (tclsize < 2)
return false;
1426 bool didSomething =
false;
1428 for (
unsigned short icl = 0; icl < tclsize; ++icl) {
1429 if (tcl[icl].ID < 0)
continue;
1430 if (tcl[icl].CTP != clCTP)
continue;
1432 if (tcl[icl].tclhits.size() < 5)
continue;
1435 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
1436 if (vtx[ivx].CTP != clCTP)
continue;
1438 if (vtx[ivx].NClusters == 0)
continue;
1440 if (tcl[icl].BeginVtx == ivx)
continue;
1441 if (tcl[icl].EndVtx == ivx)
continue;
1443 if (vtx[ivx].Wire < tcl[icl].EndWir)
continue;
1444 if (vtx[ivx].Wire > tcl[icl].BeginWir)
continue;
1446 float hiTime = tcl[icl].BeginTim;
1447 if (tcl[icl].EndTim > hiTime) hiTime = tcl[icl].EndTim;
1448 if (vtx[ivx].Time > hiTime + 5)
continue;
1449 float loTime = tcl[icl].BeginTim;
1450 if (tcl[icl].EndTim < loTime) loTime = tcl[icl].EndTim;
1451 if (vtx[ivx].Time < loTime - 5)
continue;
1455 mf::LogVerbatim(
"CC") <<
" Chk cluster ID " << tcl[icl].ID <<
" with vertex " << ivx;
1459 unsigned short nSplit = 0;
1460 unsigned short nLop = 0;
1462 for (
unsigned short ii = tcl[icl].tclhits.size() - 1; ii > 0; --ii) {
1463 iht = tcl[icl].tclhits[ii];
1465 if (fHits[iht].
WireID().Wire >= vtx[ivx].Wire) {
1468 mf::LogVerbatim(
"CC") <<
"Split cluster " << tcl[icl].ID <<
" at wire " 1469 << fHits[iht].WireID().Wire <<
" nSplit " << nSplit;
1475 if (ihvx < 0)
continue;
1476 if (fabs(fHits[ihvx].PeakTime() - vtx[ivx].Time) > 10)
continue;
1481 if (nSplit > tcl[icl].tclhits.size() / 2) { iclAng = tcl[icl].EndAng; }
1483 iclAng = tcl[icl].BeginAng;
1488 for (
unsigned short jcl = 0; jcl < tclsize; ++jcl) {
1489 if (tcl[jcl].ID < 0)
continue;
1490 if (tcl[jcl].CTP != clCTP)
continue;
1491 if (tcl[jcl].BeginVtx == ivx) {
1492 if (fabs(tcl[jcl].BeginAng - iclAng) > 0.4) {
1498 if (tcl[jcl].EndVtx == ivx) {
1499 if (fabs(tcl[jcl].EndAng - iclAng) > 0.4) {
1513 for (
unsigned short ii = 0; ii < nLop; ++ii) {
1514 unsigned int iht = fcl2hits[fcl2hits.size() - 1];
1516 fcl2hits.pop_back();
1521 MakeClusterObsolete(icl);
1523 if (!TmpStore())
continue;
1524 unsigned short newcl = tcl.size() - 1;
1525 tcl[newcl].BeginVtx = tcl[icl].BeginVtx;
1526 tcl[newcl].EndVtx = ivx;
1532 if (SplitCluster(icl, nSplit, ivx)) {
1533 tcl[tcl.size() - 1].ProcCode += 1000;
1534 tcl[tcl.size() - 2].ProcCode += 1000;
1538 didSomething =
true;
1544 return didSomething;
1549 void ClusterCrawlerAlg::MergeHits(
const unsigned int theHit,
bool& didMerge)
1563 if (theHit > fHits.size() - 1) {
return; }
1568 if (fHits[theHit].GoodnessOfFit() == 6666) {
1570 mf::LogVerbatim(
"CC") <<
"MergeHits Trying to merge already merged hit " 1573 <<
" theHit " << theHit;
1578 if (!mergeAvailable[theHit]) {
return; }
1583 std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(theHit);
1586 if (MultipletRange.second <= MultipletRange.first)
return;
1589 unsigned short nAvailable = 0;
1590 unsigned short nInClus = 0;
1591 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1592 if (jht == theHit)
continue;
1593 if (fHits[jht].GoodnessOfFit() == 6666)
continue;
1594 if (inClus[jht] != 0) {
1600 if (nAvailable == 0)
return;
1602 if (nInClus > 0)
return;
1608 short loTime = 9999;
1610 unsigned short nGaus = 1;
1613 unsigned short nclose = 0;
1615 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1616 if (inClus[jht] < 0)
continue;
1624 if (inClus[jht] != 0)
continue;
1626 if (arg < loTime) loTime = arg;
1628 if (arg > hiTime) hiTime = arg;
1629 if (jht != theHit) ++nGaus;
1631 if (jht != theHit && hitSep < 3) ++nclose;
1634 if (nGaus < 2)
return;
1637 const short int NewMultiplicity = hit.
Multiplicity() + 1 - nGaus;
1639 if (loTime < 0) loTime = 0;
1642 std::vector<double> signal(hiTime - loTime, 0.);
1645 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1647 if (jht != theHit) {
1649 if (inClus[jht] != 0)
continue;
1655 for (
unsigned short time = loTime; time < hiTime; ++time) {
1656 unsigned short indx = time - loTime;
1657 double arg = (other_hit.
PeakTime() - (double)time) / other_hit.
RMS();
1658 signal[indx] += other_hit.
PeakAmplitude() * exp(-0.5 * arg * arg);
1663 double sigsumt = 0.;
1664 for (
unsigned short time = loTime; time < hiTime; ++time) {
1665 sigsum += signal[time - loTime];
1666 sigsumt += signal[time - loTime] * time;
1672 double aveTime = sigsumt / sigsum;
1675 for (
unsigned short time = loTime; time < hiTime; ++time) {
1676 double dtime = time - aveTime;
1677 sigsumt += signal[time - loTime] * dtime * dtime;
1679 const float RMS = std::sqrt(sigsumt / sigsum);
1681 const float amplitude = chgsum * chgNorm / (2.507 * RMS);
1702 FixMultipletLocalIndices(MultipletRange.first, MultipletRange.second);
1708 void ClusterCrawlerAlg::FixMultipletLocalIndices(
size_t begin,
1710 short int multiplicity )
1722 if (multiplicity < 0) {
1724 for (
size_t iHit = begin; iHit <
end; ++iHit) {
1725 if (inClus[iHit] < 0)
continue;
1731 short int local_index = 0;
1732 for (
size_t iHit = begin; iHit <
end; ++iHit) {
1733 if (inClus[iHit] < 0)
continue;
1763 void ClusterCrawlerAlg::FindStarVertices()
1770 if (tcl.size() < 2)
return;
1775 vtxprt = (fDebugPlane == (int)plane && fDebugHit < 0);
1781 unsigned short vtxSizeIn = vtx.size();
1785 float dsl = 0, dth = 0;
1786 float es1 = 0, es2 = 0;
1787 float eth1 = 0, eth2 = 0;
1788 float bt1 = 0, bt2 = 0;
1789 float et1 = 0, et2 = 0;
1790 float bw1 = 0, bw2 = 0;
1791 float ew1 = 0, ew2 = 0;
1792 float lotime = 0, hitime = 0, nwirecut = 0;
1793 unsigned short tclsize = tcl.size();
1794 for (
unsigned short it1 = 0; it1 < tclsize - 1; ++it1) {
1796 if (tcl[it1].ID < 0)
continue;
1797 if (tcl[it1].CTP != clCTP)
continue;
1799 if (tcl[it1].tclhits.size() > 100) {
1800 dth = tcl[it1].BeginAng - tcl[it1].EndAng;
1803 es1 = tcl[it1].EndSlp;
1804 eth1 = tcl[it1].EndAng;
1805 ew1 = tcl[it1].EndWir;
1806 et1 = tcl[it1].EndTim;
1807 bw1 = tcl[it1].BeginWir;
1808 bt1 = tcl[it1].BeginTim;
1809 for (
unsigned short it2 = it1 + 1; it2 < tclsize; ++it2) {
1810 if (tcl[it2].ID < 0)
continue;
1811 if (tcl[it2].CTP != clCTP)
continue;
1813 if (tcl[it2].tclhits.size() > 100) {
1814 dth = tcl[it2].BeginAng - tcl[it2].EndAng;
1815 if (
std::abs(dth) < 0.05)
continue;
1817 es2 = tcl[it2].EndSlp;
1818 eth2 = tcl[it2].EndAng;
1819 ew2 = tcl[it2].EndWir;
1820 et2 = tcl[it2].EndTim;
1821 bw2 = tcl[it2].BeginWir;
1822 bt2 = tcl[it2].BeginTim;
1825 if (dth < 0.3)
continue;
1827 fvw = (et1 - ew1 * es1 - et2 + ew2 * es2) / dsl;
1829 if (fvw < ew1 || fvw > bw1)
continue;
1830 if (fvw < ew2 || fvw > bw2)
continue;
1832 mf::LogVerbatim(
"CC") <<
"Chk clusters " << tcl[it1].ID <<
" " << tcl[it2].ID
1833 <<
" topo5 vtx wire " << fvw;
1836 if (tcl[it1].tclhits.size() > tcl[it2].tclhits.size()) {
1837 if (tcl[it1].tclhits.size() > 20) {
1838 nwirecut = 0.5 * tcl[it1].tclhits.size();
1839 if ((fvw - ew1) > nwirecut)
continue;
1843 if (tcl[it2].tclhits.size() > 20) {
1844 nwirecut = 0.5 * tcl[it2].tclhits.size();
1845 if ((fvw - ew2) > nwirecut)
continue;
1848 fvt = et1 + (fvw - ew1) * es1;
1851 if (et1 < lotime) lotime = et1;
1852 if (bt1 < lotime) lotime = bt1;
1853 if (et2 < lotime) lotime = et2;
1854 if (bt2 < lotime) lotime = bt2;
1856 if (et1 > hitime) hitime = et1;
1857 if (bt1 > hitime) hitime = bt1;
1858 if (et2 > hitime) hitime = et2;
1859 if (bt2 > hitime) hitime = bt2;
1860 if (fvt < lotime || fvt > hitime)
continue;
1862 mf::LogVerbatim(
"CC") <<
" vertex time " << fvt <<
" lotime " << lotime <<
" hitime " 1864 unsigned int vw = (0.5 + fvw);
1866 unsigned int pos1 = 0;
1867 for (
unsigned short ii = 0; ii < tcl[it1].tclhits.size(); ++ii) {
1868 if (fHits[tcl[it1].tclhits[ii]].
WireID().Wire <= vw) {
1869 if (
std::abs(
int(fHits[tcl[it1].tclhits[ii]].PeakTime() - fvt)) < 10) pos1 = ii;
1874 if (pos1 == 0)
continue;
1875 unsigned short pos2 = 0;
1876 for (
unsigned short ii = 0; ii < tcl[it2].tclhits.size(); ++ii) {
1877 if (fHits[tcl[it2].tclhits[ii]].
WireID().Wire <= vw) {
1878 if (
std::abs(
int(fHits[tcl[it2].tclhits[ii]].PeakTime() - fvt)) < 10) pos2 = ii;
1883 if (pos2 == 0)
continue;
1885 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1886 if (
std::abs(fvw - vtx[iv].Wire) < 2 &&
std::abs(fvt - vtx[iv].Time) < 10)
continue;
1896 newvx.
Fixed =
false;
1897 vtx.push_back(newvx);
1898 unsigned short ivx = vtx.size() - 1;
1900 mf::LogVerbatim(
"CC") <<
" new vertex " << ivx <<
" cluster " << tcl[it1].ID
1901 <<
" split pos " << pos1;
1902 if (!SplitCluster(it1, pos1, ivx))
continue;
1903 tcl[tcl.size() - 1].ProcCode += 1000;
1904 tcl[tcl.size() - 2].ProcCode += 1000;
1906 mf::LogVerbatim(
"CC") <<
" new vertex " << ivx <<
" cluster " << tcl[it2].ID
1907 <<
" split pos " << pos2;
1908 if (!SplitCluster(it2, pos2, ivx))
continue;
1909 tcl[tcl.size() - 1].ProcCode += 1000;
1910 tcl[tcl.size() - 2].ProcCode += 1000;
1916 if (vtx.size() > vtxSizeIn) {
1920 VertexCluster(vtx.size() - 1);
1926 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1927 if (vtx[iv].CTP != clCTP)
continue;
1928 mf::LogVerbatim(
"CC") <<
"vtx " << iv <<
" wire " << vtx[iv].Wire <<
" time " 1929 << (int)vtx[iv].Time <<
" NClusters " << vtx[iv].NClusters <<
" topo " 1938 void ClusterCrawlerAlg::VertexCluster(
unsigned short iv)
1941 if (vtx[iv].NClusters == 0)
return;
1943 short dwb, dwe, dtb, dte;
1946 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
1947 if (tcl[icl].ID < 0)
continue;
1948 if (tcl[icl].CTP != vtx[iv].CTP)
continue;
1950 dwb = vtx[iv].Wire - tcl[icl].BeginWir;
1951 dtb = vtx[iv].Time - tcl[icl].BeginTim;
1952 dwe = vtx[iv].Wire - tcl[icl].EndWir;
1953 dte = vtx[iv].Time - tcl[icl].EndTim;
1955 float drb = dwb * dwb + dtb * dtb;
1956 float dre = dwe * dwe + dte * dte;
1958 bool bCloser = (drb < dre);
1962 if (tcl[icl].BeginChgNear > fChgNearCut)
continue;
1965 if (tcl[icl].EndChgNear > fChgNearCut)
continue;
1969 mf::LogVerbatim(
"CC") <<
"VertexCluster: Try icl ID " << tcl[icl].ID <<
" w vtx " << iv
1970 <<
" dwb " << dwb <<
" dwe " << dwe <<
" drb " << drb <<
" dre " 1971 << dre <<
" Begin closer? " << bCloser;
1973 if (tcl[icl].BeginVtx < 0 && bCloser && dwb > -3 && dwb < 3 && tcl[icl].EndVtx != iv) {
1974 sigOK = ChkSignal(tcl[icl].BeginWir, tcl[icl].BeginTim, vtx[iv].Wire, vtx[iv].Time);
1976 mf::LogVerbatim(
"CC") <<
" Attach cluster Begin to vtx? " << iv <<
" sigOK " << sigOK;
1979 mf::LogVerbatim(
"CC") <<
" check ClusterVertexChi " << ClusterVertexChi(icl, 0, iv);
1980 if (ClusterVertexChi(icl, 0, iv) < fVertex2DCut) {
1982 tcl[icl].BeginVtx = iv;
1984 if (vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
1985 tcl[icl].BeginVtx = -99;
1992 if (tcl[icl].EndVtx < 0 && !bCloser && dwe > -3 && dwe < 3 && tcl[icl].BeginVtx != iv) {
1993 sigOK = ChkSignal(tcl[icl].EndWir, tcl[icl].EndTim, vtx[iv].Wire, vtx[iv].Time);
1995 mf::LogVerbatim(
"CC") <<
" Attach cluster End to vtx? " << iv <<
" sigOK " << sigOK;
1998 mf::LogVerbatim(
"CC") <<
" check ClusterVertexChi " << ClusterVertexChi(icl, 1, iv);
1999 if (ClusterVertexChi(icl, 1, iv) < 3) {
2001 tcl[icl].EndVtx = iv;
2003 if (vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
2004 tcl[icl].EndVtx = -99;
2014 void ClusterCrawlerAlg::FitAllVtx(
CTP_t inCTP)
2017 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
2018 if (vtx[iv].CTP != inCTP)
continue;
2025 void ClusterCrawlerAlg::FindVertices()
2029 if (tcl.size() < 2)
return;
2032 std::vector<CluLen> clulens;
2034 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
2035 if (tcl[icl].ID < 0)
continue;
2036 if (tcl[icl].CTP != clCTP)
continue;
2037 if (tcl[icl].BeginVtx >= 0 && tcl[icl].EndVtx >= 0)
continue;
2039 clulen.length = tcl[icl].tclhits.size();
2040 clulens.push_back(clulen);
2042 if (
empty(clulens))
return;
2043 std::sort(clulens.begin(), clulens.end(),
greaterThan);
2045 float nwires = fNumWires;
2046 float maxtime = fMaxTime;
2048 unsigned short vtxSizeIn = vtx.size();
2050 vtxprt = (fDebugPlane == (short)plane && fDebugHit < 0);
2052 mf::LogVerbatim(
"CC") <<
"FindVertices plane " << plane <<
" pass " << pass;
2056 float es1 = 0, eth1 = 0, ew1 = 0, et1 = 0;
2057 float bs1 = 0, bth1 = 0, bw1 = 0, bt1 = 0;
2058 float es2 = 0, eth2 = 0, ew2 = 0, et2 = 0;
2059 float bs2 = 0, bth2 = 0, bw2 = 0, bt2 = 0;
2060 float dth = 0, dsl = 0, fvw = 0, fvt = 0;
2062 unsigned int vw = 0, pass1, pass2, ii1, it1, ii2, it2;
2064 for (ii1 = 0; ii1 < clulens.size() - 1; ++ii1) {
2065 it1 = clulens[ii1].index;
2066 es1 = tcl[it1].EndSlp;
2067 eth1 = tcl[it1].EndAng;
2068 ew1 = tcl[it1].EndWir;
2069 et1 = tcl[it1].EndTim;
2070 bs1 = tcl[it1].BeginSlp;
2071 bth1 = tcl[it1].BeginAng;
2072 bw1 = tcl[it1].BeginWir;
2073 bt1 = tcl[it1].BeginTim;
2074 pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
2075 for (ii2 = ii1 + 1; ii2 < clulens.size(); ++ii2) {
2076 it2 = clulens[ii2].index;
2080 if (tcl[it1].tclhits.size() < 5 && tcl[it2].tclhits.size() < 5)
continue;
2081 es2 = tcl[it2].EndSlp;
2082 eth2 = tcl[it2].EndAng;
2083 ew2 = tcl[it2].EndWir;
2084 et2 = tcl[it2].EndTim;
2085 bs2 = tcl[it2].BeginSlp;
2086 bth2 = tcl[it2].BeginAng;
2087 bw2 = tcl[it2].BeginWir;
2088 bt2 = tcl[it2].BeginTim;
2089 pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
2090 if (pass1 < pass2) { angcut = fKinkAngCut[pass2]; }
2092 angcut = fKinkAngCut[pass1];
2095 dth = fabs(eth1 - eth2);
2096 if (tcl[it1].EndVtx < 0 && tcl[it2].EndVtx < 0 && dth > 0.1) {
2099 fvw = (et1 - ew1 * es1 - et2 + ew2 * es2) / dsl;
2101 if (fvw > 0. && fvw < nwires) {
2106 if (vw >= fFirstWire - 1 && fvw <= ew1 + 3 && fvw <= ew2 + 3 && fvw > (ew1 - 10) &&
2108 fvt = et1 + (fvw - ew1) * es1;
2111 <<
"Chk clusters topo1 " << tcl[it1].ID <<
" " << tcl[it2].ID <<
" vtx wire " 2112 << vw <<
" time " << (int)fvt <<
" dth " << dth;
2113 if (fvt > 0 && fvt < maxtime) {
2117 SigOK = ChkSignal(vw, fvt, vw, fvt);
2121 SigOK = ChkSignal(vw, fvt, vw, fvt);
2124 if (SigOK) ChkVertex(fvw, fvt, it1, it2, 1);
2131 if (tcl[it1].EndVtx < 0 && tcl[it2].BeginVtx < 0 && dth > angcut) {
2133 if (fabs(ew1 - bw2) < 3 && fabs(et1 - bt2) < 500) { fvw = 0.5 * (ew1 + bw2); }
2135 fvw = (et1 - ew1 * es1 - bt2 + bw2 * bs2) / dsl;
2137 if (fvw > 0 && fvw < nwires) {
2142 if (fvw <= ew1 + 2 && fvw >= bw2 - 2) {
2143 fvt = et1 + (vw - ew1) * es1;
2144 fvt += bt2 + (vw - bw2) * bs2;
2148 <<
"Chk clusters topo2 " << tcl[it1].ID <<
" " << tcl[it2].ID <<
" vtx wire " 2149 << vw <<
" time " << (int)fvt <<
" dth " << dth;
2150 if (fvt > 0. && fvt < maxtime) {
2151 ChkVertex(fvw, fvt, it1, it2, 2);
2158 if (tcl[it1].BeginVtx < 0 && tcl[it2].EndVtx < 0 && dth > angcut) {
2160 if (fabs(bw1 - ew2) < 3 && fabs(bt1 - et2) < 500) { fvw = 0.5 * (bw1 + ew2); }
2162 fvw = (et2 - ew2 * es2 - bt1 + bw1 * bs1) / dsl;
2164 if (fvw > 0 && fvw < nwires) {
2168 if (fvw <= ew2 + 2 && fvw >= bw1 - 2) {
2169 fvt = et2 + (fvw - ew2) * es2;
2170 fvt += bt1 + (fvw - bw1) * es1;
2174 <<
"Chk clusters topo3 " << tcl[it1].ID <<
" " << tcl[it2].ID <<
" vtx wire " 2175 << vw <<
" time " << (int)fvt <<
" dth " << dth;
2176 if (fvt > 0. && fvt < maxtime) {
2177 ChkVertex(fvw, fvt, it1, it2, 3);
2184 if (tcl[it1].BeginVtx < 0 && tcl[it2].BeginVtx < 0 && dth > 0.1) {
2188 fvw = (bt1 - bw1 * bs1 - bt2 + bw2 * bs2) / dsl;
2190 mf::LogVerbatim(
"CC") <<
"Chk clusters topo4 " << bw1 <<
":" << (int)bt1 <<
" " << bw2
2191 <<
":" << (
int)bt2 <<
" fvw " << fvw <<
" nwires " << nwires;
2192 if (fvw > 0 && fvw < nwires) {
2198 if (tcl[it1].tclhits.size() < 2 * dwcut) dwcut = tcl[it1].tclhits.size() / 2;
2199 if (tcl[it2].tclhits.size() < 2 * dwcut) dwcut = tcl[it2].tclhits.size() / 2;
2200 if (fvw <= fLastWire + 1 && fvw >= bw1 - dwcut && fvw <= bw1 + dwcut &&
2201 fvw >= bw2 - dwcut && fvw <= bw1 + dwcut) {
2202 fvt = bt1 + (fvw - bw1) * bs1;
2205 <<
" vtx wire " << vw <<
" time " << fvt <<
" dth " << dth <<
" dwcut " << dwcut;
2206 if (fvt > 0. && fvt < maxtime) {
2210 SigOK = ChkSignal(vw, fvt, vw, fvt);
2214 SigOK = ChkSignal(vw, fvt, vw, fvt);
2217 if (SigOK) ChkVertex(fvw, fvt, it1, it2, 4);
2227 for (
unsigned short it = 0; it < tcl.size(); ++it) {
2228 if (tcl[it].ID < 0)
continue;
2229 if (tcl[it].CTP != clCTP)
continue;
2230 if (tcl[it].BeginVtx > -1 && tcl[it].BeginVtx == tcl[it].EndVtx) {
2231 unsigned short iv = tcl[it].BeginVtx;
2232 float dwir = tcl[it].BeginWir - vtx[iv].Wire;
2233 float dtim = tcl[it].BeginTim - vtx[iv].Time;
2234 float rbeg = dwir * dwir + dtim * dtim;
2235 dwir = tcl[it].EndWir - vtx[iv].Wire;
2236 dtim = tcl[it].EndTim - vtx[iv].Time;
2237 float rend = dwir * dwir + dtim * dtim;
2238 if (rend < rbeg) { tcl[it].EndVtx = -99; }
2240 tcl[it].BeginVtx = -99;
2245 if (vtx.size() > vtxSizeIn) FitAllVtx(clCTP);
2248 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
2249 if (vtx[ivx].CTP != clCTP)
continue;
2250 if (vtx[ivx].NClusters == 1) {
2251 vtx[ivx].NClusters = 0;
2252 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
2253 if (tcl[icl].CTP != clCTP)
continue;
2254 if (tcl[icl].BeginVtx == ivx) {
2255 tcl[icl].BeginVtx = -99;
2258 if (tcl[icl].EndVtx == ivx) {
2259 tcl[icl].EndVtx = -99;
2269 void ClusterCrawlerAlg::ClusterVertex(
unsigned short it)
2273 if (vtx.size() == 0)
return;
2275 unsigned short iv, jv;
2276 short dwib, dwjb, dwie, dwje;
2277 bool matchEnd, matchBegin;
2279 for (iv = 0; iv < vtx.size(); ++iv) {
2281 if (vtx[iv].CTP != clCTP)
continue;
2283 if (vtx[iv].NClusters == 0)
continue;
2287 if (tcl[it].tclhits.size() < 6) {
2289 dwib =
std::abs(vtx[iv].Wire - tcl[it].BeginWir);
2290 if (dwib > 2) dwib = 2;
2291 dwie =
std::abs(vtx[iv].Wire - tcl[it].EndWir);
2292 if (dwie > 2) dwie = 2;
2295 for (jv = 0; jv < vtx.size(); ++jv) {
2296 if (iv == jv)
continue;
2297 if (
std::abs(vtx[jv].Time - tcl[it].BeginTim) < 50) {
2298 if (
std::abs(vtx[jv].Wire - tcl[it].BeginWir) < dwjb)
2299 dwjb =
std::abs(vtx[jv].Wire - tcl[it].BeginWir);
2301 if (
std::abs(vtx[jv].Time - tcl[it].EndTim) < 50) {
2302 if (
std::abs(vtx[jv].Wire - tcl[it].EndWir) < dwje)
2303 dwje =
std::abs(vtx[jv].Wire - tcl[it].EndWir);
2306 matchEnd = tcl[it].EndVtx != iv && dwie < 3 && dwie < dwje && dwie < dwib;
2307 matchBegin = tcl[it].BeginVtx != iv && dwib < 3 && dwib < dwjb && dwib < dwie;
2310 matchEnd = tcl[it].EndVtx < 0 && vtx[iv].Wire <= tcl[it].EndWir + 2;
2311 matchBegin = tcl[it].BeginVtx < 0 && vtx[iv].Wire >= tcl[it].BeginWir - 2;
2315 mf::LogVerbatim(
"CC") <<
" Match End chi " << ClusterVertexChi(it, 1, iv) <<
" to vtx " 2316 << iv <<
" signalOK " 2318 vtx[iv].Wire, vtx[iv].Time, tcl[it].EndWir, tcl[it].EndTim);
2319 if (ClusterVertexChi(it, 1, iv) < fVertex2DCut &&
2320 ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].EndWir, tcl[it].EndTim)) {
2322 tcl[it].EndVtx = iv;
2326 mf::LogVerbatim(
"CC") <<
" Add End " << tcl[it].ID <<
" to vtx " << iv <<
" NClusters " 2327 << vtx[iv].NClusters;
2328 if (vtx[iv].ChiDOF < fVertex2DCut && vtx[iv].WireErr < fVertex2DWireErrCut)
return;
2330 mf::LogVerbatim(
"CC") <<
" Bad fit. ChiDOF " << vtx[iv].ChiDOF <<
" WireErr " 2331 << vtx[iv].WireErr <<
" Undo it";
2332 tcl[it].EndVtx = -99;
2339 mf::LogVerbatim(
"CC") <<
" Match Begin chi " << ClusterVertexChi(it, 0, iv) <<
" to vtx " 2340 << iv <<
" signalOK " 2341 << ChkSignal(vtx[iv].Wire,
2345 if (ClusterVertexChi(it, 0, iv) < fVertex2DCut &&
2346 ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].BeginWir, tcl[it].BeginTim)) {
2348 tcl[it].BeginVtx = iv;
2352 mf::LogVerbatim(
"CC") <<
" Add Begin " << tcl[it].ID <<
" to vtx " << iv
2353 <<
" NClusters " << vtx[iv].NClusters;
2354 if (vtx[iv].ChiDOF < fVertex2DCut && vtx[iv].WireErr < fVertex2DWireErrCut)
return;
2356 mf::LogVerbatim(
"CC") <<
" Bad fit. ChiDOF " << vtx[iv].ChiDOF <<
" WireErr " 2357 << vtx[iv].WireErr <<
" Undo it";
2358 tcl[it].BeginVtx = -99;
2366 void ClusterCrawlerAlg::ChkVertex(
float fvw,
2381 mf::LogVerbatim(
"CC") <<
" ChkVertex " << tcl[it1].EndWir <<
":" << (int)tcl[it1].EndTim
2382 <<
" - " << tcl[it1].BeginWir <<
":" << (
int)tcl[it1].BeginTim
2383 <<
" and " << tcl[it2].EndWir <<
":" << (int)tcl[it2].EndTim <<
" - " 2384 << tcl[it2].BeginWir <<
":" << (
int)tcl[it2].BeginTim <<
" topo " 2385 << topo <<
" fvw " << fvw <<
" fvt " << fvt;
2387 unsigned int vw = (
unsigned int)(0.5 + fvw);
2393 if (tcl[it1].tclhits.size() < 10 && tcl[it2].tclhits.size() < 10) {
2394 for (
unsigned short it = 0; it < tcl.size(); ++it) {
2395 if (it == it1 || it == it2)
continue;
2396 if (tcl[it].ID < 0)
continue;
2397 if (tcl[it].CTP != clCTP)
continue;
2398 if (tcl[it].tclhits.size() < 100)
continue;
2399 if (
std::abs(tcl[it].BeginAng - tcl[it].EndAng) > 0.1)
continue;
2401 if (vw < tcl[it].EndWir + 5)
continue;
2402 if (vw > tcl[it].BeginWir - 5)
continue;
2403 for (
unsigned short ii = 0; ii < tcl[it].tclhits.size(); ++ii) {
2404 iht = tcl[it].tclhits[ii];
2405 if (fHits[iht].
WireID().Wire <= vw) {
2406 if (
std::abs(fHits[iht].PeakTime() - fvt) < 60)
return;
2413 unsigned short nFitOK = 0;
2414 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
2415 if (vtx[iv].CTP != clCTP)
continue;
2417 if (PointVertexChi(fvw, fvt, iv) > 300)
continue;
2420 << PointVertexChi(fvw, fvt, iv);
2422 if ((topo == 1 || topo == 2) && tcl[it1].EndVtx < 0) {
2423 if (ChkSignal(vw, fvt, tcl[it1].EndWir, tcl[it1].EndTim)) {
2425 tcl[it1].EndVtx = iv;
2428 mf::LogVerbatim(
"CC") <<
" FitVtx " << iv <<
" WireErr " << vtx[iv].WireErr
2429 <<
" ChiDOF " << vtx[iv].ChiDOF;
2430 if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2433 tcl[it1].EndVtx = -99;
2438 else if ((topo == 3 || topo == 4) && tcl[it1].BeginVtx < 0) {
2439 if (ChkSignal(vw, fvt, tcl[it1].BeginWir, tcl[it1].BeginTim)) {
2440 tcl[it1].BeginVtx = iv;
2443 mf::LogVerbatim(
"CC") <<
" FitVtx " << iv <<
" WireErr " << vtx[iv].WireErr
2444 <<
" ChiDOF " << vtx[iv].ChiDOF;
2445 if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2448 tcl[it1].BeginVtx = -99;
2453 if ((topo == 1 || topo == 3) && tcl[it2].EndVtx < 0) {
2454 if (ChkSignal(vw, fvt, tcl[it2].EndWir, tcl[it2].EndTim)) {
2455 tcl[it2].EndVtx = iv;
2458 mf::LogVerbatim(
"CC") <<
" FitVtx " << iv <<
" WireErr " << vtx[iv].WireErr
2459 <<
" ChiDOF " << vtx[iv].ChiDOF;
2460 if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2463 tcl[it2].EndVtx = -99;
2468 else if ((topo == 2 || topo == 4) && tcl[it2].BeginVtx < 0) {
2469 if (ChkSignal(vw, fvt, tcl[it2].BeginWir, tcl[it2].BeginTim)) {
2470 tcl[it2].BeginVtx = iv;
2473 mf::LogVerbatim(
"CC") <<
" FitVtx " << iv <<
" WireErr " << vtx[iv].WireErr
2474 <<
" ChiDOF " << vtx[iv].ChiDOF;
2475 if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2478 tcl[it2].BeginVtx = -99;
2484 if (vtxprt)
mf::LogVerbatim(
"CC") <<
" Attached " << nFitOK <<
" clusters to vertex " << iv;
2492 if (topo == 1 || topo == 2) { SigOK = ChkSignal(vw, fvt, tcl[it1].EndWir, tcl[it1].EndTim); }
2494 SigOK = ChkSignal(vw, fvt, tcl[it1].BeginWir, tcl[it1].BeginTim);
2498 if (topo == 1 || topo == 3) { SigOK = ChkSignal(vw, fvt, tcl[it2].EndWir, tcl[it2].EndTim); }
2500 SigOK = ChkSignal(vw, fvt, tcl[it2].BeginWir, tcl[it2].BeginTim);
2509 newvx.
Fixed =
false;
2510 vtx.push_back(newvx);
2511 unsigned short iv = vtx.size() - 1;
2512 if (topo == 1 || topo == 2) {
2513 if (tcl[it1].EndVtx >= 0) {
2517 tcl[it1].EndVtx = iv;
2520 if (tcl[it1].BeginVtx >= 0) {
2524 tcl[it1].BeginVtx = iv;
2526 if (topo == 1 || topo == 3) {
2527 if (tcl[it2].EndVtx >= 0) {
2531 tcl[it2].EndVtx = iv;
2534 if (tcl[it2].BeginVtx >= 0) {
2538 tcl[it2].BeginVtx = iv;
2543 if (vtx[iv].ChiDOF < 5 && vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].TimeErr < 20) {
2545 mf::LogVerbatim(
"CC") <<
" New vtx " << iv <<
" in plane " << plane <<
" topo " << topo
2546 <<
" cls " << tcl[it1].ID <<
" " << tcl[it2].ID <<
" W:T " << (int)vw
2547 <<
":" << (
int)fvt <<
" NClusters " << vtx[iv].NClusters;
2549 if (fRefineVertexClusters) RefineVertexClusters(iv);
2553 mf::LogVerbatim(
"CC") <<
" Bad vtx fit " << vtx[iv].ChiDOF <<
" wire err " 2554 << vtx[iv].WireErr <<
" TimeErr " << vtx[iv].TimeErr;
2557 if (tcl[it1].BeginVtx == iv) tcl[it1].BeginVtx = -99;
2558 if (tcl[it1].EndVtx == iv) tcl[it1].EndVtx = -99;
2559 if (tcl[it2].BeginVtx == iv) tcl[it2].BeginVtx = -99;
2560 if (tcl[it2].EndVtx == iv) tcl[it2].EndVtx = -99;
2566 bool ClusterCrawlerAlg::ChkSignal(
unsigned int iht,
unsigned int jht)
2568 if (iht > fHits.size() - 1)
return false;
2569 if (jht > fHits.size() - 1)
return false;
2570 unsigned int wire1 = fHits[iht].WireID().Wire;
2571 float time1 = fHits[iht].PeakTime();
2572 unsigned int wire2 = fHits[jht].WireID().Wire;
2573 float time2 = fHits[jht].PeakTime();
2574 return ChkSignal(wire1, time1, wire2, time2);
2578 bool ClusterCrawlerAlg::ChkSignal(
unsigned int wire1,
2588 const float gausAmp[20] = {1, 0.99, 0.96, 0.90, 0.84, 0.75, 0.67, 0.58, 0.49, 0.40,
2589 0.32, 0.26, 0.20, 0.15, 0.11, 0.08, 0.06, 0.04, 0.03, 0.02};
2592 if (fMinAmp[plane] <= 0)
return true;
2595 unsigned int wireb = wire1;
2596 float timeb = time1;
2597 unsigned int wiree = wire2;
2598 float timee = time2;
2600 if (wiree > wireb) {
2606 if (wiree < fFirstWire || wiree > fLastWire)
return false;
2607 if (wireb < fFirstWire || wireb > fLastWire)
return false;
2612 bool oneWire =
false;
2613 float prTime, prTimeLo = 0, prTimeHi = 0;
2614 if (wireb == wiree) {
2616 if (time1 < time2) {
2626 slope = (timeb - timee) / (wireb - wiree);
2630 unsigned short nmissed = 0;
2631 for (
unsigned int wire = wiree; wire < wireb + 1; ++wire) {
2632 if (oneWire) { prTime = (prTimeLo + prTimeHi) / 2; }
2634 prTime = timee + (wire - wire0) * slope;
2637 if (WireHitRange[wire].first == -1)
continue;
2639 if (WireHitRange[wire].first == -2) ++nmissed;
2640 unsigned int firsthit = WireHitRange[wire].first;
2641 unsigned int lasthit = WireHitRange[wire].second;
2643 for (
unsigned int khit = firsthit; khit < lasthit; ++khit) {
2647 if (prTime < fHits[khit].StartTick())
continue;
2648 if (prTime > fHits[khit].EndTick())
continue;
2653 if (fHits[khit].PeakTime() - prTime > 500)
continue;
2654 bin =
std::abs(fHits[khit].PeakTime() - prTime) / fHits[khit].RMS();
2656 if (bin > 19)
continue;
2657 if (bin < 0)
continue;
2659 amp += fHits[khit].PeakAmplitude() * gausAmp[
bin];
2662 if (amp < fMinAmp[plane]) ++nmissed;
2664 if (nmissed > fAllowNoHitWire)
return false;
2670 bool ClusterCrawlerAlg::SplitCluster(
unsigned short icl,
unsigned short pos,
unsigned short ivx)
2674 if (tcl[icl].ID < 0)
return false;
2677 MakeClusterObsolete(icl);
2679 unsigned short ii, iclnew;
2685 clBeginSlp = tcl[icl].BeginSlp;
2686 clBeginSlpErr = tcl[icl].BeginSlpErr;
2687 clBeginAng = tcl[icl].BeginAng;
2688 clBeginWir = tcl[icl].BeginWir;
2689 clBeginTim = tcl[icl].BeginTim;
2690 clBeginChg = tcl[icl].BeginChg;
2692 clProcCode = tcl[icl].ProcCode;
2697 for (ii = 0; ii < pos; ++ii) {
2698 iht = tcl[icl].tclhits[ii];
2699 fcl2hits.push_back(iht);
2702 pass = tcl[icl].ProcCode - 10 * (tcl[icl].ProcCode / 10);
2703 if (pass > fNumPass - 1) pass = fNumPass - 1;
2706 clEndSlp = clpar[1];
2707 clEndSlpErr = clparerr[1];
2708 clEndAng = std::atan(fScaleF * clEndSlp);
2713 RestoreObsoleteCluster(icl);
2717 iclnew = tcl.size() - 1;
2718 tcl[iclnew].EndVtx = ivx;
2719 tcl[iclnew].BeginVtx = tcl[icl].BeginVtx;
2721 mf::LogVerbatim(
"CC") <<
"SplitCluster made cluster " << iclnew <<
" attached to Begin vtx " 2725 if (pos < tcl[icl].tclhits.size() - 3) {
2728 clEndSlp = tcl[icl].EndSlp;
2729 clEndSlpErr = tcl[icl].EndSlpErr;
2730 clEndAng = std::atan(fScaleF * clEndSlp);
2731 clEndWir = tcl[icl].EndWir;
2732 clEndTim = tcl[icl].EndTim;
2733 clEndChg = tcl[icl].EndChg;
2735 clProcCode = tcl[icl].ProcCode;
2740 bool didFit =
false;
2741 for (ii = pos; ii < tcl[icl].tclhits.size(); ++ii) {
2742 iht = tcl[icl].tclhits[ii];
2743 if (inClus[iht] != 0) {
2744 RestoreObsoleteCluster(icl);
2747 fcl2hits.push_back(iht);
2749 if (fcl2hits.size() == fMaxHitsFit[pass] || fcl2hits.size() == fMinHits[pass]) {
2751 clBeginSlp = clpar[1];
2752 clBeginAng = std::atan(fScaleF * clBeginSlp);
2753 clBeginSlpErr = clparerr[1];
2756 if ((
unsigned short)fcl2hits.size() == fNHitsAve[pass] + 1) {
2758 clBeginChg = fAveChg;
2766 clBeginChg = fAveChg;
2770 MakeClusterObsolete(tcl.size() - 1);
2771 RestoreObsoleteCluster(icl);
2775 iclnew = tcl.size() - 1;
2776 tcl[iclnew].BeginVtx = ivx;
2777 tcl[iclnew].EndVtx = tcl[icl].EndVtx;
2779 mf::LogVerbatim(
"CC") <<
"SplitCluster made cluster " << iclnew <<
" attached to End vtx " 2787 void ClusterCrawlerAlg::ChkMerge()
2792 if (tcl.size() < 2)
return;
2797 prt = (fDebugPlane == (short)plane && fDebugWire < 0);
2800 unsigned short it1, it2, nh1, pass1, pass2;
2801 float bs1, bth1, bt1, bc1, es1, eth1, et1, ec1;
2802 float bs2, bth2, bt2, bc2, es2, eth2, et2, ec2;
2803 int bw1, ew1, bw2, ew2, ndead;
2804 float dth, dw, angcut, chgrat, chgcut, dtim, timecut, bigslp;
2805 bool bothLong, NoVtx;
2807 int skipcut, tclsize = tcl.size();
2810 for (it1 = 0; it1 < tclsize - 1; ++it1) {
2812 if (tcl[it1].ID < 0)
continue;
2813 if (tcl[it1].CTP != clCTP)
continue;
2814 bs1 = tcl[it1].BeginSlp;
2816 bth1 = std::atan(fScaleF * bs1);
2818 bw1 = tcl[it1].BeginWir;
2819 bt1 = tcl[it1].BeginTim;
2820 bc1 = tcl[it1].BeginChg;
2821 es1 = tcl[it1].EndSlp;
2822 eth1 = tcl[it1].EndAng;
2823 ew1 = tcl[it1].EndWir;
2824 et1 = tcl[it1].EndTim;
2825 ec1 = tcl[it1].EndChg;
2826 nh1 = tcl[it1].tclhits.size();
2827 pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
2828 if (pass1 > fNumPass) pass1 = fNumPass;
2829 for (it2 = it1 + 1; it2 < tclsize; ++it2) {
2831 if (tcl[it1].ID < 0)
continue;
2832 if (tcl[it2].ID < 0)
continue;
2834 if (tcl[it2].CTP != clCTP)
continue;
2837 if (!ChkMergedClusterHitFrac(it1, it2)) {
continue; }
2838 bs2 = tcl[it2].BeginSlp;
2839 bth2 = std::atan(fScaleF * bs2);
2840 bw2 = tcl[it2].BeginWir;
2841 bt2 = tcl[it2].BeginTim;
2842 bc2 = tcl[it2].BeginChg;
2843 es2 = tcl[it2].EndSlp;
2844 eth2 = tcl[it2].EndAng;
2845 ew2 = tcl[it2].EndWir;
2846 et2 = tcl[it2].EndTim;
2847 ec2 = tcl[it2].EndChg;
2848 pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
2849 if (pass2 > fNumPass) pass2 = fNumPass;
2851 angcut = fKinkAngCut[pass1];
2852 if (fKinkAngCut[pass2] > angcut) angcut = fKinkAngCut[pass2];
2853 skipcut = fMaxWirSkip[pass1];
2854 if (fMaxWirSkip[pass2] > skipcut) skipcut = fMaxWirSkip[pass2];
2855 chgcut = fMergeChgCut[pass1];
2856 if (fMergeChgCut[pass2] > chgcut) chgcut = fMergeChgCut[pass2];
2858 bothLong = (nh1 > 100 && tcl[it2].tclhits.size() > 100);
2866 dw = ew1 - bw2 - ndead;
2868 NoVtx = (tcl[it1].EndVtx < 0) && (tcl[it2].BeginVtx < 0);
2869 if (prt && bw2 < (ew1 + maxOverlap))
2870 mf::LogVerbatim(
"CC") <<
"Chk1 ID1-2 " << tcl[it1].ID <<
"-" << tcl[it2].ID <<
" " << ew1
2871 <<
":" << (int)et1 <<
" " << bw2 <<
":" << (
int)bt2 <<
" dw " << dw
2872 <<
" ndead " << ndead <<
" skipcut " << skipcut <<
" dth " << dth
2873 <<
" angcut " << angcut;
2874 if (NoVtx && bw2 < (ew1 + maxOverlap) && dw < skipcut && dth < angcut) {
2875 chgrat = 2 * fabs(bc2 - ec1) / (bc2 + ec1);
2877 if (bothLong && dth < 0.05) chgrat = 0.;
2879 dtim = fabs(bt2 + (ew1 - bw2) * bs2 - et1);
2882 timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2884 mf::LogVerbatim(
"CC") <<
" dtim " << dtim <<
" timecut " << (int)timecut <<
" ec1 " 2885 << ec1 <<
" bc2 " << bc2 <<
" chgrat " << chgrat <<
" chgcut " 2886 << chgcut <<
" es1 " << es1 <<
" ChkSignal " 2887 << ChkSignal(ew1, et1, bw2, bt2);
2888 if (chgrat < chgcut && dtim < timecut) {
2890 if (ChkSignal(ew1, et1, bw2, bt2)) {
2891 DoMerge(it2, it1, 10);
2892 tclsize = tcl.size();
2900 dth = fabs(bth1 - eth2);
2902 dw = ew2 - bw1 - ndead;
2903 if (prt && bw1 < (ew2 + maxOverlap) && dw < skipcut)
2904 mf::LogVerbatim(
"CC") <<
"Chk2 ID1-2 " << tcl[it1].ID <<
"-" << tcl[it2].ID <<
" " << bw1
2905 <<
":" << (int)bt1 <<
" " << bw2 <<
":" << (
int)et2 <<
" dw " << dw
2906 <<
" ndead " << ndead <<
" skipcut " << skipcut <<
" dth " << dth
2907 <<
" angcut " << angcut;
2909 NoVtx = (tcl[it2].EndVtx < 0) && (tcl[it1].BeginVtx < 0);
2910 if (NoVtx && bw1 < (ew2 + maxOverlap) && dw < skipcut && dth < angcut) {
2911 chgrat = 2 * fabs((bc1 - ec2) / (bc1 + ec2));
2913 if (bothLong && dth < 0.05) chgrat = 0.;
2915 dtim =
std::abs(bt1 + (ew2 - bw1) * bs1 - et2);
2918 timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2920 mf::LogVerbatim(
"CC") <<
" dtim " << dtim <<
" err " << dtim <<
" timecut " 2921 << (int)timecut <<
" chgrat " << chgrat <<
" chgcut " << chgcut
2922 <<
" ChkSignal " << ChkSignal(bw1, bt1, ew2, et2);
2924 if (chgrat < chgcut && dtim < timecut) {
2925 if (ChkSignal(bw1, bt1, ew2, et2)) {
2926 DoMerge(it1, it2, 10);
2927 tclsize = tcl.size();
2933 if (bw2 < bw1 && ew2 > ew1) {
2936 dth = fabs(eth2 - eth1);
2937 dtim = fabs(et1 + (ew2 - ew1 - 1) * es1 - et2);
2940 timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2942 short nmiss1 = bw1 - ew1 + 1 - tcl[it1].tclhits.size();
2944 short nin2 = tcl[it2].tclhits.size();
2946 mf::LogVerbatim(
"CC") <<
"cl2: " << ew2 <<
":" << (int)et2 <<
" - " << bw2 <<
":" 2947 << (
int)bt2 <<
" within cl1 " << ew1 <<
":" << (int)et1 <<
" - " 2948 << bw1 <<
":" << (
int)bt1 <<
" ? dth " << dth <<
" dtim " << dtim
2949 <<
" nmissed " << nmiss1 <<
" timecut " << timecut
2950 <<
" FIX THIS CODE";
2955 if (dth < 1 && dtim < timecut && nmiss1 >= nin2) ChkMerge12(it1, it2, didit);
2957 tclsize = tcl.size();
2962 if (bw1 < bw2 && ew1 > ew2) {
2966 dtim =
std::abs(et2 + (ew1 - ew2 - 1) * es2 - et1);
2969 timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2971 short nmiss2 = bw2 - ew2 + 1 - tcl[it2].tclhits.size();
2973 short nin1 = tcl[it1].tclhits.size();
2975 mf::LogVerbatim(
"CC") <<
"cl1: " << ew1 <<
":" << (int)et1 <<
" - " << bw1 <<
":" 2976 << (
int)bt1 <<
" within cl2 " << ew2 <<
":" << (int)et2 <<
" - " 2977 << bw2 <<
":" << (
int)bt2 <<
" ? dth " << dth <<
" dtim " << dtim
2978 <<
" nmissed " << nmiss2 <<
" timecut " << timecut
2979 <<
" FIX THIS CODE";
2983 if (dth < 1 && dtim < timecut && nmiss2 >= nin1) ChkMerge12(it2, it1, didit);
2985 tclsize = tcl.size();
2990 if (tcl[it1].ID < 0)
break;
2992 if (tcl[it1].ID < 0)
continue;
2997 void ClusterCrawlerAlg::ChkMerge12(
unsigned short it1,
unsigned short it2,
bool& didit)
3007 if (prt)
mf::LogVerbatim(
"CC") <<
"ChkMerge12 " << tcl[it1].ID <<
" " << tcl[it2].ID;
3012 int ew1 = tcl[it1].
EndWir;
3013 int bw1 = tcl[it1].BeginWir;
3014 unsigned int iht,
hit;
3016 std::vector<unsigned int> cl1hits(bw1 + 1 - ew1);
3018 for (iht = 0; iht < cl1.
tclhits.size(); ++iht) {
3020 wire = fHits[hit].WireID().Wire;
3021 if (wire - ew1 < 0 || wire - ew1 > (
int)cl1hits.size()) {
return; }
3022 cl1hits[wire - ew1] = hit;
3024 unsigned int ew2 = tcl[it2].EndWir;
3025 float et2 = tcl[it2].EndTim;
3027 unsigned int wiron1 = 0;
3030 for (wire = ew2 - 1; wire > ew1; --wire) {
3031 if (cl1hits[wire - ew1] > 0) {
3037 if (prt)
mf::LogVerbatim(
"CC") <<
"chk next US wire " << wiron1 <<
" missed " << nmiss;
3038 if (wiron1 == 0)
return;
3039 if (nmiss > fMaxWirSkip[pass])
return;
3043 unsigned int hiton2;
3045 unsigned short nfit = 0;
3046 for (iht = 0; iht < tcl[it2].tclhits.size(); ++iht) {
3047 hiton2 = tcl[it2].tclhits[iht];
3048 wiron2 = fHits[hiton2].WireID().Wire;
3049 if (wiron2 < ew1 || wiron2 > bw1)
return;
3050 if (cl1hits[wiron2 - ew1] == 0) ++nfit;
3053 if (nfit < tcl[it2].tclhits.size())
return;
3056 unsigned short pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
3057 unsigned short pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
3058 unsigned short cpass = pass1;
3060 if (pass2 < pass1) cpass = pass2;
3063 if ((
int)wiron1 - ew1 < 0)
return;
3064 unsigned int hiton1 = cl1hits[wiron1 - ew1];
3065 if (hiton1 > fHits.size() - 1) {
return; }
3067 float timon1 = fHits[hiton1].PeakTime();
3068 float dtim =
std::abs(et2 + (wiron1 - ew2) * tcl[it2].EndSlp - timon1);
3069 if (dtim > fTimeDelta[cpass])
return;
3072 FitClusterMid(it1, hiton1, 3);
3073 if (clChisq > 20.)
return;
3076 float dth =
std::abs(std::atan(fScaleF * clpar[1]) - std::atan(fScaleF * tcl[it2].EndSlp));
3077 if (prt)
mf::LogVerbatim(
"CC") <<
"US dtheta " << dth <<
" cut " << fKinkAngCut[cpass];
3078 if (dth > fKinkAngCut[cpass])
return;
3080 float chgrat = 2 *
std::abs(fAveChg - tcl[it2].EndChg) / (fAveChg + tcl[it2].EndChg);
3081 if (prt)
mf::LogVerbatim(
"CC") <<
"US chgrat " << chgrat <<
" cut " << fMergeChgCut[pass];
3084 SigOK = ChkSignal(wiron1, timon1, ew2, et2);
3089 unsigned int bw2 = tcl[it2].BeginWir;
3090 float bt2 = tcl[it2].BeginTim;
3093 for (wire = bw2 + 1; wire < bw1; ++wire) {
3094 if (cl1hits[wire - ew1] > 0) {
3100 if (wiron1 == 0)
return;
3101 if (nmiss > fMaxWirSkip[pass])
return;
3104 hiton1 = cl1hits[wiron1 - ew1];
3105 if (hiton1 > fHits.size() - 1) {
return; }
3106 timon1 = fHits[hiton1].PeakTime();
3107 dtim =
std::abs(bt2 - (wiron1 - bw2) * tcl[it2].BeginSlp - timon1);
3108 if (dtim > fTimeDelta[cpass])
return;
3109 FitClusterMid(it1, hiton1, -3);
3110 if (clChisq > 20.)
return;
3112 dth =
std::abs(std::atan(fScaleF * clpar[1]) - std::atan(fScaleF * tcl[it2].BeginSlp));
3113 if (prt)
mf::LogVerbatim(
"CC") <<
"DS dtheta " << dth <<
" cut " << fKinkAngCut[cpass];
3114 if (dth > fKinkAngCut[cpass])
return;
3116 chgrat = 2 *
std::abs(fAveChg - tcl[it2].BeginChg) / (fAveChg + tcl[it2].BeginChg);
3117 if (prt)
mf::LogVerbatim(
"CC") <<
"DS chgrat " << chgrat <<
" cut " << fMergeChgCut[pass];
3119 SigOK = ChkSignal(wiron1, timon1, bw2, bt2);
3125 DoMerge(it1, it2, 100);
3130 void ClusterCrawlerAlg::DoMerge(
unsigned short it1,
unsigned short it2,
short inProcCode)
3137 if (cl1.
tclhits.size() < 3)
return;
3138 if (cl2.
tclhits.size() < 3)
return;
3140 unsigned int lowire, hiwire, whsize, ii, iht, indx;
3143 unsigned int fithit;
3158 whsize = hiwire + 2 - lowire;
3159 std::vector<int> wirehit(whsize, -1);
3161 for (ii = 0; ii < cl2.
tclhits.size(); ++ii) {
3163 indx = fHits[iht].WireID().Wire - lowire;
3164 wirehit[indx] = iht;
3167 for (ii = 0; ii < cl1.
tclhits.size(); ++ii) {
3169 indx = fHits[iht].WireID().Wire - lowire;
3170 wirehit[indx] = iht;
3174 for (std::vector<int>::reverse_iterator rit = wirehit.rbegin(); rit != wirehit.rend(); ++rit) {
3175 if (*rit < 0)
continue;
3176 fcl2hits.push_back(*rit);
3181 FitClusterMid(fcl2hits, fithit, nhitfit);
3182 if (clChisq > 5)
return;
3185 MakeClusterObsolete(it1);
3186 MakeClusterObsolete(it2);
3190 short del1Vtx = -99;
3191 short del2Vtx = -99;
3240 if (!TmpStore())
return;
3241 unsigned short itnew = tcl.size() - 1;
3243 mf::LogVerbatim(
"CC") <<
"DoMerge " << cl1.
ID <<
" " << cl2.
ID <<
" -> " << tcl[itnew].ID;
3245 tcl[itnew].ProcCode = inProcCode + pass;
3248 if (del1Vtx >= 0 && del1Vtx == del2Vtx) vtx[del1Vtx].NClusters = 0;
3250 tcl[itnew].BeginVtx = begVtx;
3251 tcl[itnew].EndVtx = endVtx;
3255 void ClusterCrawlerAlg::PrintVertices()
3260 if (vtx3.size() > 0) {
3263 <<
"****** 3D vertices ******************************************__2DVtx_Indx__*******\n";
3265 <<
"Vtx Cstat TPC Proc X Y Z XEr YEr ZEr pln0 pln1 pln2 Wire\n";
3266 for (
unsigned short iv = 0; iv < vtx3.size(); ++iv) {
3267 myprt <<
std::right << std::setw(3) << std::fixed << iv << std::setprecision(1);
3268 myprt <<
std::right << std::setw(7) << vtx3[iv].CStat;
3269 myprt <<
std::right << std::setw(5) << vtx3[iv].TPC;
3270 myprt <<
std::right << std::setw(5) << vtx3[iv].ProcCode;
3271 myprt <<
std::right << std::setw(8) << vtx3[iv].X;
3272 myprt <<
std::right << std::setw(8) << vtx3[iv].Y;
3273 myprt <<
std::right << std::setw(8) << vtx3[iv].Z;
3274 myprt <<
std::right << std::setw(5) << vtx3[iv].XErr;
3275 myprt <<
std::right << std::setw(5) << vtx3[iv].YErr;
3276 myprt <<
std::right << std::setw(5) << vtx3[iv].ZErr;
3277 myprt <<
std::right << std::setw(5) << vtx3[iv].Ptr2D[0];
3278 myprt <<
std::right << std::setw(5) << vtx3[iv].Ptr2D[1];
3279 myprt <<
std::right << std::setw(5) << vtx3[iv].Ptr2D[2];
3280 myprt <<
std::right << std::setw(5) << vtx3[iv].Wire;
3281 if (vtx3[iv].Wire < 0) { myprt <<
" Matched in all planes"; }
3283 myprt <<
" Incomplete";
3289 if (vtx.size() > 0) {
3291 myprt <<
"************ 2D vertices ************\n";
3292 myprt <<
"Vtx CTP wire error tick error ChiDOF NCl topo cluster IDs\n";
3293 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
3294 if (fDebugPlane < 3 && fDebugPlane != (
int)vtx[iv].CTP)
continue;
3295 myprt <<
std::right << std::setw(3) << std::fixed << iv << std::setprecision(1);
3296 myprt <<
std::right << std::setw(6) << vtx[iv].CTP;
3297 myprt <<
std::right << std::setw(8) << vtx[iv].Wire <<
" +/- ";
3298 myprt <<
std::right << std::setw(4) << vtx[iv].WireErr;
3299 myprt <<
std::right << std::setw(8) << vtx[iv].Time <<
" +/- ";
3300 myprt <<
std::right << std::setw(4) << vtx[iv].TimeErr;
3301 myprt <<
std::right << std::setw(8) << vtx[iv].ChiDOF;
3302 myprt <<
std::right << std::setw(5) << vtx[iv].NClusters;
3303 myprt <<
std::right << std::setw(6) << vtx[iv].Topo;
3306 for (
unsigned short ii = 0; ii < tcl.size(); ++ii) {
3307 if (fDebugPlane < 3 && fDebugPlane != (
int)tcl[ii].CTP)
continue;
3308 if (tcl[ii].ID < 0)
continue;
3309 if (tcl[ii].BeginVtx == (
short)iv) myprt <<
std::right << std::setw(4) << tcl[ii].ID;
3310 if (tcl[ii].EndVtx == (
short)iv) myprt <<
std::right << std::setw(4) << tcl[ii].ID;
3327 float aveRMS, aveRes;
3328 myprt <<
"*************************************** Clusters " 3329 "*********************************************************************\n";
3330 myprt <<
" ID CTP nht Stop Proc beg_W:T bAng bSlp Err bChg end_W:T eAng eSlp " 3331 "Err eChg bVx eVx aveRMS Qual cnt\n";
3332 for (
unsigned short ii = 0; ii < tcl.size(); ++ii) {
3334 if (fDebugPlane < 3 && fDebugPlane != (
int)tcl[ii].CTP)
continue;
3335 myprt <<
std::right << std::setw(4) << tcl[ii].ID;
3336 myprt <<
std::right << std::setw(3) << tcl[ii].CTP;
3337 myprt <<
std::right << std::setw(5) << tcl[ii].tclhits.size();
3338 myprt <<
std::right << std::setw(4) << tcl[ii].StopCode;
3339 myprt <<
std::right << std::setw(6) << tcl[ii].ProcCode;
3340 unsigned int iTime = tcl[ii].BeginTim;
3341 myprt <<
std::right << std::setw(6) << tcl[ii].BeginWir <<
":" << iTime;
3342 if (iTime < 10) { myprt <<
" "; }
3343 else if (iTime < 100) {
3346 else if (iTime < 1000)
3348 myprt <<
std::right << std::setw(7) << std::fixed << std::setprecision(2) << tcl[ii].BeginAng;
3349 if (
std::abs(tcl[ii].BeginSlp) < 100) {
3350 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(2)
3351 << tcl[ii].BeginSlp;
3354 myprt <<
std::right << std::setw(6) << (int)tcl[ii].BeginSlp;
3356 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(2)
3357 << tcl[ii].BeginSlpErr;
3358 myprt <<
std::right << std::setw(5) << (int)tcl[ii].BeginChg;
3359 iTime = tcl[ii].EndTim;
3360 myprt <<
std::right << std::setw(6) << tcl[ii].EndWir <<
":" << iTime;
3361 if (iTime < 10) { myprt <<
" "; }
3362 else if (iTime < 100) {
3365 else if (iTime < 1000)
3367 myprt <<
std::right << std::setw(7) << std::fixed << std::setprecision(2) << tcl[ii].EndAng;
3368 if (
std::abs(tcl[ii].EndSlp) < 100) {
3369 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(2) << tcl[ii].EndSlp;
3372 myprt <<
std::right << std::setw(6) << (int)tcl[ii].EndSlp;
3374 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(2)
3375 << tcl[ii].EndSlpErr;
3376 myprt <<
std::right << std::setw(5) << (int)tcl[ii].EndChg;
3377 myprt <<
std::right << std::setw(5) << tcl[ii].BeginVtx;
3378 myprt <<
std::right << std::setw(5) << tcl[ii].EndVtx;
3380 unsigned int iht = 0;
3381 for (
unsigned short jj = 0; jj < tcl[ii].tclhits.size(); ++jj) {
3382 iht = tcl[ii].tclhits[jj];
3383 aveRMS += fHits[iht].RMS();
3385 aveRMS /= (float)tcl[ii].tclhits.size();
3386 myprt <<
std::right << std::setw(5) << std::fixed << std::setprecision(1) << aveRMS;
3389 unsigned int hit0, hit1, hit2, cnt = 0;
3391 for (
unsigned short iht = 1; iht < tcl[ii].tclhits.size() - 1; ++iht) {
3392 hit1 = tcl[ii].tclhits[iht];
3393 hit0 = tcl[ii].tclhits[iht - 1];
3394 hit2 = tcl[ii].tclhits[iht + 1];
3396 if (fHits[hit1].
WireID().Wire + 1 != fHits[hit0].WireID().Wire)
continue;
3397 if (fHits[hit2].
WireID().Wire + 1 != fHits[hit1].WireID().Wire)
continue;
3398 arg = (fHits[hit0].PeakTime() + fHits[hit2].PeakTime()) / 2 - fHits[hit1].PeakTime();
3399 aveRes += arg * arg;
3403 aveRes /= (float)cnt;
3404 aveRes = sqrt(aveRes);
3406 aveRes /= (aveRMS * fHitErrFac);
3407 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(1) << aveRes;
3408 myprt <<
std::right << std::setw(5) << std::fixed << cnt;
3412 myprt <<
std::right << std::setw(5) << std::fixed << cnt;
3420 void ClusterCrawlerAlg::TmpGet(
unsigned short it1)
3425 if (it1 > tcl.size())
return;
3427 clBeginSlp = tcl[it1].BeginSlp;
3428 clBeginSlpErr = tcl[it1].BeginSlpErr;
3429 clBeginAng = tcl[it1].BeginAng;
3430 clBeginWir = tcl[it1].BeginWir;
3431 clBeginTim = tcl[it1].BeginTim;
3432 clBeginChg = tcl[it1].BeginChg;
3433 clBeginChgNear = tcl[it1].BeginChgNear;
3434 clEndSlp = tcl[it1].EndSlp;
3435 clEndSlpErr = tcl[it1].EndSlpErr;
3436 clEndAng = tcl[it1].EndAng;
3437 clEndWir = tcl[it1].EndWir;
3438 clEndTim = tcl[it1].EndTim;
3439 clEndChg = tcl[it1].EndChg;
3440 clEndChgNear = tcl[it1].EndChgNear;
3441 clStopCode = tcl[it1].StopCode;
3442 clProcCode = tcl[it1].ProcCode;
3443 clCTP = tcl[it1].CTP;
3444 fcl2hits = tcl[it1].tclhits;
3448 bool ClusterCrawlerAlg::TmpStore()
3451 if (fcl2hits.size() < 2)
return false;
3452 if (fcl2hits.size() > fHits.size())
return false;
3454 if (NClusters == SHRT_MAX)
return false;
3458 unsigned int hit0 = fcl2hits[0];
3460 unsigned int tCST = fHits[hit0].WireID().Cryostat;
3461 unsigned int tTPC = fHits[hit0].WireID().TPC;
3462 unsigned int tPlane = fHits[hit0].WireID().Plane;
3463 unsigned int lastWire = 0;
3465 for (
unsigned short it = 0; it < fcl2hits.size(); ++it) {
3467 if (inClus[hit] != 0) {
3472 if (fHits[hit].
WireID().Cryostat != tCST || fHits[hit].WireID().TPC != tTPC ||
3473 fHits[hit].WireID().Plane != tPlane) {
3478 if (clProcCode < 900 && it > 0 && fHits[hit].
WireID().Wire >= lastWire) {
3482 lastWire = fHits[hit].WireID().Wire;
3483 inClus[hit] = NClusters;
3489 if (clEndChg <= 0) {
3491 unsigned int ih0 = fcl2hits.size() - 2;
3492 hit = fcl2hits[ih0];
3493 clEndChg = fHits[hit].Integral();
3494 hit = fcl2hits[ih0 - 1];
3495 clEndChg += fHits[hit].Integral();
3496 clEndChg = clEndChg / 2.;
3498 if (clBeginChg <= 0) {
3501 clBeginChg = fHits[hit].Integral();
3503 clBeginChg += fHits[hit].Integral();
3504 clBeginChg = clBeginChg / 2.;
3508 hit = fcl2hits[fcl2hits.size() - 1];
3513 clstr.
ID = NClusters;
3516 clstr.
BeginAng = std::atan(fScaleF * clBeginSlp);
3517 clstr.
BeginWir = fHits[hit0].WireID().Wire;
3518 clstr.
BeginTim = fHits[hit0].PeakTime();
3523 clstr.
EndAng = std::atan(fScaleF * clEndSlp);
3524 clstr.
EndWir = fHits[hit].WireID().Wire;
3525 clstr.
EndTim = fHits[hit].PeakTime();
3534 tcl.push_back(clstr);
3540 void ClusterCrawlerAlg::LACrawlUS()
3545 unsigned int dhit = fcl2hits[0];
3546 short dwir = fHits[dhit].WireID().Wire;
3549 if (fDebugPlane == (
short)plane && dwir == fDebugWire && fDebugHit > 0)
3550 prt =
std::abs(fHits[dhit].PeakTime() - fDebugHit) < 40;
3554 myprt <<
"******************* LACrawlUS PASS " << pass <<
" Hits ";
3555 for (
unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3556 unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3557 myprt << fHits[iht].WireID().Wire <<
":" << (int)fHits[iht].PeakTime() <<
" ";
3566 unsigned short kinkOnWire = 0;
3567 unsigned int it = fcl2hits.size() - 1;
3568 unsigned int lasthit = fcl2hits[it];
3569 unsigned int lastwire = fHits[lasthit].WireID().Wire;
3570 unsigned int prevHit, prevWire;
3571 bool ChkCharge =
false;
3572 for (
unsigned int nextwire = lastwire - 1; nextwire >= fFirstWire; --nextwire) {
3574 mf::LogVerbatim(
"CC") <<
"LACrawlUS: next wire " << nextwire <<
" HitRange " 3575 << WireHitRange[nextwire].first;
3577 if (CrawlVtxChk(nextwire)) {
3583 AddLAHit(nextwire, ChkCharge, HitOK, SigOK);
3585 mf::LogVerbatim(
"CC") <<
"LACrawlUS: HitOK " << HitOK <<
" SigOK " << SigOK
3586 <<
" nmissed SigOK " << nmissed <<
" cut " << fAllowNoHitWire;
3587 if (SigOK) nmissed = 0;
3590 if (nmissed > fAllowNoHitWire) {
3599 prevHit = fcl2hits[fcl2hits.size() - 2];
3600 prevWire = fHits[prevHit].WireID().Wire;
3601 if (prevWire > nextwire + 2) {
3602 if (!ChkSignal(fcl2hits[fcl2hits.size() - 1], fcl2hits[fcl2hits.size() - 2])) {
3612 if (fcl2hits.size() == 4) {
3614 for (
unsigned short kk = 0; kk < fcl2hits.size() - 1; ++kk) {
3615 unsigned int hit = fcl2hits[kk];
3616 if (mergeAvailable[hit]) MergeHits(hit, didMerge);
3620 clBeginSlp = clpar[1];
3625 unsigned short chsiz = chifits.size() - 1;
3627 if (chsiz < 6)
continue;
3628 if (fKinkChiRat[pass] <= 0)
continue;
3629 if (chifits.size() != fcl2hits.size()) {
3630 mf::LogError(
"CC") <<
"LACrawlUS: chifits size error " << chifits.size() <<
" " 3635 mf::LogVerbatim(
"CC") <<
"Kink chk " << chifits[chsiz] <<
" " << chifits[chsiz - 1] <<
" " 3636 << chifits[chsiz - 2] <<
" " << chifits[chsiz - 3];
3637 if (chifits[chsiz - 1] > fKinkChiRat[pass] * chifits[chsiz - 2] &&
3638 chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz - 1]) {
3640 unsigned int ih0 = fcl2hits.size() - 1;
3641 unsigned int hit0 = fcl2hits[ih0];
3642 unsigned int ih2 = ih0 - 2;
3643 unsigned int hit2 = fcl2hits[ih2];
3644 float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
3645 float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
3646 float th02 = std::atan(fScaleF * dt02 / dw02);
3648 unsigned int ih3 = ih2 - 1;
3649 unsigned int hit3 = fcl2hits[ih3];
3650 unsigned int ih5 = ih3 - 2;
3651 unsigned int hit5 = fcl2hits[ih5];
3652 float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
3653 float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
3654 float th35 = std::atan(fScaleF * dt35 / dw35);
3657 mf::LogVerbatim(
"CC") <<
" Kink angle " << std::setprecision(3) << dth <<
" cut " 3658 << fKinkAngCut[pass];
3659 if (dth > fKinkAngCut[pass]) {
3665 if (kinkOnWire > 0) {
3666 if (kinkOnWire - nextwire < 4) {
3669 <<
"Hit a second kink. kinkOnWire = " << kinkOnWire <<
" Stopping";
3675 kinkOnWire = nextwire;
3681 CheckClusterHitFrac(prt);
3684 if (prt)
mf::LogVerbatim(
"CC") <<
"LACrawlUS done. Nhits = " << fcl2hits.size();
3689 void ClusterCrawlerAlg::CrawlUS()
3693 if (fcl2hits.size() < 2)
return;
3695 unsigned int dhit = fcl2hits[0];
3696 int dwir = fHits[dhit].WireID().Wire;
3700 if (fDebugPlane == (
short)plane && dwir == fDebugWire && fDebugHit > 0)
3701 prt =
std::abs(fHits[dhit].PeakTime() - fDebugHit) < 20;
3705 myprt <<
"******************* Start CrawlUS on pass " << pass <<
" Hits: ";
3706 for (
unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3707 unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3708 myprt << fHits[iht].WireID().Wire <<
":" << (int)fHits[iht].PeakTime() <<
" ";
3719 short nHitAfterSkip = 0;
3720 bool DidaSkip =
false;
3721 bool PostSkip =
false;
3722 unsigned int it = fcl2hits.size() - 1;
3723 unsigned int lasthit = fcl2hits[it];
3724 if (lasthit > fHits.size() - 1) {
3725 mf::LogError(
"CC") <<
"CrawlUS bad lasthit " << lasthit;
3728 unsigned int lastwire = fHits[lasthit].WireID().Wire;
3729 if (prt)
mf::LogVerbatim(
"CC") <<
"CrawlUS: last wire " << lastwire <<
" hit " << lasthit;
3731 unsigned int lastWireWithSignal = lastwire;
3732 unsigned short nDroppedHit = 0;
3734 for (
unsigned int nextwire = lastwire - 1; nextwire > fFirstWire; --nextwire) {
3736 mf::LogVerbatim(
"CC") <<
"CrawlUS: next wire " << nextwire <<
" HitRange " 3737 << WireHitRange[nextwire].first;
3739 if (CrawlVtxChk(nextwire)) {
3745 if (
std::abs(clpar[1]) > fLAClusSlopeCut) {
3746 if (prt)
mf::LogVerbatim(
"CC") <<
">>>>> CrawlUS: Switching to LACrawlUS";
3751 AddHit(nextwire, HitOK, SigOK);
3753 mf::LogVerbatim(
"CC") <<
"CrawlUS: HitOK " << HitOK <<
" SigOK " << SigOK <<
" nmissed " 3755 if (SigOK) lastWireWithSignal = nextwire;
3762 if (PostSkip && nmissed > fMinWirAfterSkip[pass]) {
3764 if ((
int)(fcl2hits.size() - nHitAfterSkip) < 4) {
3768 if (prt)
mf::LogVerbatim(
"CC") <<
" PostSkip && nmissed = " << nmissed;
3770 FclTrimUS(nHitAfterSkip);
3772 if (clChisq > 90.) {
3787 lasthit = fcl2hits[fcl2hits.size() - 1];
3788 if ((lastWireWithSignal - nextwire) > fAllowNoHitWire) {
3791 <<
"No hit or signal on wire " << nextwire <<
" last wire with signal " 3792 << lastWireWithSignal <<
" exceeding fAllowNoHitWire " << fAllowNoHitWire
3800 mf::LogVerbatim(
"CC") <<
" CrawlUS check clChisq " << clChisq <<
" cut " << fChiCut[pass];
3801 if (clChisq > fChiCut[pass]) {
3802 if (fcl2hits.size() < 3) {
3807 if (prt)
mf::LogVerbatim(
"CC") <<
"ADD- Bad clChisq " << clChisq <<
" dropping hit";
3811 if (nDroppedHit > 4) {
3814 <<
" Too many dropped hits: " << nDroppedHit <<
" Stop crawling";
3817 if (clChisq > fChiCut[pass]) {
3820 <<
" Bad clChisq " << clChisq <<
" after dropping hit. Stop crawling";
3828 if (chifits.size() > 5 && fKinkChiRat[pass] > 0) {
3829 if (chifits.size() != fcl2hits.size()) {
3830 mf::LogError(
"CC") <<
"CrawlUS: chifits size error " << chifits.size() <<
" " 3834 unsigned short chsiz = chifits.size() - 1;
3836 mf::LogVerbatim(
"CC") <<
"Kink chk " << chifits[chsiz] <<
" " << chifits[chsiz - 1]
3837 <<
" " << chifits[chsiz - 2] <<
" " << chifits[chsiz - 3];
3838 if (chifits[chsiz - 1] > fKinkChiRat[pass] * chifits[chsiz - 2] &&
3839 chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz - 1]) {
3840 if (fcl2hits.size() != chifits.size()) {
3841 mf::LogError(
"CC") <<
"bad kink check size " << chifits.size() <<
" " 3842 << fcl2hits.size() <<
" plane " << plane <<
" cluster " << dwir
3846 if (EndKinkAngle() > fKinkAngCut[pass]) {
3849 <<
"******************* Stopped tracking - kink angle " << EndKinkAngle() <<
" > " 3850 << fKinkAngCut[pass] <<
" Removing 3 hits";
3860 if (fcl2hits.size() == fMaxHitsFit[pass] || fcl2hits.size() == fMinHits[pass]) {
3861 clBeginSlp = clpar[1];
3862 clBeginSlpErr = clparerr[1];
3865 if (clBeginChg <= 0 && fAveChg > 0) {
3866 clBeginChg = fAveChg;
3882 if (nHitAfterSkip == fMinWirAfterSkip[pass]) PostSkip =
false;
3885 if (clChisq > fChiCut[pass]) {
3889 unsigned short lopped = 0;
3890 for (
unsigned short nlop = 0; nlop < 4; ++nlop) {
3891 unsigned short cfsize = chifits.size() - 1;
3892 chirat = chifits[cfsize] / chifits[cfsize - 1];
3895 <<
"chirat " << chirat <<
" last hit " << fcl2hits[fcl2hits.size() - 1];
3896 if (chirat < 1.2)
break;
3897 if (prt)
mf::LogVerbatim(
"CC") <<
"<<ADD- Bad chisq. Bad chirat " << chirat;
3900 if (fcl2hits.size() < 6)
break;
3901 if (chifits.size() < 6)
break;
3903 if (fcl2hits.size() < 6) {
3905 if (prt)
mf::LogVerbatim(
"CC") <<
"Bad fit chisq - short cluster. Break";
3908 if (lopped == 0 && fcl2hits.size() > 5) {
3916 mf::LogVerbatim(
"CC") <<
"Bad fit chisq - removed " << lopped <<
" hits. Continue";
3921 mf::LogVerbatim(
"CC") <<
"******************* CrawlUS normal stop. size " << fcl2hits.size();
3925 if (fcl2hits.size() > 5) {
3928 mf::LogVerbatim(
"CC") <<
"EndKinkAngle check " << EndKinkAngle() <<
" cut " 3929 << fKinkAngCut[pass];
3930 if (EndKinkAngle() > fKinkAngCut[pass]) {
3939 if ((
unsigned short)fcl2hits.size() > fMinWirAfterSkip[pass] + 3) {
3940 unsigned int ih0 = fcl2hits.size() - 1;
3941 unsigned int hit0 = fcl2hits[ih0];
3942 unsigned int uswir = fHits[hit0].WireID().Wire;
3943 unsigned int nxtwir;
3944 unsigned short nAdjHit = 0;
3945 for (
unsigned short ii = ih0 - 1; ii > 0; --ii) {
3946 nxtwir = fHits[fcl2hits[ii]].WireID().Wire;
3948 if (nxtwir != uswir + 1)
break;
3950 if (nAdjHit == fMinWirAfterSkip[pass])
break;
3954 if (nAdjHit < fMinWirAfterSkip[pass]) {
3955 if (prt)
mf::LogVerbatim(
"CC") <<
"fMinWirAfterSkip removes " << nAdjHit <<
" hits ";
3962 if (!reFit && fcl2hits.size() > 3) {
3963 float chirat = chifits[chifits.size() - 1] / chifits[chifits.size() - 2];
3965 mf::LogVerbatim(
"CC") <<
"Last hit chirat " << chirat <<
" cut " << fKinkChiRat[pass];
3967 mf::LogVerbatim(
"CC") <<
"Check " << clChisq <<
" " << chifits[chifits.size() - 1] <<
" " 3968 << chifits[chifits.size() - 2];
3969 if (chirat > fKinkChiRat[pass]) {
3980 CheckClusterHitFrac(prt);
3982 mf::LogVerbatim(
"CC") <<
"******************* CrawlUS done. Size " << fcl2hits.size()
3983 <<
" min length for this pass " << fMinHits[pass];
3989 float ClusterCrawlerAlg::EndKinkAngle()
3993 unsigned int ih0 = fcl2hits.size() - 1;
3994 unsigned int hit0 = fcl2hits[ih0];
3995 unsigned int ih2 = ih0 - 2;
3996 unsigned int hit2 = fcl2hits[ih2];
3997 float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
3998 float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
3999 float th02 = std::atan(fScaleF * dt02 / dw02);
4001 unsigned int ih3 = ih2 - 1;
4002 unsigned int hit3 = fcl2hits[ih3];
4003 unsigned int ih5 = ih3 - 2;
4004 unsigned int hit5 = fcl2hits[ih5];
4005 float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
4006 float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
4007 float th35 = std::atan(fScaleF * dt35 / dw35);
4012 bool ClusterCrawlerAlg::ChkMergedClusterHitFrac(
unsigned short it1,
unsigned short it2)
4016 if (it1 > tcl.size() - 1)
return false;
4017 if (it2 > tcl.size() - 1)
return false;
4018 unsigned int eWire = 99999;
4019 unsigned int bWire = 0, wire;
4020 if (tcl[it1].BeginWir > bWire) bWire = tcl[it1].BeginWir;
4021 if (tcl[it2].BeginWir > bWire) bWire = tcl[it2].BeginWir;
4022 if (tcl[it1].EndWir < eWire) eWire = tcl[it1].EndWir;
4023 if (tcl[it2].EndWir < eWire) eWire = tcl[it2].EndWir;
4024 unsigned int mergedClusterLength = bWire - eWire + 1;
4026 std::vector<bool> cHits(mergedClusterLength,
false);
4028 unsigned int ii, iht, indx;
4029 for (ii = 0; ii < tcl[it1].tclhits.size(); ++ii) {
4030 iht = tcl[it1].tclhits[ii];
4031 if (iht > fHits.size() - 1) {
4032 mf::LogError(
"CC") <<
"ChkMergedClusterHitFrac bad iht ";
4035 indx = fHits[iht].WireID().Wire - eWire;
4038 for (ii = 0; ii < tcl[it2].tclhits.size(); ++ii) {
4039 iht = tcl[it2].tclhits[ii];
4040 if (iht > fHits.size() - 1) {
4041 mf::LogError(
"CC") <<
"ChkMergedClusterHitFrac bad iht ";
4044 indx = fHits[iht].WireID().Wire - eWire;
4048 for (ii = 0; ii < cHits.size(); ++ii) {
4050 if (WireHitRange[wire].first == -1) cHits[ii] =
true;
4053 float nhits = std::count(cHits.begin(), cHits.end(),
true);
4054 float hitFrac = nhits / (float)cHits.size();
4055 return (hitFrac > fMinHitFrac);
4059 void ClusterCrawlerAlg::CheckClusterHitFrac(
bool prt)
4064 unsigned int iht = fcl2hits[fcl2hits.size() - 1];
4065 clEndWir = fHits[iht].WireID().Wire;
4066 clBeginWir = fHits[fcl2hits[0]].WireID().Wire;
4067 float hitFrac = (float)(fcl2hits.size() +
DeadWireCount()) / (
float)(clBeginWir - clEndWir + 1);
4069 if (hitFrac < fMinHitFrac) {
4071 mf::LogVerbatim(
"CC") <<
"CheckClusterHitFrac: Poor hit fraction " << hitFrac
4072 <<
" clBeginWir " << clBeginWir <<
" clEndWir " << clEndWir
4073 <<
" size " << fcl2hits.size() <<
" DeadWireCount " 4086 if (fcl2hits.size() < 5) {
4087 unsigned short nsing = 0;
4088 for (
unsigned short iht = 0; iht < fcl2hits.size(); ++iht)
4089 if (fHits[fcl2hits[iht]].Multiplicity() == 1) ++nsing;
4090 hitFrac = (float)nsing / (
float)fcl2hits.size();
4091 if (hitFrac < fMinHitFrac) {
4094 mf::LogVerbatim(
"CC") <<
"CheckClusterHitFrac: Poor short track hit fraction " << hitFrac;
4101 if (clBeginChg <= 0) {
4102 unsigned int iht, nht = 0;
4103 for (
unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
4105 clBeginChg += fHits[iht].Integral();
4107 if (nht == 8)
break;
4109 clBeginChg /= (float)nht;
4112 unsigned short cnt = chgNear.size() / 2;
4114 if (chgNear.size() > 60) cnt = 30;
4117 for (
unsigned short ids = 0; ids < cnt; ++ids) {
4118 clBeginChgNear += chgNear[ids];
4119 clEndChgNear += chgNear[chgNear.size() - 1 - ids];
4121 clBeginChgNear /= (float)cnt;
4122 clEndChgNear /= (float)cnt;
4127 void ClusterCrawlerAlg::FitClusterMid(
unsigned short it1,
unsigned int ihtin,
short nhit)
4129 FitClusterMid(tcl[it1].tclhits, ihtin, nhit);
4133 void ClusterCrawlerAlg::FitClusterMid(std::vector<unsigned int>& hitVec,
4146 if (hitVec.size() < 3)
return;
4148 std::vector<float> xwir;
4149 std::vector<float> ytim;
4150 std::vector<float> ytimerr2;
4152 unsigned short ii, hitcnt = 0, nht = 0, usnhit;
4162 for (ii = 0; ii < hitVec.size(); ++ii) {
4164 if (iht > fHits.size() - 1) {
4171 wire0 = fHits[iht].WireID().Wire;
4175 xwir.push_back((
float)fHits[iht].
WireID().Wire - wire0);
4176 ytim.push_back(fHits[iht].PeakTime());
4178 float terr = fHitErrFac * fHits[iht].RMS();
4179 ytimerr2.push_back(terr * terr);
4180 fAveChg += fHits[iht].Integral();
4182 if (hitcnt == usnhit)
break;
4190 for (
auto ii = hitVec.crbegin(); ii != hitVec.crend(); ++ii) {
4192 if (iht > fHits.size() - 1) {
4199 wire0 = fHits[iht].WireID().Wire;
4203 xwir.push_back((
float)fHits[iht].
WireID().Wire - wire0);
4204 ytim.push_back(fHits[iht].PeakTime());
4205 float terr = fHitErrFac * fHits[iht].RMS();
4206 ytimerr2.push_back(terr * terr);
4207 fAveChg += fHits[iht].Integral();
4209 if (hitcnt == usnhit)
break;
4215 if (nht < 2)
return;
4216 fAveChg = fAveChg / (float)nht;
4221 float intcpterr = 0.;
4222 float slopeerr = 0.;
4224 fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4226 if (clChisq > fChiCut[0])
return;
4230 clparerr[0] = intcpterr;
4231 clparerr[1] = slopeerr;
4235 void ClusterCrawlerAlg::FitCluster()
4244 if (pass > fNumPass - 1) {
4245 mf::LogError(
"CC") <<
"FitCluster called on invalid pass " << pass;
4249 unsigned short ii, nht = 0;
4251 nht = fcl2hits.size();
4254 if (nht > fLAClusMaxHitsFit) nht = fLAClusMaxHitsFit;
4257 if (nht > fMaxHitsFit[pass]) nht = fMaxHitsFit[pass];
4259 if (nht < 2)
return;
4261 std::vector<float> xwir;
4262 std::vector<float> ytim;
4263 std::vector<float> ytimerr2;
4265 float angfactor = AngleFactor(clpar[1]);
4268 unsigned int wire0 = fHits[fcl2hits[fcl2hits.size() - 1]].WireID().Wire;
4270 float terr, qave = 0, qwt;
4271 for (ii = 0; ii < nht; ++ii) {
4272 ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4273 qave += fHits[ihit].Integral();
4276 for (ii = 0; ii < nht; ++ii) {
4277 ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4278 wire = fHits[ihit].WireID().Wire;
4279 xwir.push_back(wire - wire0);
4280 ytim.push_back(fHits[ihit].PeakTime());
4283 terr = fHitErrFac * fHits[ihit].RMS() * fHits[ihit].Multiplicity();
4286 qwt = (fHits[ihit].Integral() / qave) - 1;
4287 if (qwt < 1) qwt = 1;
4290 if (terr < 0.01) terr = 0.01;
4291 ytimerr2.push_back(angfactor * terr * terr);
4293 CalculateAveHitWidth();
4296 myprt <<
"FitCluster W:T ";
4297 unsigned short cnt = 0;
4298 for (std::vector<unsigned int>::reverse_iterator it = fcl2hits.rbegin();
4299 it != fcl2hits.rend();
4301 unsigned int ihit = *it;
4302 unsigned short wire = fHits[ihit].WireID().Wire;
4303 myprt << wire <<
":" << (short)fHits[ihit].PeakTime() <<
" ";
4312 if (xwir.size() < 2)
return;
4316 float intcpterr = 0.;
4317 float slopeerr = 0.;
4319 fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4321 if (chidof > fChiCut[0])
return;
4325 clparerr[0] = intcpterr;
4326 clparerr[1] = slopeerr;
4329 mf::LogVerbatim(
"CC") <<
"nht " << nht <<
" fitpar " << (int)clpar[0] <<
"+/-" 4330 << (
int)intcpterr <<
" " << clpar[1] <<
"+/-" << slopeerr <<
" clChisq " 4334 float ClusterCrawlerAlg::AngleFactor(
float slope)
4340 if (slp > 15) slp = 15;
4342 float angfac = 1 + 0.03 * slp * slp;
4347 void ClusterCrawlerAlg::CalculateAveHitWidth()
4350 for (
unsigned short ii = 0; ii < fcl2hits.size(); ++ii)
4351 fAveHitWidth += fHits[fcl2hits[ii]].EndTick() - fHits[fcl2hits[ii]].StartTick();
4352 fAveHitWidth /= (float)fcl2hits.size();
4356 void ClusterCrawlerAlg::FitClusterChg()
4361 if (fcl2hits.size() == 0)
return;
4362 unsigned int ih0 = fcl2hits.size() - 1;
4364 if (pass >= fNumPass) {
4365 mf::LogError(
"CC") <<
"FitClusterChg bad pass " << pass;
4373 unsigned short nhave = fLAClusMaxHitsFit;
4374 if (nhave > fcl2hits.size()) nhave = fcl2hits.size();
4379 for (
unsigned short ii = 0; ii < nhave; ++ii) {
4380 iht = fcl2hits[fcl2hits.size() - 1 - ii];
4381 fAveChg += fHits[iht].Integral();
4382 fAveHitWidth += (fHits[iht].EndTick() - fHits[iht].StartTick());
4384 fAveChg /= (float)fcl2hits.size();
4385 fAveHitWidth /= (float)fcl2hits.size();
4390 unsigned short fitLen = fNHitsAve[pass];
4394 fcl2hits.size() > 5 &&
4395 fcl2hits.size() < fitLen)
4399 if (fNHitsAve[pass] < 1)
return;
4401 if (fNHitsAve[pass] == 1) {
4403 fAveChg = fHits[fcl2hits[ih0]].Integral();
4406 else if (fNHitsAve[pass] == 2) {
4408 fAveChg = (fHits[fcl2hits[ih0]].Integral() + fHits[fcl2hits[ih0 - 1]].Integral()) / 2.;
4411 else if ((
unsigned short)fcl2hits.size() > fitLen) {
4413 std::vector<float> xwir;
4414 std::vector<float> ychg;
4415 std::vector<float> ychgerr2;
4417 unsigned int wire0 = fHits[fcl2hits[fcl2hits.size() - 1]].WireID().Wire;
4419 unsigned short npt = 0;
4420 unsigned short imlast = 0;
4424 for (
unsigned int ii = fcl2hits.size() - 1; ii > 0; --ii) {
4426 float chg = fHits[fcl2hits[ii]].Integral();
4429 if (npt == fitLen) {
4436 rms = std::sqrt((rms - fnpt * ave * ave) / (fnpt - 1));
4437 float chgcut = ave + rms;
4440 for (
unsigned short ii = fcl2hits.size() - 1; ii > imlast; --ii) {
4441 wire = fHits[fcl2hits[ii]].WireID().Wire;
4442 chg = fHits[fcl2hits[ii]].Integral();
4443 if (chg > chgcut)
continue;
4444 xwir.push_back((
float)(wire - wire0));
4445 ychg.push_back(chg);
4446 ychgerr2.push_back(chg);
4448 if (ychg.size() < 3)
return;
4454 fLinFitAlg.LinFit(xwir, ychg, ychgerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4456 mf::LogVerbatim(
"CC") <<
"FitClusterChg wire " << wire0 <<
" chidof " << (int)chidof
4457 <<
" npt " << xwir.size() <<
" charge = " << (int)intcpt
4458 <<
" slope = " << (
int)slope <<
" first ave " << (int)ave <<
" rms " 4460 if (chidof > 100.)
return;
4463 if (intcpt > ave)
return;
4466 ave = intcpt / fAveChg;
4467 if (ave > 1.3)
return;
4468 if (ave < 0.77)
return;
4476 void ClusterCrawlerAlg::AddLAHit(
unsigned int kwire,
bool& ChkCharge,
bool& HitOK,
bool& SigOK)
4484 if (kwire < fFirstWire || kwire > fLastWire)
return;
4486 if (fcl2hits.size() == 0)
return;
4489 if (WireHitRange[kwire].first == -1) {
4494 if (WireHitRange[kwire].first == -2)
return;
4496 unsigned int firsthit = WireHitRange[kwire].first;
4497 unsigned int lasthit = WireHitRange[kwire].second;
4500 float timeDiff = 40 * AngleFactor(clpar[1]);
4504 unsigned int lastClHit = UINT_MAX;
4505 if (fcl2hits.size() > 0) {
4506 lastClHit = fcl2hits[fcl2hits.size() - 1];
4507 if (lastClHit == 0) {
4508 fAveChg = fHits[lastClHit].Integral();
4509 fAveHitWidth = fHits[lastClHit].EndTick() - fHits[lastClHit].StartTick();
4514 float prtime = clpar[0] + ((float)kwire - clpar[2]) * clpar[1];
4515 float chgWinLo = prtime - fChgNearWindow;
4516 float chgWinHi = prtime + fChgNearWindow;
4517 float chgrat, hitWidth;
4518 float hitWidthCut = 0.5 * fAveHitWidth;
4522 mf::LogVerbatim(
"CC") <<
"AddLAHit: wire " << kwire <<
" prtime " << prtime
4523 <<
" max timeDiff " << timeDiff <<
" fAveChg " << fAveChg;
4524 unsigned int imbest = 0;
4526 for (khit = firsthit; khit < lasthit; ++khit) {
4528 if (inClus[khit] < 0)
continue;
4529 dtime =
std::abs(fHits[khit].PeakTime() - prtime);
4530 hitWidth = fHits[khit].EndTick() - fHits[khit].StartTick();
4532 if (ChkCharge && fAveChg > 0) { chgrat = fHits[khit].Integral() / fAveChg; }
4534 mf::LogVerbatim(
"CC") <<
" Chk W:T " << kwire <<
":" << (short)fHits[khit].PeakTime()
4535 <<
" dT " << std::fixed << std::setprecision(1) << dtime <<
" InClus " 4536 << inClus[khit] <<
" mult " << fHits[khit].Multiplicity() <<
" width " 4537 << (int)hitWidth <<
" MergeAvail " << mergeAvailable[khit] <<
" Chi2 " 4538 << std::fixed << std::setprecision(2) << fHits[khit].GoodnessOfFit()
4539 <<
" Charge " << (int)fHits[khit].Integral() <<
" chgrat " 4540 << std::fixed << std::setprecision(1) << chgrat <<
" index " << khit;
4542 if (fHits[khit].PeakTime() > chgWinLo && fHits[khit].PeakTime() < chgWinHi)
4543 cnear += fHits[khit].Integral();
4545 if (prtime < fHits[khit].StartTick() - timeDiff)
continue;
4546 if (prtime > fHits[khit].EndTick() + timeDiff)
continue;
4549 if (inClus[khit] > 0)
continue;
4551 if (hitWidth < hitWidthCut)
continue;
4553 if (chgrat < 0.1)
continue;
4554 if (dtime < timeDiff) {
4566 mf::LogVerbatim(
"CC") <<
" Pick hit time " << (int)fHits[imbest].PeakTime() <<
" hit index " 4571 if (lastClHit != UINT_MAX && fHits[imbest].Multiplicity() > 1) {
4572 bool doMerge =
true;
4575 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
4576 if (vtx[ivx].CTP != clCTP)
continue;
4578 mf::LogVerbatim(
"CC") <<
" close vtx chk W:T " << vtx[ivx].Wire <<
":" 4579 << (int)vtx[ivx].Time;
4580 if (
std::abs(kwire - vtx[ivx].Wire) < 5 &&
4581 std::abs(
int(fHits[imbest].PeakTime() - vtx[ivx].Time)) < 20) {
4582 if (prt)
mf::LogVerbatim(
"CC") <<
" Close to a vertex. Don't merge hits";
4589 unsigned short nused = 0;
4591 float multipletChg = 0.;
4592 float chicut = AngleFactor(clpar[1]) * fHitMergeChiCut * fHits[lastClHit].RMS();
4594 std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(imbest);
4595 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
4596 if (inClus[jht] < 0)
continue;
4597 if (inClus[jht] == 0)
4598 multipletChg += fHits[jht].Integral();
4602 if (jht > MultipletRange.first) {
4604 float hitRMS = fHits[jht].RMS();
4605 if (fHits[jht - 1].RMS() > hitRMS) hitRMS = fHits[jht - 1].RMS();
4607 std::abs(fHits[jht].PeakTime() - fHits[jht - 1].PeakTime()) / hitRMS;
4608 if (prt)
mf::LogVerbatim(
"CC") <<
" Hit RMS chisq " << tdiff <<
" chicut " << chicut;
4609 if (tdiff > chicut) doMerge =
false;
4613 if (!doMerge)
mf::LogVerbatim(
"CC") <<
" Hits are well separated. Don't merge them ";
4615 if (doMerge && nused == 0) {
4620 float chgrat = multipletChg / fHits[lastClHit].Integral();
4622 mf::LogVerbatim(
"CC") <<
" merge hits charge check " << (int)multipletChg
4623 <<
" Previous hit charge " << (
int)fHits[lastClHit].Integral();
4624 if (chgrat > 2) doMerge =
false;
4632 MergeHits(imbest, didMerge);
4637 fcl2hits.push_back(imbest);
4640 chifits.push_back(clChisq);
4641 hitNear.push_back(hnear);
4643 cnear -= fHits[imbest].Integral();
4644 if (cnear < 0) cnear = 0;
4646 cnear /= fHits[imbest].Integral();
4647 chgNear.push_back(cnear);
4649 hitWidth = fHits[imbest].EndTick() - fHits[imbest].StartTick();
4651 << timeDiff <<
" clChisq " << clChisq <<
" Chg " 4652 << (int)fHits[imbest].Integral() <<
" AveChg " << (int)fAveChg
4653 <<
" width " << (
int)hitWidth <<
" AveWidth " << (int)fAveHitWidth
4654 <<
" fcl2hits size " << fcl2hits.size();
4657 if (clChisq > fChiCut[pass]) {
4662 if (prt)
mf::LogVerbatim(
"CC") <<
" LADD- Removed bad hit. Stopped tracking";
4667 bool ClusterCrawlerAlg::ClusterHitsOK(
short nHitChk)
4680 if (fcl2hits.size() == 0)
return true;
4682 unsigned short nHitToChk = fcl2hits.size();
4683 if (nHitChk > 0) nHitToChk = nHitChk + 1;
4684 unsigned short ii, indx;
4690 if (plane < geom->TPC(
geo::TPCID(cstat, tpc)).Nplanes() - 1) tol = 40;
4693 (fHits[fcl2hits[0]].PeakTime() > fHits[fcl2hits[fcl2hits.size() - 1]].PeakTime());
4696 for (ii = 0; ii < nHitToChk; ++ii) {
4697 indx = fcl2hits.size() - 1 - ii;
4698 mf::LogVerbatim(
"CC") <<
"ClusterHitsOK chk " << fHits[fcl2hits[indx]].WireID().Wire
4699 <<
" start " << fHits[fcl2hits[indx]].StartTick() <<
" peak " 4700 << fHits[fcl2hits[indx]].PeakTime() <<
" end " 4701 << fHits[fcl2hits[indx]].EndTick() <<
" posSlope " << posSlope;
4706 for (ii = 0; ii < nHitToChk - 1; ++ii) {
4707 indx = fcl2hits.size() - 1 - ii;
4710 fHits[fcl2hits[indx - 1]].
WireID().Wire) > 1)
4713 std::max(fHits[fcl2hits[indx]].StartTick(), fHits[fcl2hits[indx - 1]].StartTick());
4714 loEndTick = std::min(fHits[fcl2hits[indx]].EndTick(), fHits[fcl2hits[indx - 1]].EndTick());
4716 if (loEndTick + tol < hiStartTick) {
return false; }
4719 if (loEndTick + tol < hiStartTick) {
return false; }
4726 void ClusterCrawlerAlg::AddHit(
unsigned int kwire,
bool& HitOK,
bool& SigOK)
4737 if (kwire < fFirstWire || kwire > fLastWire)
return;
4739 unsigned int lastClHit = UINT_MAX;
4740 if (fcl2hits.size() > 0) lastClHit = fcl2hits[fcl2hits.size() - 1];
4743 unsigned int wire0 = clpar[2];
4746 if (fAllowNoHitWire == 0) {
4747 if (WireHitRange[kwire].first == -2)
return;
4751 if (WireHitRange[kwire].first == -2 && (wire0 - kwire) > fAllowNoHitWire) {
4757 if (WireHitRange[kwire].first == -1) {
4762 unsigned int firsthit = WireHitRange[kwire].first;
4763 unsigned int lasthit = WireHitRange[kwire].second;
4766 float dw = (float)kwire - (
float)wire0;
4767 float prtime = clpar[0] + dw * clpar[1];
4768 if (prtime < 0 || (
unsigned int)prtime > fMaxTime)
return;
4771 float prtimerr2 =
std::abs(dw) * clparerr[1] * clparerr[1];
4775 if (lastClHit != UINT_MAX) hiterr = 3 * fHitErrFac * fHits[lastClHit].RMS();
4776 float err = std::sqrt(prtimerr2 + hiterr * hiterr);
4778 float hitWin = fClProjErrFac * err;
4780 float prtimeLo = prtime - hitWin;
4781 float prtimeHi = prtime + hitWin;
4782 float chgWinLo = prtime - fChgNearWindow;
4783 float chgWinHi = prtime + fChgNearWindow;
4785 mf::LogVerbatim(
"CC") <<
"AddHit: wire " << kwire <<
" prtime Lo " << (int)prtimeLo
4786 <<
" prtime " << (
int)prtime <<
" Hi " << (int)prtimeHi <<
" prtimerr " 4787 << sqrt(prtimerr2) <<
" hiterr " << hiterr <<
" fAveChg " 4788 << (int)fAveChg <<
" fAveHitWidth " << std::setprecision(3)
4792 unsigned int imbest = INT_MAX;
4793 float best = 9999., dtime;
4795 float hitTime, hitChg, hitStartTick, hitEndTick;
4796 for (
unsigned int khit = firsthit; khit < lasthit; ++khit) {
4798 if (inClus[khit] < 0)
continue;
4799 hitTime = fHits[khit].PeakTime();
4800 dtime =
std::abs(hitTime - prtime);
4801 if (dtime > 1000)
continue;
4802 hitStartTick = fHits[khit].StartTick();
4803 hitEndTick = fHits[khit].EndTick();
4805 if (fAveChg > 0) dtime *=
std::abs(fHits[khit].Integral() - fAveChg) / fAveChg;
4806 if (prt &&
std::abs(dtime) < 100) {
4808 << std::setprecision(1) << (hitTime - prtime) <<
" InClus " 4809 << inClus[khit] <<
" mult " << fHits[khit].Multiplicity() <<
" RMS " 4810 << std::fixed << std::setprecision(1) << fHits[khit].RMS() <<
" Chi2 " 4811 << std::fixed << std::setprecision(1) << fHits[khit].GoodnessOfFit()
4812 <<
" Charge " << (int)fHits[khit].Integral() <<
" Peak " << std::fixed
4813 << std::setprecision(1) << fHits[khit].PeakAmplitude() <<
" LoT " 4814 << (int)hitStartTick <<
" HiT " << (
int)hitEndTick <<
" index " 4818 if (fHits[khit].StartTick() > chgWinLo && fHits[khit].EndTick() < chgWinHi)
4819 cnear += fHits[khit].Integral();
4821 if (prtimeHi < hitStartTick)
continue;
4822 if (prtimeLo > hitEndTick)
continue;
4825 if (hitTime < prtimeLo)
continue;
4826 if (hitTime > prtimeHi)
continue;
4828 if (inClus[khit] > 0)
continue;
4836 if (fAllowNoHitWire == 0)
return;
4838 mf::LogVerbatim(
"CC") <<
" wire0 " << wire0 <<
" kwire " << kwire <<
" max " 4839 << fAllowNoHitWire <<
" imbest " << imbest;
4840 if ((wire0 - kwire) > fAllowNoHitWire)
return;
4844 if (imbest == INT_MAX)
return;
4853 bool didMerge =
false;
4854 if (lastClHit != UINT_MAX && fAveHitWidth > 0 && fHitMergeChiCut > 0 &&
4856 bool doMerge =
true;
4857 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
4858 if (
std::abs(kwire - vtx[ivx].Wire) < 10 &&
4865 if (hit.
LocalIndex() != 0 && imbest == 0) doMerge =
false;
4869 if (hit.
LocalIndex() == 0) { oht = imbest + 1; }
4876 hitSep /= hit.
RMS();
4878 float totChg = hitChg + other_hit.
Integral();
4879 float lastHitChg = fAveChg;
4880 if (lastHitChg < 0) lastHitChg = fHits[lastClHit].Integral();
4883 mf::LogVerbatim(
"CC") <<
" Chk hit merge hitsep " << hitSep <<
" dChg " 4884 <<
std::abs(totChg - lastHitChg) <<
" Cut " 4886 if (inClus[oht] == 0 && hitSep < fHitMergeChiCut) {
4888 MergeHits(imbest, didMerge);
4898 float chgrat = (hitChg - fAveChg) / fAveChg;
4899 if (prt)
mf::LogVerbatim(
"CC") <<
" Chgrat " << std::setprecision(2) << chgrat;
4902 if (chgrat > 3 * fChgCut[pass]) {
4904 mf::LogVerbatim(
"CC") <<
" fails 3 x high charge cut " << fChgCut[pass] <<
" on pass " 4912 float bigchgcut = 1.5 * fChgCut[pass];
4913 bool lasthitbig =
false;
4914 bool lasthitlow =
false;
4916 float lastchgrat = (fHits[lastClHit].Integral() - fAveChg) / fAveChg;
4917 lasthitbig = (lastchgrat > bigchgcut);
4918 lasthitlow = (lastchgrat < -fChgCut[pass]);
4922 if (lasthitlow && chgrat < -fChgCut[pass]) {
4923 if (prt)
mf::LogVerbatim(
"CC") <<
" fails low charge cut. Stop crawling.";
4929 if (lasthitbig && chgrat > fChgCut[pass]) {
4931 mf::LogVerbatim(
"CC") <<
" fails 2nd hit high charge cut. Last hit was high also. ";
4936 if (chgrat > fChgCut[pass]) {
4937 if (best > 2 * err) {
4938 if (prt)
mf::LogVerbatim(
"CC") <<
" high charge && bad dT= " << best <<
" err= " << err;
4944 fitChg = (chgrat <
std::abs(fChgCut[pass]));
4948 fcl2hits.push_back(imbest);
4950 if (fcl2hits.size() == 3) std::sort(fcl2hits.begin(), fcl2hits.end(),
SortByLowHit);
4952 chifits.push_back(clChisq);
4953 hitNear.push_back(hnear);
4955 cnear -= fHits[imbest].Integral();
4956 if (cnear < 0) cnear = 0;
4958 cnear /= fHits[imbest].Integral();
4959 chgNear.push_back(cnear);
4964 if (chgNear.size() != fcl2hits.size()) {
4971 <<
" clChisq " << clChisq <<
" Chg " << (int)fHits[imbest].Integral()
4972 <<
" AveChg " << (int)fAveChg <<
" fcl2hits size " << fcl2hits.size();
4974 if (!fitChg)
return;
4980 void ClusterCrawlerAlg::ChkClusterNearbyHits(
bool prt)
4987 if (fHitMergeChiCut <= 0)
return;
4989 if (hitNear.size() != fcl2hits.size()) {
4990 mf::LogWarning(
"CC") <<
"Coding error: hitNear size != fcl2hits";
4995 if (hitNear.size() < 12)
return;
4998 unsigned short ii, indx;
4999 unsigned short merged = 0;
5000 unsigned short notmerged = 0;
5001 for (ii = 0; ii < 6; ++ii) {
5002 indx = hitNear.size() - 1 - ii;
5003 if (hitNear[indx] > 0) ++notmerged;
5004 if (hitNear[indx] < 0) ++merged;
5008 mf::LogVerbatim(
"CC") <<
"ChkClusterNearbyHits: nearby hits merged " << merged
5009 <<
" not merged " << notmerged;
5011 if (notmerged < 2)
return;
5017 for (ii = 0; ii < 6; ++ii) {
5018 indx = fcl2hits.size() - 1 - ii;
5019 const unsigned int iht = fcl2hits[indx];
5023 if (hit.
LocalIndex() != 0 && iht == 0)
continue;
5026 if (hit.
LocalIndex() == 0) { oht = iht + 1; }
5033 hitSep /= hit.
RMS();
5034 if (hitSep < fHitMergeChiCut && inClus[oht] == 0) {
5037 << fHits[iht].WireID().Wire <<
":" << fHits[iht].PeakTime();
5038 MergeHits(iht, didMerge);
5039 if (didMerge) hitNear[indx] = -1;
5048 if (prt)
mf::LogVerbatim(
"CC") <<
"ChkClusterNearbyHits refit cluster. fAveChg= " << fAveChg;
5053 void ClusterCrawlerAlg::FitVtx(
unsigned short iv)
5055 std::vector<float>
x;
5056 std::vector<float>
y;
5057 std::vector<float> ey2;
5061 if (vtx[iv].Fixed)
return;
5064 vtx[iv].ChiDOF = 99;
5068 std::vector<unsigned short> vcl;
5069 for (icl = 0; icl < tcl.size(); ++icl) {
5070 if (tcl[icl].ID < 0)
continue;
5071 if (tcl[icl].CTP != vtx[iv].CTP)
continue;
5072 if (tcl[icl].EndVtx == iv) vcl.push_back(icl);
5073 if (tcl[icl].BeginVtx == iv) vcl.push_back(icl);
5076 vtx[iv].NClusters = vcl.size();
5078 if (vcl.size() == 0)
return;
5084 unsigned short indx = tcl[icl].tclhits.size() - 1;
5085 unsigned int hit = tcl[icl].tclhits[indx];
5086 float minTimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5088 if (vcl.size() == 1) {
5091 if (tcl[icl].EndVtx == iv) {
5092 vtx[iv].Wire = tcl[icl].EndWir;
5093 vtx[iv].WireErr = 1;
5094 vtx[iv].Time = tcl[icl].EndTim;
5096 indx = tcl[icl].tclhits.size() - 1;
5097 hit = tcl[icl].tclhits[indx];
5098 vtx[iv].TimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5101 if (tcl[icl].BeginVtx == iv) {
5102 vtx[iv].Wire = tcl[icl].BeginWir;
5103 vtx[iv].WireErr = 1;
5104 vtx[iv].Time = tcl[icl].BeginTim;
5106 hit = tcl[icl].tclhits[0];
5107 vtx[iv].TimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5113 std::vector<double> slps;
5114 std::vector<double> slperrs;
5115 for (
unsigned short ii = 0; ii < vcl.size(); ++ii) {
5117 if (tcl[icl].EndVtx == iv) {
5118 x.push_back(tcl[icl].EndSlp);
5119 slps.push_back(tcl[icl].EndSlp);
5120 slperrs.push_back(tcl[icl].EndSlpErr);
5121 arg = tcl[icl].EndSlp * tcl[icl].EndWir - tcl[icl].EndTim;
5123 if (tcl[icl].EndSlpErr > 0.) { arg = tcl[icl].EndSlpErr * tcl[icl].EndWir; }
5125 arg = .1 * tcl[icl].EndWir;
5127 ey2.push_back(arg * arg);
5129 else if (tcl[icl].BeginVtx == iv) {
5130 x.push_back(tcl[icl].BeginSlp);
5131 slps.push_back(tcl[icl].BeginSlp);
5132 slperrs.push_back(tcl[icl].BeginSlpErr);
5133 arg = tcl[icl].BeginSlp * tcl[icl].BeginWir - tcl[icl].BeginTim;
5135 if (tcl[icl].BeginSlpErr > 0.) { arg = tcl[icl].BeginSlpErr * tcl[icl].BeginWir; }
5137 arg = .1 * tcl[icl].BeginWir;
5139 ey2.push_back(arg * arg);
5142 if (x.size() < 2)
return;
5145 double sumerr = 0, cnt = 0;
5146 for (
unsigned short ii = 0; ii < slps.size() - 1; ++ii) {
5147 for (
unsigned short jj = ii + 1; jj < slps.size(); ++jj) {
5148 arg = std::min(slperrs[ii], slperrs[jj]);
5149 arg /= (slps[ii] - slps[jj]);
5150 sumerr += arg * arg;
5157 float vTimeErr = 0.;
5159 float vWireErr = 0.;
5161 fLinFitAlg.LinFit(x, y, ey2, vTime, vWire, vTimeErr, vWireErr, chiDOF);
5162 if (chiDOF > 900)
return;
5165 if (vTime < 0 || vTime > fMaxTime)
return;
5168 if (vWire < 0 || vWire > geom->Nwires(iplID))
return;
5169 vtx[iv].ChiDOF = chiDOF;
5170 vtx[iv].Wire = vWire;
5171 vtx[iv].Time = vTime;
5172 vtx[iv].WireErr = vWire * sqrt(sumerr);
5173 vtx[iv].TimeErr = vTime * fabs(sumerr);
5175 if (vtx[iv].WireErr < 1) vtx[iv].WireErr = 2;
5177 if (vtx[iv].TimeErr < minTimeErr) vtx[iv].TimeErr = minTimeErr;
5187 if (
empty(vtx3))
return;
5189 const unsigned int cstat = tpcid.
Cryostat;
5190 const unsigned int tpc = tpcid.
TPC;
5192 unsigned int thePlane, theWire;
5196 for (
unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5198 if (vtx3[ivx].Wire < 0)
continue;
5199 if (vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc)
continue;
5202 theWire = vtx3[ivx].Wire;
5203 for (plane = 0; plane < 3; ++plane) {
5204 if (vtx3[ivx].Ptr2D[plane] >= 0)
continue;
5208 if (thePlane > 2)
continue;
5210 clCTP =
EncodeCTP(cstat, tpc, thePlane);
5213 vnew.
Wire = theWire;
5214 vnew.
Time = theTime;
5218 vtx.push_back(vnew);
5219 unsigned short ivnew = vtx.size() - 1;
5220 std::vector<short> vclIndex;
5221 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
5222 if (tcl[icl].ID < 0)
continue;
5223 if (tcl[icl].CTP != clCTP)
continue;
5227 if (dwb > 10 && dwe > 10)
continue;
5228 if (dwb < dwe && dwb < 10 && tcl[icl].BeginVtx < 0) {
5230 if (theWire < tcl[icl].BeginWir + 5)
continue;
5231 if (ClusterVertexChi(icl, 0, ivnew) > fVertex3DCut)
continue;
5232 tcl[icl].BeginVtx = ivnew;
5233 vclIndex.push_back(icl);
5235 else if (dwe < 10 && tcl[icl].EndVtx < 0) {
5237 if (theWire > tcl[icl].EndWir - 5)
continue;
5238 if (ClusterVertexChi(icl, 1, ivnew) > fVertex3DCut)
continue;
5239 tcl[icl].EndVtx = ivnew;
5240 vclIndex.push_back(icl);
5243 bool goodVtx =
false;
5244 if (vclIndex.size() > 0) {
5246 goodVtx = (vtx[ivnew].ChiDOF < fVertex3DCut);
5247 vtx3[ivx].Ptr2D[thePlane] = ivnew;
5250 vtx3[ivx].Ptr2D[thePlane] = ivnew;
5251 vtx3[ivx].Wire = -1;
5256 for (
unsigned short ii = 0; ii < vclIndex.size(); ++ii) {
5257 unsigned short icl = vclIndex[ii];
5258 if (tcl[icl].BeginVtx == ivnew) tcl[icl].BeginVtx = -99;
5259 if (tcl[icl].EndVtx == ivnew) tcl[icl].EndVtx = -99;
5271 if (
empty(vtx3))
return;
5273 const unsigned int cstat = tpcid.
Cryostat;
5274 const unsigned int tpc = tpcid.
TPC;
5276 vtxprt = (fDebugPlane >= 0) && (fDebugHit == 6666);
5278 unsigned int lastplane = 5, kcl, kclID;
5280 unsigned int thePlane, theWire, plane;
5281 unsigned int loWire, hiWire;
5283 for (
unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5284 if (vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc)
continue;
5287 mf::LogVerbatim(
"CC") <<
"Vtx3ClusterSplit ivx " << ivx <<
" Ptr2D " << vtx3[ivx].Ptr2D[0]
5288 <<
" " << vtx3[ivx].Ptr2D[1] <<
" " << vtx3[ivx].Ptr2D[2] <<
" wire " 5290 if (vtx3[ivx].Wire < 0)
continue;
5293 theWire = vtx3[ivx].Wire;
5294 for (plane = 0; plane < 3; ++plane) {
5295 if (vtx3[ivx].Ptr2D[plane] >= 0)
continue;
5299 if (thePlane > 2)
continue;
5301 (
double)vtx3[ivx].
X, (
int)thePlane, (
int)tpcid.
TPC, (
int)tpcid.
Cryostat);
5303 if (thePlane != lastplane) {
5306 lastplane = thePlane;
5309 std::vector<short> clIDs;
5310 if (theWire > fFirstWire + 5) { loWire = theWire - 5; }
5312 loWire = fFirstWire;
5314 if (theWire < fLastWire - 5) { hiWire = theWire + 5; }
5319 mf::LogVerbatim(
"CC") <<
"3DVtx " << ivx <<
" look for cluster hits near P:W:T " << thePlane
5320 <<
":" << theWire <<
":" << (int)theTime <<
" Wire range " << loWire
5321 <<
" to " << hiWire;
5322 for (
unsigned int wire = loWire; wire < hiWire; ++wire) {
5324 if (WireHitRange[wire].first < 0)
continue;
5325 unsigned int firsthit = WireHitRange[wire].first;
5326 unsigned int lasthit = WireHitRange[wire].second;
5327 for (
unsigned int khit = firsthit; khit < lasthit; ++khit) {
5329 if (inClus[khit] <= 0)
continue;
5330 if ((
unsigned int)inClus[khit] > tcl.size() + 1) {
5331 mf::LogError(
"CC") <<
"Invalid hit InClus. " << khit <<
" " << inClus[khit];
5335 if (theTime < fHits[khit].StartTick() - 20)
continue;
5336 if (theTime > fHits[khit].EndTick() + 20)
continue;
5337 kclID = inClus[khit];
5340 if (tcl[kcl].ID < 0)
continue;
5342 if (tcl[kcl].tclhits.size() < 6)
continue;
5344 if (tcl[kcl].tclhits.size() > 100 &&
std::abs(tcl[kcl].BeginAng - tcl[kcl].EndAng) < 0.1)
5348 mf::LogVerbatim(
"CC") <<
"Bingo " << ivx <<
" plane " << thePlane <<
" wire " << wire
5349 <<
" hit " << fHits[khit].WireID().Wire <<
":" 5350 << (int)fHits[khit].PeakTime() <<
" inClus " << inClus[khit]
5351 <<
" P:W:T " << thePlane <<
":" << tcl[kcl].BeginWir <<
":" 5352 << (int)tcl[kcl].BeginTim;
5353 if (std::find(clIDs.begin(), clIDs.end(), kclID) == clIDs.end()) {
5354 clIDs.push_back(kclID);
5358 if (clIDs.size() == 0)
continue;
5360 for (
unsigned int ii = 0; ii < clIDs.size(); ++ii)
5363 unsigned short ii, icl, jj;
5370 unsigned short i2Dvx = 0;
5371 for (ii = 0; ii < 3; ++ii) {
5372 if (ii == thePlane)
continue;
5373 i2Dvx = vtx3[ivx].Ptr2D[ii];
5374 if (i2Dvx > vtx.size() - 1) {
5375 mf::LogError(
"CC") <<
"Vtx3ClusterSplit: Coding error";
5378 if (vtx[i2Dvx].TimeErr > tErr) tErr = vtx[i2Dvx].TimeErr;
5382 for (ii = 0; ii < clIDs.size(); ++ii) {
5383 icl = clIDs[ii] - 1;
5385 for (jj = 0; jj < tcl[icl].tclhits.size(); ++jj) {
5386 iht = tcl[icl].tclhits[jj];
5387 if (fHits[iht].
WireID().Wire < theWire) {
5389 if (jj > 3) nhitfit = -3;
5390 FitClusterMid(icl, iht, nhitfit);
5391 float doca = DoCA(-1, 1, theWire, theTime);
5393 mf::LogVerbatim(
"CC") <<
" cls " << icl <<
" DoCA " << doca <<
" tErr " << tErr;
5394 if ((doca / tErr) > 2) clIDs[ii] = -1;
5404 for (ii = 0; ii < clIDs.size(); ++ii)
5409 unsigned short nok = 0;
5410 for (ii = 0; ii < clIDs.size(); ++ii)
5411 if (clIDs[ii] >= 0) ++nok;
5412 if (nok == 0)
continue;
5416 vnew.
Wire = theWire;
5418 vnew.
Time = theTime;
5423 vtx.push_back(vnew);
5425 unsigned short ivnew = vtx.size() - 1;
5427 mf::LogVerbatim(
"CC") <<
"Make new 2D vtx " << ivnew <<
" in plane " << thePlane
5428 <<
" from 3D vtx " << ivx;
5429 vtx3[ivx].Ptr2D[thePlane] = ivnew;
5431 for (ii = 0; ii < clIDs.size(); ++ii) {
5432 if (clIDs[ii] < 0)
continue;
5433 icl = clIDs[ii] - 1;
5436 unsigned short pos = 0;
5437 for (
unsigned short jj = 0; jj < tcl[icl].tclhits.size(); ++jj) {
5438 iht = tcl[icl].tclhits[jj];
5439 if (fHits[iht].
WireID().Wire < theWire) {
5446 tcl[icl].BeginVtx = ivnew;
5449 else if (pos > tcl[icl].tclhits.size()) {
5451 tcl[icl].EndVtx = ivnew;
5456 if (vtxprt)
mf::LogVerbatim(
"CC") <<
"Split cluster " << clIDs[ii] <<
" at pos " << pos;
5457 if (!SplitCluster(icl, pos, ivnew)) {
5461 tcl[icl].ProcCode += 10000;
5462 tcl[tcl.size() - 1].ProcCode += 10000;
5467 if (vtx[ivnew].ChiDOF < 5 && vtx[ivnew].WireErr < fVertex2DWireErrCut) {
5469 vtx3[ivx].Wire = -1;
5473 mf::LogVerbatim(
"CC") <<
"Bad vtx fit " << ivnew <<
" ChiDOF " << vtx[ivnew].ChiDOF
5474 <<
" WireErr " << vtx[ivnew].WireErr;
5477 vtx3[ivx].Ptr2D[thePlane] = -1;
5479 for (jj = 0; jj < tcl.size(); ++jj) {
5480 if (tcl[jj].BeginVtx == ivnew) tcl[jj].BeginVtx = -99;
5481 if (tcl[jj].EndVtx == ivnew) tcl[jj].EndVtx = -99;
5496 unsigned int nPln = geom->TPC(
geo::TPCID(cstat, tpc)).Nplanes();
5497 if (nPln != 3)
return;
5499 float ew1, ew2, bw2, fvw;
5506 unsigned short longClIndex;
5507 unsigned short shortClIndex;
5508 unsigned short splitPos;
5510 std::array<std::vector<Hammer>, 3> hamrVec;
5514 for (ipl = 0; ipl < 3; ++ipl) {
5516 for (
unsigned short ic1 = 0; ic1 < tcl.size(); ++ic1) {
5517 if (tcl[ic1].ID < 0)
continue;
5519 if (tcl[ic1].tclhits.size() < 20)
continue;
5520 if (tcl[ic1].CTP != clCTP)
continue;
5522 if (tcl[ic1].EndVtx >= 0)
continue;
5523 ew1 = tcl[ic1].EndWir;
5524 for (
unsigned short ic2 = 0; ic2 < tcl.size(); ++ic2) {
5525 if (tcl[ic2].ID < 0)
continue;
5527 if (tcl[ic2].tclhits.size() > 20)
continue;
5529 if (tcl[ic2].tclhits.size() < 6)
continue;
5530 if (tcl[ic2].CTP != clCTP)
continue;
5531 ew2 = tcl[ic2].EndWir;
5532 bw2 = tcl[ic2].BeginWir;
5535 if (ew1 < ew2 || ew1 > bw2)
continue;
5539 unsigned short spos = 0;
5540 for (
unsigned short ii = 0; ii < tcl[ic2].tclhits.size(); ++ii) {
5541 unsigned int iht = tcl[ic2].tclhits[ii];
5542 float dw = fHits[iht].WireID().Wire - tcl[ic1].EndWir;
5543 float dt = fabs(fHits[iht].PeakTime() - tcl[ic1].EndTim - tcl[ic1].EndSlp * dw);
5550 if (ibst < 0)
continue;
5551 fvw = 0.5 + fHits[ibst].WireID().Wire;
5554 aHam.Wire = (0.5 + fvw);
5555 aHam.Tick = fHits[ibst].PeakTime();
5556 aHam.X = det_prop.
ConvertTicksToX((
double)aHam.Tick, (
int)ipl, (
int)tpc, (
int)cstat);
5557 aHam.longClIndex = ic1;
5558 aHam.shortClIndex = ic2;
5559 aHam.splitPos = spos;
5560 unsigned short indx = hamrVec[ipl].size();
5561 hamrVec[ipl].resize(indx + 1);
5562 hamrVec[ipl][indx] = aHam;
5569 unsigned short noham = 0;
5570 for (ipl = 0; ipl < 3; ++ipl)
5571 if (hamrVec[ipl].
size() == 0) ++noham;
5572 if (noham > 1)
return;
5579 float YLo = world.Y() - thetpc.
HalfHeight() + 1;
5580 float YHi = world.Y() + thetpc.
HalfHeight() - 1;
5581 float ZLo = world.Z() - thetpc.
Length() / 2 + 1;
5582 float ZHi = world.Z() + thetpc.
Length() / 2 - 1;
5587 unsigned short icl, jpl, jcl, kpl, splitPos;
5588 for (ipl = 0; ipl < 3; ++ipl) {
5589 if (hamrVec[ipl].
size() == 0)
continue;
5590 jpl = (ipl + 1) % nPln;
5591 kpl = (jpl + 1) % nPln;
5592 for (
unsigned short ii = 0; ii < hamrVec[ipl].size(); ++ii) {
5593 if (hamrVec[ipl][ii].Used)
continue;
5594 for (
unsigned short jj = 0; jj < hamrVec[jpl].size(); ++jj) {
5595 if (hamrVec[jpl][jj].Used)
continue;
5596 dX = hamrVec[ipl][ii].X - hamrVec[jpl][jj].X;
5597 if (fabs(dX) > fVertex3DCut)
continue;
5600 geom->IntersectionPoint(
geo::WireID{plane_i, hamrVec[ipl][ii].Wire},
5604 if (y < YLo || y > YHi || z < ZLo || z > ZHi)
continue;
5606 hamrVec[ipl][ii].Used =
true;
5607 hamrVec[jpl][jj].Used =
true;
5611 newVtx3.
X = 0.5 * (hamrVec[ipl][ii].X + hamrVec[jpl][jj].X);
5613 newVtx3.
XErr = fabs(hamrVec[ipl][ii].
X - hamrVec[jpl][jj].
X);
5618 newVtx3.
CStat = cstat;
5623 newVtx2.
Wire = hamrVec[ipl][ii].Wire;
5625 newVtx2.
Time = hamrVec[ipl][ii].Tick;
5628 newVtx2.
Fixed =
false;
5629 icl = hamrVec[ipl][ii].longClIndex;
5630 newVtx2.
CTP = tcl[icl].CTP;
5631 vtx.push_back(newVtx2);
5632 unsigned short ivnew = vtx.size() - 1;
5634 tcl[icl].EndVtx = ivnew;
5637 newVtx3.
Ptr2D[ipl] = (short)ivnew;
5639 icl = hamrVec[ipl][ii].shortClIndex;
5640 splitPos = hamrVec[ipl][ii].splitPos;
5641 if (!SplitCluster(icl, splitPos, ivnew))
return;
5644 newVtx2.
Wire = hamrVec[jpl][jj].Wire;
5645 newVtx2.
Time = hamrVec[jpl][jj].Tick;
5647 jcl = hamrVec[jpl][jj].longClIndex;
5648 newVtx2.
CTP = tcl[jcl].CTP;
5649 vtx.push_back(newVtx2);
5650 ivnew = vtx.size() - 1;
5652 tcl[jcl].EndVtx = ivnew;
5654 newVtx3.
Ptr2D[jpl] = (short)(vtx.size() - 1);
5657 jcl = hamrVec[jpl][jj].shortClIndex;
5658 splitPos = hamrVec[jpl][jj].splitPos;
5659 if (!SplitCluster(jcl, splitPos, vtx.size() - 1))
return;
5663 newVtx3.
Ptr2D[kpl] = -1;
5666 newVtx3.
Wire = geom->NearestWireID(WPos,
geo::PlaneID{cstat, tpc, kpl}).Wire;
5671 vtx3.push_back(newVtx3);
5691 float YLo = world.Y() - TPC.
HalfHeight() + 1;
5692 float YHi = world.Y() + TPC.
HalfHeight() - 1;
5693 float ZLo = world.Z() - TPC.
Length() / 2 + 1;
5694 float ZHi = world.Z() + TPC.
Length() / 2 - 1;
5696 vtxprt = (fDebugPlane >= 0) && (fDebugHit == 6666);
5704 float wirePitch = geom->WirePitch(
geo::PlaneID{tpcid, 0});
5707 std::vector<float> vX(vtx.size());
5708 std::vector<float> vXsigma(vtx.size());
5710 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5711 if (vtx[ivx].NClusters == 0)
continue;
5713 if (iplID.
TPC != tpc || iplID.
Cryostat != cstat)
continue;
5718 (
double)(vtx[ivx].Time + vtx[ivx].TimeErr), (
int)iplID.
Plane, (
int)tpc, (
int)cstat);
5719 vXsigma[ivx] = fabs(vXp - vX[ivx]);
5723 std::array<std::vector<unsigned short>, 3> vIndex;
5724 unsigned short indx, ipl;
5725 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5726 if (vtx[ivx].NClusters == 0)
continue;
5728 if (iplID.
TPC != tpc || iplID.
Cryostat != cstat)
continue;
5730 if (ipl > 2)
continue;
5731 indx = vIndex[ipl].size();
5732 vIndex[ipl].resize(indx + 1);
5733 vIndex[ipl][indx] = ivx;
5737 std::vector<short> vPtr;
5738 for (
unsigned short ii = 0; ii < vtx.size(); ++ii)
5742 std::vector<Vtx3Store> v3temp;
5744 double y = 0,
z = 0;
5747 unsigned short ii, jpl, jj, kpl, kk, ivx, jvx, kvx;
5748 unsigned int iWire, jWire;
5749 unsigned short v3dBest = 0;
5750 float xbest = 0, ybest = 0, zbest = 0;
5754 for (ipl = 0; ipl < 2; ++ipl) {
5756 for (ii = 0; ii < vIndex[ipl].size(); ++ii) {
5757 ivx = vIndex[ipl][ii];
5758 if (ivx > vtx.size() - 1) {
5763 if (vPtr[ivx] >= 0)
continue;
5764 iWire = vtx[ivx].Wire;
5765 float best = fVertex3DCut;
5769 std::array<short, 3> t2dIndex = {{-1, -1, -1}};
5770 std::array<short, 3> tmpIndex = {{-1, -1, -1}};
5771 for (jpl = ipl + 1; jpl < 3; ++jpl) {
5773 for (jj = 0; jj < vIndex[jpl].size(); ++jj) {
5774 jvx = vIndex[jpl][jj];
5775 if (jvx > vtx.size() - 1) {
5780 if (vPtr[jvx] >= 0)
continue;
5781 jWire = vtx[jvx].Wire;
5783 float dX = fabs(vX[ivx] - vX[jvx]);
5784 float dXSigma = sqrt(vXsigma[ivx] * vXsigma[ivx] + vXsigma[jvx] * vXsigma[jvx]);
5785 float dXChi = dX / dXSigma;
5789 <<
"VtxMatch: ipl " << ipl <<
" ivx " << ivx <<
" ivX " << vX[ivx] <<
" jpl " << jpl
5790 <<
" jvx " << jvx <<
" jvX " << vX[jvx] <<
" W:T " << (int)vtx[jvx].Wire <<
":" 5791 << (
int)vtx[jvx].Time <<
" dXChi " << dXChi <<
" fVertex3DCut " << fVertex3DCut;
5793 if (dXChi > fVertex3DCut)
continue;
5795 if (y < YLo || y > YHi || z < ZLo || z > ZHi)
continue;
5798 kpl = 3 - ipl - jpl;
5799 kX = 0.5 * (vX[ivx] + vX[jvx]);
5803 kWire = geom->NearestWireID(WPos,
geo::PlaneID{cstat, tpc, kpl}).Wire;
5809 kpl = 3 - ipl - jpl;
5813 tmpIndex[ipl] = ivx;
5814 tmpIndex[jpl] = jvx;
5816 v3d.
Ptr2D = tmpIndex;
5820 float yzSigma = wirePitch * sqrt(vtx[ivx].WireErr * vtx[ivx].WireErr +
5821 vtx[jvx].WireErr * vtx[jvx].WireErr);
5828 v3temp.push_back(v3d);
5832 <<
"VtxMatch: 2 Plane match ivx " << ivx <<
" P:W:T " << ipl <<
":" 5833 << (int)vtx[ivx].Wire <<
":" << (
int)vtx[ivx].Time <<
" jvx " << jvx <<
" P:W:T " 5834 << jpl <<
":" << (int)vtx[jvx].Wire <<
":" << (
int)vtx[jvx].Time <<
" dXChi " 5835 << dXChi <<
" yzSigma " << yzSigma;
5837 if (TPC.
Nplanes() == 2)
continue;
5839 best = fVertex3DCut;
5840 for (kk = 0; kk < vIndex[kpl].size(); ++kk) {
5841 kvx = vIndex[kpl][kk];
5842 if (vPtr[kvx] >= 0)
continue;
5844 float dW = wirePitch * (vtx[kvx].Wire -
kWire) / yzSigma;
5846 float dX = (vX[kvx] -
kX) / dXSigma;
5847 float kChi = 0.5 * sqrt(dW * dW + dX * dX);
5850 xbest = (vX[kvx] + 2 *
kX) / 3;
5853 t2dIndex[ipl] = ivx;
5854 t2dIndex[jpl] = jvx;
5855 t2dIndex[kpl] = kvx;
5856 v3dBest = v3temp.size() - 1;
5861 <<
" kvx " << kvx <<
" kpl " << kpl <<
" wire " << (int)vtx[kvx].Wire <<
" kTime " 5862 << (
int)vtx[kvx].Time <<
" kChi " << kChi <<
" best " << best <<
" dW " 5863 << vtx[kvx].Wire -
kWire;
5867 mf::LogVerbatim(
"CC") <<
" done best = " << best <<
" fVertex3DCut " << fVertex3DCut;
5868 if (TPC.
Nplanes() > 2 && best < fVertex3DCut) {
5870 if (v3dBest > v3temp.size() - 1) {
5871 mf::LogError(
"CC") <<
"VtxMatch: bad v3dBest " << v3dBest;
5875 v3d.
Ptr2D = t2dIndex;
5881 vtx3.push_back(v3d);
5884 for (
unsigned short jj = 0; jj < 3; ++jj)
5885 if (t2dIndex[jj] >= 0) vPtr[t2dIndex[jj]] = vtx3.size() - 1;
5889 <<
"New 3D vtx " << vtx3.size() <<
" X " << v3d.
X <<
" Y " << v3d.
Y <<
" Z " 5890 << v3d.
Z <<
" t2dIndex " << t2dIndex[0] <<
" " << t2dIndex[1] <<
" " 5891 << t2dIndex[2] <<
" best Chi " << best;
5903 unsigned short vsize = vtx3.size();
5904 for (
unsigned short it = 0; it < v3temp.size(); ++it) {
5906 for (
unsigned short i3d = 0; i3d < vsize; ++i3d) {
5907 for (
unsigned short plane = 0; plane < 3; ++plane) {
5908 if (v3temp[it].Ptr2D[plane] == vtx3[i3d].Ptr2D[plane]) {
5916 if (keepit) vtx3.push_back(v3temp[it]);
5921 for (
unsigned short iv3 = 0; iv3 < vtx3.size(); ++iv3) {
5922 vtx3[iv3].Ptr2D[2] = 666;
5927 for (
unsigned short it = 0; it < vtx3.size(); ++it) {
5928 mf::LogVerbatim(
"CC") <<
"vtx3 " << it <<
" Ptr2D " << vtx3[it].Ptr2D[0] <<
" " 5929 << vtx3[it].Ptr2D[1] <<
" " << vtx3[it].Ptr2D[2] <<
" wire " 5937 void ClusterCrawlerAlg::GetHitRange(
CTP_t CTP)
5943 unsigned int nwires = geom->Nwires(planeID);
5944 WireHitRange.resize(nwires + 1);
5950 unsigned int wire, iht;
5951 unsigned int nHitInPlane;
5952 std::pair<int, int> flag;
5957 for (
auto& apair : WireHitRange)
5962 std::vector<bool> firsthit;
5963 firsthit.resize(nwires + 1,
true);
5964 bool firstwire =
true;
5965 for (iht = 0; iht < fHits.size(); ++iht) {
5966 if (fHits[iht].
WireID().asPlaneID() != planeID)
continue;
5967 wire = fHits[iht].WireID().Wire;
5969 if (firsthit[wire]) {
5970 WireHitRange[wire].first = iht;
5971 firsthit[wire] =
false;
5977 WireHitRange[wire].second = iht + 1;
5978 fLastWire = wire + 1;
5982 lariov::ChannelStatusProvider
const& channelStatus =
5987 unsigned int nbad = 0;
5988 for (wire = 0; wire < nwires; ++wire) {
5990 if (!channelStatus.IsGood(chan)) {
5991 WireHitRange[wire] = flag;
5996 if (mergeAvailable.size() < fHits.size())
5998 <<
"GetHitRange: Invalid mergeAvailable vector size " << mergeAvailable.size()
6000 unsigned int firstHit, lastHit;
6003 float maxRMS, chiSep, peakCut;
6004 for (wire = 0; wire < nwires; ++wire) {
6006 if (WireHitRange[wire].first < 0)
continue;
6007 firstHit = WireHitRange[wire].first;
6008 lastHit = WireHitRange[wire].second;
6009 for (iht = firstHit; iht < lastHit; ++iht) {
6010 if (fHits[iht].
WireID().Wire != wire)
6012 <<
"Bad WireHitRange on wire " << wire <<
"\n";
6014 if (fHits[iht].Multiplicity() > 1) {
6015 peakCut = 0.6 * fHits[iht].PeakAmplitude();
6016 std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(iht);
6017 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
6018 if (jht == iht)
continue;
6020 if (fHits[jht].PeakAmplitude() < peakCut)
continue;
6021 maxRMS = std::max(fHits[iht].RMS(), fHits[jht].RMS());
6022 chiSep =
std::abs(fHits[iht].PeakTime() - fHits[jht].PeakTime()) / maxRMS;
6023 if (chiSep < fHitMergeChiCut) {
6024 mergeAvailable[iht] =
true;
6031 if (cnt != nHitInPlane)
6032 mf::LogWarning(
"CC") <<
"Bad WireHitRange count " << cnt <<
" " << nHitInPlane <<
"\n";
6034 if (!fMergeAllHits)
return;
6038 for (wire = 0; wire < nwires; ++wire) {
6039 if (WireHitRange[wire].first < 0)
continue;
6040 firstHit = WireHitRange[wire].first;
6041 lastHit = WireHitRange[wire].second;
6042 for (iht = firstHit; iht < lastHit; ++iht) {
6043 if (!mergeAvailable[iht])
continue;
6045 if (fHits[iht].GoodnessOfFit() == 6666)
continue;
6046 MergeHits(iht, didMerge);
6047 mergeAvailable[iht] =
false;
6056 if (inWire1 > inWire2) {
6058 unsigned int tmp = inWire1;
6063 unsigned int wire, ndead = 0;
6064 for (wire = inWire1; wire < inWire2; ++wire)
6065 if (WireHitRange[wire].first == -1) ++ndead;
6073 if (fcl2hits.size() < 2)
return 0;
6074 unsigned int wire, ndead = 0;
6075 unsigned int iht = fcl2hits[fcl2hits.size() - 1];
6076 unsigned int eWire = fHits[iht].WireID().Wire;
6078 unsigned int bWire = fHits[iht].WireID().Wire + 1;
6079 for (wire = eWire; wire < bWire; ++wire)
6080 if (WireHitRange[wire].first == -1) ++ndead;
6085 bool ClusterCrawlerAlg::areInSameMultiplet(
recob::Hit const& first_hit,
6093 std::pair<size_t, size_t> ClusterCrawlerAlg::FindHitMultiplet(
size_t iHit)
const 6095 std::pair<size_t, size_t> range{iHit, iHit};
6097 range.first = iHit - fHits[iHit].LocalIndex();
6098 range.second = range.first + fHits[iHit].Multiplicity();
6104 bool ClusterCrawlerAlg::CheckHitDuplicates(std::string location,
6105 std::string marker )
const 6108 unsigned int nDuplicates = 0;
6109 std::set<unsigned int>
hits;
6110 for (
unsigned int hit : fcl2hits) {
6111 if (hits.count(
hit)) {
6114 log <<
"Hit #" <<
hit 6115 <<
" being included twice in the future cluster (ID=" << (tcl.size() + 1)
6116 <<
"?) at location: " << location;
6117 if (!marker.empty()) log <<
" (marker: '" << marker <<
"')";
6121 return nDuplicates > 0;
6125 float ClusterCrawlerAlg::DoCA(
short icl,
unsigned short end,
float vwire,
float vtick)
6130 if (icl > (
short)tcl.size())
return 9999;
6132 float cwire, cslp, ctick;
6135 if (fcl2hits.size() == 0)
return 9999;
6151 cwire = tcl[icl].BeginWir;
6152 cslp = tcl[icl].BeginSlp;
6153 ctick = tcl[icl].BeginTim;
6156 cwire = tcl[icl].EndWir;
6157 cslp = tcl[icl].EndSlp;
6158 ctick = tcl[icl].EndTim;
6163 float docaW = (vwire + cslp * (vtick - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6164 float dW = docaW - vwire;
6165 float dT = ctick + (vwire - cwire) * cslp - vtick;
6166 return sqrt(dW * dW + dT * dT);
6171 float ClusterCrawlerAlg::ClusterVertexChi(
short icl,
unsigned short end,
unsigned short ivx)
6175 if (icl > (
short)tcl.size())
return 9999;
6176 if (ivx > vtx.size())
return 9999;
6178 float cwire, cslp, cslpErr, ctick;
6181 if (fcl2hits.size() == 0)
return 9999;
6186 cslpErr = clBeginSlpErr;
6192 cslpErr = clparerr[1];
6199 cwire = tcl[icl].BeginWir;
6200 cslp = tcl[icl].BeginSlp;
6201 cslpErr = tcl[icl].BeginSlpErr;
6202 ctick = tcl[icl].BeginTim;
6205 cwire = tcl[icl].EndWir;
6206 cslp = tcl[icl].EndSlp;
6207 cslpErr = tcl[icl].EndSlpErr;
6208 ctick = tcl[icl].EndTim;
6214 (vtx[ivx].Wire + cslp * (vtx[ivx].Time - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6215 float dW = docaW - vtx[ivx].Wire;
6216 float chi = dW / vtx[ivx].WireErr;
6217 float totChi = chi * chi;
6218 dW = vtx[ivx].Wire - cwire;
6219 float dT = ctick + dW * cslp - vtx[ivx].Time;
6220 if (cslpErr < 1
E-3) cslpErr = 1
E-3;
6222 cslpErr *= AngleFactor(cslp);
6224 float dTErr = dW * cslpErr;
6228 dTErr += vtx[ivx].TimeErr * vtx[ivx].TimeErr;
6229 if (dTErr < 1
E-3) dTErr = 1
E-3;
6230 totChi += dT * dT / dTErr;
6238 float ClusterCrawlerAlg::PointVertexChi(
float wire,
float tick,
unsigned short ivx)
6242 if (ivx > vtx.size())
return 9999;
6244 float dW = wire - vtx[ivx].Wire;
6245 float chi = dW / vtx[ivx].WireErr;
6246 float totChi = chi * chi;
6247 float dT = tick - vtx[ivx].Time;
6248 chi = dT / vtx[ivx].TimeErr;
6249 totChi += chi * chi;
6259 if (iht > fHits.size() - 1)
return "Bad Hit";
short int LocalIndex() const
How well do we believe we know this hit?
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
Functions to help with numbers.
geo::SigType_t SignalType() const
Signal type for the plane of the hit.
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Utilities related to art service access.
static unsigned int kWire
Encapsulate the construction of a single cyostat.
struct of temporary 2D vertices (end points)
unsigned int Nplanes() const
Number of planes in this tpc.
float RMS() const
RMS of the hit shape, in tick units.
Declaration of signal hit object.
Planes which measure X direction.
The data type to uniquely identify a Plane.
Geometry information for a single TPC.
double Temperature() const
In kelvin.
float SigmaPeakAmplitude() const
Uncertainty on estimated amplitude of the hit at its peak, in ADC units.
float SigmaIntegral() const
Initial tdc tick for hit.
constexpr auto abs(T v)
Returns the absolute value of the argument.
int DegreesOfFreedom() const
Initial tdc tick for hit.
CryostatID_t Cryostat
Index of cryostat.
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
struct of temporary clusters
geo::View_t View() const
View for the plane of the hit.
WireID_t Wire
Index of the wire within its plane.
geo::WireID const & WireID() const
Initial tdc tick for hit.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
Cluster finding and building.
float GoodnessOfFit() const
Degrees of freedom in the determination of the hit signal shape (-1 by default)
short int Multiplicity() const
How many hits could this one be shared with.
struct of temporary 3D vertices
float PeakAmplitude() const
The estimated amplitude of the hit at its peak, in ADC units.
double Length() const
Length is associated with z coordinate [cm].
constexpr int cmp(WireID const &other) const
Returns < 0 if this is smaller than tpcid, 0 if equal, > 0 if larger.
double Efield(unsigned int planegap=0) const
kV/cm
int TDCtick_t
Type representing a TDC tick.
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Access the description of detector geometry.
Point_t GetCenter() const
Returns the center of the TPC volume in world coordinates [cm].
Collection of exceptions for Geometry system.
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
float DeadWireCount(const TCSlice &slc, const TrajPoint &tp1, const TrajPoint &tp2)
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
T get(std::string const &key) const
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
double ConvertXToTicks(double X, int p, int t, int c) const
void MergeOverlap(std::string inFcnLabel, TCSlice &slc, const CTP_t &inCTP, bool prt)
unsigned int NumberTimeSamples() const
std::string PrintHit(const TCHit &tch)
bool SortByLowHit(unsigned int i, unsigned int j)
bool has_key(std::string const &key) const
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
The data type to uniquely identify a TPC.
PlaneID_t Plane
Index of the plane within its TPC.
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
float PeakTimeMinusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
std::array< short, 3 > Ptr2D
Detector simulation of raw signals on wires.
double ConvertTicksToX(double ticks, int p, int t, int c) const
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
double HalfHeight() const
Height is associated with y coordinate [cm].
bool greaterThan(CluLen c1, CluLen c2)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
float PeakTime() const
Time of the signal peak, in tick units.
Contains all timing reference information for the detector.
std::vector< unsigned int > tclhits
geo::PlaneID DecodeCTP(CTP_t CTP)
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
CTP_t EncodeCTP(unsigned int cryo, unsigned int tpc, unsigned int plane)
span(IterB &&b, IterE &&e, Adaptor &&adaptor) -> span< decltype(adaptor(std::forward< IterB >(b))), decltype(adaptor(std::forward< IterE >(e))) >
Exception thrown on invalid wire number.
float SummedADC() const
The sum of calibrated ADC counts of the hit (0. by default)
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
float SigmaPeakTime() const
Uncertainty for the signal peak, in tick units.
2D representation of charge deposited in the TDC/wire plane
float PeakTimePlusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
TPCID_t TPC
Index of the TPC within its cryostat.
second_as<> second
Type of time stored in seconds, in double precision.
geo::WireID suggestedWireID() const
Returns a better wire ID.
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
recob::tracking::Plane Plane
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
art framework interface to geometry description
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Encapsulate the construction of a single detector plane.