36 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h" 37 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h" 48 return c1.length > c2.length;
57 fNumPass = pset.
get<
unsigned short>(
"NumPass", 0);
58 fMaxHitsFit = pset.
get<std::vector<unsigned short>>(
"MaxHitsFit");
59 fMinHits = pset.
get<std::vector<unsigned short>>(
"MinHits");
60 fNHitsAve = pset.
get<std::vector<unsigned short>>(
"NHitsAve");
61 fChgCut = pset.
get<std::vector<float>>(
"ChgCut");
62 fChiCut = pset.
get<std::vector<float>>(
"ChiCut");
63 fMaxWirSkip = pset.
get<std::vector<unsigned short>>(
"MaxWirSkip");
64 fMinWirAfterSkip = pset.
get<std::vector<unsigned short>>(
"MinWirAfterSkip");
65 fKinkChiRat = pset.
get<std::vector<float>>(
"KinkChiRat");
66 fKinkAngCut = pset.
get<std::vector<float>>(
"KinkAngCut");
67 fDoMerge = pset.
get<std::vector<bool>>(
"DoMerge");
68 fTimeDelta = pset.
get<std::vector<float>>(
"TimeDelta");
69 fMergeChgCut = pset.
get<std::vector<float>>(
"MergeChgCut");
70 fFindVertices = pset.
get<std::vector<bool>>(
"FindVertices");
71 fLACrawl = pset.
get<std::vector<bool>>(
"LACrawl");
72 fMinAmp = pset.
get<std::vector<float>>(
"MinAmp", {5, 5, 5});
73 fChgNearWindow = pset.
get<
float>(
"ChgNearWindow");
74 fChgNearCut = pset.
get<
float>(
"ChgNearCut");
76 fChkClusterDS = pset.
get<
bool>(
"ChkClusterDS",
false);
77 fVtxClusterSplit = pset.
get<
bool>(
"VtxClusterSplit",
false);
78 fFindStarVertices = pset.
get<
bool>(
"FindStarVertices",
false);
79 if (pset.
has_key(
"HammerCluster")) {
81 <<
"fcl setting HammerCluster is replaced by FindHammerClusters. Ignoring...";
83 fFindHammerClusters = pset.
get<
bool>(
"FindHammerClusters",
false);
84 fKillGarbageClusters = pset.
get<
float>(
"KillGarbageClusters", 0);
85 fRefineVertexClusters = pset.
get<
bool>(
"RefineVertexClusters",
false);
86 fHitErrFac = pset.
get<
float>(
"HitErrFac", 0.2);
87 fHitMinAmp = pset.
get<
float>(
"HitMinAmp", 0.2);
88 fClProjErrFac = pset.
get<
float>(
"ClProjErrFac", 4);
89 fMinHitFrac = pset.
get<
float>(
"MinHitFrac", 0.6);
91 fLAClusAngleCut = pset.
get<
float>(
"LAClusAngleCut", 45);
92 fLAClusMaxHitsFit = pset.
get<
unsigned short>(
"LAClusMaxHitsFit");
93 fMergeAllHits = pset.
get<
bool>(
"MergeAllHits",
false);
94 fHitMergeChiCut = pset.
get<
float>(
"HitMergeChiCut", 2.5);
95 fMergeOverlapAngCut = pset.
get<
float>(
"MergeOverlapAngCut");
96 fAllowNoHitWire = pset.
get<
unsigned short>(
"AllowNoHitWire", 0);
97 fVertex2DCut = pset.
get<
float>(
"Vertex2DCut", 5);
98 fVertex2DWireErrCut = pset.
get<
float>(
"Vertex2DWireErrCut", 5);
99 fVertex3DCut = pset.
get<
float>(
"Vertex3DCut", 5);
101 fDebugPlane = pset.
get<
int>(
"DebugPlane", -1);
102 fDebugWire = pset.
get<
int>(
"DebugWire", -1);
103 fDebugHit = pset.
get<
int>(
"DebugHit", -1);
106 bool badinput =
false;
107 if (fNumPass > fMaxHitsFit.size()) badinput =
true;
108 if (fNumPass > fMinHits.size()) badinput =
true;
109 if (fNumPass > fNHitsAve.size()) badinput =
true;
110 if (fNumPass > fChgCut.size()) badinput =
true;
111 if (fNumPass > fChiCut.size()) badinput =
true;
112 if (fNumPass > fMaxWirSkip.size()) badinput =
true;
113 if (fNumPass > fMinWirAfterSkip.size()) badinput =
true;
114 if (fNumPass > fKinkChiRat.size()) badinput =
true;
115 if (fNumPass > fKinkAngCut.size()) badinput =
true;
116 if (fNumPass > fDoMerge.size()) badinput =
true;
117 if (fNumPass > fTimeDelta.size()) badinput =
true;
118 if (fNumPass > fMergeChgCut.size()) badinput =
true;
119 if (fNumPass > fFindVertices.size()) badinput =
true;
120 if (fNumPass > fLACrawl.size()) badinput =
true;
124 <<
"ClusterCrawlerAlg: Bad input from fcl file";
138 return a_tup < b_tup;
142 void ClusterCrawlerAlg::ClearResults()
152 void ClusterCrawlerAlg::CrawlInit()
178 WireHitRange.clear();
184 void ClusterCrawlerAlg::ClusterInit()
200 std::vector<recob::Hit>
const& srchits)
208 if (fHits.size() < 3)
return;
209 if (fHits.size() > UINT_MAX) {
210 mf::LogWarning(
"CC") <<
"Too many hits for ClusterCrawler " << fHits.size();
215 if (fNumPass == 0)
return;
220 std::sort(fHits.begin(), fHits.end(), &SortByMultiplet);
222 inClus.resize(fHits.size());
223 mergeAvailable.resize(fHits.size());
224 for (
unsigned int iht = 0; iht < inClus.size(); ++iht) {
226 mergeAvailable[iht] =
false;
231 cstat = tpcid.Cryostat;
234 plane = planeid.Plane;
235 WireHitRange.clear();
237 clCTP =
EncodeCTP(tpcid.Cryostat, tpcid.TPC, planeid.Plane);
238 cstat = tpcid.Cryostat;
245 if (WireHitRange.empty() || (fFirstWire == fLastWire))
continue;
249 float wirePitch = wireReadoutGeom->Plane(tpcid, wireReadoutGeom->View(channel)).WirePitch();
252 fScaleF = tickToDist / wirePitch;
254 if (fLAClusAngleCut > 0)
255 fLAClusSlopeCut = std::tan(3.142 * fLAClusAngleCut / 180.) / fScaleF;
257 fNumWires = wireReadoutGeom->Nwires(planeid);
259 if (fNumPass > 0) ClusterLoop();
261 if (fVertex3DCut > 0) {
263 VtxMatch(det_prop, tpcid);
264 Vtx3ClusterMatch(det_prop, tpcid);
265 if (fFindHammerClusters) FindHammerClusters(det_prop);
267 Vtx3ClusterSplit(det_prop, tpcid);
269 if (fDebugPlane >= 0) {
276 WireHitRange.clear();
283 RemoveObsoleteHits();
288 void ClusterCrawlerAlg::ClusterLoop()
292 unsigned int nHitsUsed = 0, iwire, jwire, kwire;
293 bool AllDone =
false, SigOK =
false, HitOK =
false;
294 unsigned int ihit, jhit;
295 for (
unsigned short thispass = 0; thispass < fNumPass; ++thispass) {
298 unsigned int span = 3;
299 if (fMinHits[pass] < span) span = fMinHits[pass];
300 for (iwire = fLastWire; iwire > fFirstWire +
span; --iwire) {
302 if (WireHitRange[iwire].first < 0)
continue;
303 auto ifirsthit = (
unsigned int)WireHitRange[iwire].first;
304 auto ilasthit = (
unsigned int)WireHitRange[iwire].
second;
305 for (ihit = ifirsthit; ihit < ilasthit; ++ihit) {
306 bool ClusterAdded =
false;
309 if (ihit > fHits.size() - 1) {
310 mf::LogError(
"CC") <<
"ClusterLoop bad ihit " << ihit <<
" fHits size " << fHits.size();
314 if (inClus[ihit] != 0)
continue;
316 if (fHits[ihit].PeakAmplitude() < fHitMinAmp)
continue;
317 if ((iwire + 1) < span)
continue;
318 jwire = iwire - span + 1;
322 if (WireHitRange[jwire].first == -2)
continue;
323 if (WireHitRange[jwire].first == -1) {
325 unsigned int nmissed = 0;
326 while (WireHitRange[jwire].first == -1 && jwire > 1 && nmissed < fMaxWirSkip[pass]) {
332 <<
" new jwire " << jwire <<
" dead? " << WireHitRange[jwire].first;
333 if (WireHitRange[jwire].first < 0)
continue;
337 unsigned int useHit = 0;
338 bool doConstrain =
false;
339 VtxConstraint(iwire, ihit, jwire, useHit, doConstrain);
340 unsigned int jfirsthit = (
unsigned int)WireHitRange[jwire].first;
341 unsigned int jlasthit = (
unsigned int)WireHitRange[jwire].
second;
342 if (jfirsthit > fHits.size() - 1 || jfirsthit > fHits.size() - 1)
344 <<
"ClusterLoop jwire " << jwire <<
" bad firsthit " << jfirsthit <<
" lasthit " 345 << jlasthit <<
" fhits size " << fHits.size();
346 for (jhit = jfirsthit; jhit < jlasthit; ++jhit) {
347 if (jhit > fHits.size() - 1)
349 <<
"ClusterLoop bad jhit " << jhit <<
" firsthit " << jfirsthit <<
" lasthit " 350 << jlasthit <<
" fhits size" << fHits.size();
352 if (doConstrain && jhit != useHit)
continue;
355 if (inClus[jhit] != 0)
continue;
357 if (fHits[jhit].PeakAmplitude() < fHitMinAmp)
continue;
360 fcl2hits.push_back(ihit);
361 chifits.push_back(0.);
362 hitNear.push_back(0);
363 chgNear.push_back(0);
365 fcl2hits.push_back(jhit);
366 chifits.push_back(0.);
367 hitNear.push_back(0);
368 chgNear.push_back(0);
373 clparerr[1] = 0.2 *
std::abs(clpar[1]);
374 clpar[2] = fHits[jhit].WireID().Wire;
378 for (kwire = jwire + 1; kwire < iwire; ++kwire) {
380 if (CrawlVtxChk(kwire)) {
384 AddHit(kwire, HitOK, SigOK);
386 mf::LogVerbatim(
"CC") <<
" HitOK " << HitOK <<
" clChisq " << clChisq <<
" cut " 387 << fChiCut[pass] <<
" ClusterHitsOK " << ClusterHitsOK(-1);
391 if (clChisq > 2)
break;
393 if (!ClusterHitsOK(-1))
continue;
398 prt = (fDebugPlane == (int)plane && (
int)iwire == fDebugWire &&
402 <<
"ADD >>>>> Starting cluster with hits " <<
PrintHit(fcl2hits[0]) <<
" " 403 <<
PrintHit(fcl2hits[1]) <<
" " <<
PrintHit(fcl2hits[2]) <<
" on pass " << pass;
407 clBeginSlp = clpar[1];
410 if (!fLACrawl[pass] &&
std::abs(clBeginSlp) > fLAClusSlopeCut)
continue;
413 if (CrawlVtxChk2())
continue;
414 clBeginSlpErr = clparerr[1];
418 for (
unsigned short kk = 0; kk < fcl2hits.size(); ++kk) {
419 fAveHitWidth += fHits[fcl2hits[kk]].EndTick() - fHits[fcl2hits[kk]].StartTick();
421 fAveHitWidth /= (float)fcl2hits.size();
427 if (fLACrawl[pass] && fLAClusSlopeCut > 0) {
429 if (
std::abs(clBeginSlp) > fLAClusSlopeCut) { LACrawlUS(); }
438 if (fcl2hits.size() >= fMinHits[pass]) {
441 clEndSlpErr = clparerr[1];
444 mf::LogError(
"CC") <<
"Failed to store cluster in plane " << plane;
448 nHitsUsed += fcl2hits.size();
449 AllDone = (nHitsUsed == fHits.size());
456 if (ClusterAdded || AllDone)
break;
464 if (fDoMerge[pass]) ChkMerge();
466 if (fFindVertices[pass]) FindVertices();
473 if (fKillGarbageClusters > 0 && !tcl.empty()) KillGarbageClusters();
477 if (fChkClusterDS) ChkClusterDS();
479 if (fVtxClusterSplit) {
480 bool didSomething = VtxClusterSplit();
482 if (didSomething) VtxClusterSplit();
485 if (fFindStarVertices) FindStarVertices();
487 if (fDebugPlane == (
int)plane) {
492 CheckHitClusterAssociations();
497 void ClusterCrawlerAlg::KillGarbageClusters()
501 if (tcl.size() < 2)
return;
503 unsigned short icl, jcl;
506 std::vector<float> iHits, jHits;
510 float sepcut = 0, iFrac, jFrac;
512 unsigned short iLoIndx, jLoIndx, olapSize, iop, ii, jj;
513 unsigned short nclose;
516 std::vector<unsigned short> killMe;
518 for (icl = 0; icl < tcl.size() - 1; ++icl) {
519 if (tcl[icl].ID < 0)
continue;
520 if (tcl[icl].CTP != clCTP)
continue;
524 iHits.resize(tcl[icl].BeginWir - tcl[icl].EndWir + 1, 1000);
526 for (
auto iht : tcl[icl].tclhits) {
527 indx = fHits[iht].WireID().Wire - tcl[icl].EndWir;
528 if (indx > iHits.size() - 1) {
529 mf::LogWarning(
"CC") <<
"KillGarbageClusters: icl ID " << tcl[icl].ID <<
" Bad indx " 530 << indx <<
" " << iHits.size() <<
"\n";
533 iHits[indx] = fHits[iht].PeakTime();
534 iChg += fHits[iht].Integral();
535 if (first) sepcut += fHits[iht].RMS();
538 sepcut /= (float)tcl[icl].tclhits.size();
544 for (jcl = icl + 1; jcl < tcl.size(); ++jcl) {
545 if (tcl[jcl].ID < 0)
continue;
546 if (tcl[jcl].CTP != clCTP)
continue;
548 if (tcl[icl].BeginWir < tcl[jcl].EndWir)
continue;
549 if (tcl[icl].EndWir > tcl[jcl].BeginWir)
continue;
551 if (
std::abs(tcl[icl].BeginAng - tcl[jcl].BeginAng) > fKillGarbageClusters)
continue;
553 if (tcl[icl].EndWir < tcl[jcl].EndWir) {
557 iLoIndx = tcl[jcl].EndWir - tcl[icl].EndWir;
559 if (tcl[icl].BeginWir < tcl[jcl].BeginWir) {
563 olapSize = tcl[icl].BeginWir - tcl[jcl].EndWir + 1;
569 olapSize = tcl[jcl].BeginWir - tcl[jcl].EndWir + 1;
577 jLoIndx = tcl[icl].EndWir - tcl[icl].EndWir;
578 if (tcl[icl].BeginWir < tcl[jcl].BeginWir) {
582 olapSize = tcl[icl].BeginWir - tcl[icl].EndWir + 1;
588 olapSize = tcl[jcl].BeginWir - tcl[icl].EndWir + 1;
593 jHits.resize(tcl[jcl].BeginWir - tcl[jcl].EndWir + 1, -1000);
595 for (
auto jht : tcl[jcl].tclhits) {
596 indx = fHits[jht].WireID().Wire - tcl[jcl].EndWir;
597 if (indx > jHits.size() - 1) {
598 mf::LogWarning(
"CC") <<
"KillGarbageClusters: jcl ID " << tcl[jcl].ID <<
" Bad indx " 599 << indx <<
" " << jHits.size() <<
"\n";
602 jHits[indx] = fHits[jht].PeakTime();
603 jChg += fHits[jht].Integral();
607 for (iop = 0; iop < olapSize; ++iop) {
609 if (ii > iHits.size() - 1)
continue;
611 if (jj > jHits.size() - 1)
continue;
612 if (
std::abs(iHits[ii] - jHits[jj]) < sepcut) ++nclose;
614 iFrac = (float)nclose / (
float)iHits.size();
615 jFrac = (float)nclose / (
float)jHits.size();
616 if (iFrac < 0.5 && jFrac < 0.5)
continue;
617 doKill = (iFrac < jFrac && iChg > jChg);
618 if (doKill) killMe.push_back(jcl);
622 if (killMe.size() == 0)
return;
623 for (
auto icl : killMe) {
625 if (tcl[icl].ID < 0)
continue;
626 tcl[icl].ProcCode = 666;
627 MakeClusterObsolete(icl);
646 unsigned short icl, jcl;
648 bool chkprt = (fDebugWire == 666);
649 if (chkprt)
mf::LogVerbatim(
"CC") <<
"Inside MergeOverlap using clCTP " << clCTP;
651 unsigned short minLen = 6;
652 unsigned short minOvrLap = 2;
655 float maxDTick = fTimeDelta[fTimeDelta.size() - 1];
657 unsigned int overlapSize, ii, indx, bWire, eWire;
658 unsigned int iht, jht;
659 float dang, prtime, dTick;
660 for (icl = 0; icl < tcl.size(); ++icl) {
661 if (tcl[icl].ID < 0)
continue;
662 if (tcl[icl].CTP != clCTP)
continue;
663 prt = chkprt && fDebugPlane == (int)clCTP;
664 if (tcl[icl].BeginVtx >= 0)
continue;
665 if (tcl[icl].tclhits.size() < minLen)
continue;
666 for (jcl = 0; jcl < tcl.size(); ++jcl) {
667 if (icl == jcl)
continue;
668 if (tcl[jcl].ID < 0)
continue;
669 if (tcl[jcl].CTP != clCTP)
continue;
670 if (tcl[jcl].EndVtx >= 0)
continue;
671 if (tcl[jcl].tclhits.size() < minLen)
continue;
673 if (tcl[icl].BeginWir < tcl[jcl].EndWir + minOvrLap)
continue;
675 if (tcl[icl].BeginWir > tcl[jcl].BeginWir - minOvrLap)
continue;
677 if (tcl[jcl].EndWir < tcl[icl].EndWir + minOvrLap)
continue;
678 dang =
std::abs(tcl[icl].BeginAng - tcl[jcl].EndAng);
680 mf::LogVerbatim(
"CC") <<
"MergeOverlap icl ID " << tcl[icl].ID <<
" jcl ID " 681 << tcl[jcl].ID <<
" dang " << dang;
682 if (dang > 0.5)
continue;
683 overlapSize = tcl[icl].BeginWir - tcl[jcl].EndWir + 1;
684 eWire = tcl[jcl].EndWir;
685 bWire = tcl[icl].BeginWir;
687 mf::LogVerbatim(
"CC") <<
" Candidate icl ID " << tcl[icl].ID <<
" " << tcl[icl].EndWir
688 <<
"-" << tcl[icl].BeginWir <<
" jcl ID " << tcl[jcl].ID <<
" " 689 << tcl[jcl].EndWir <<
"-" << tcl[jcl].BeginWir <<
" overlapSize " 690 << overlapSize <<
" bWire " << bWire <<
" eWire " << eWire;
693 for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
694 iht = tcl[icl].tclhits[ii];
695 if (fHits[iht].
WireID().Wire < eWire)
break;
698 dTick =
std::abs(fHits[iht].PeakTime() - tcl[jcl].EndTim);
699 if (dTick > maxDTick)
continue;
702 << tcl[jcl].EndTim <<
" dTick " << dTick;
703 for (ii = 0; ii < tcl[jcl].tclhits.size(); ++ii) {
704 jht = tcl[jcl].tclhits[tcl[jcl].tclhits.size() - ii - 1];
705 if (fHits[jht].
WireID().Wire > bWire)
break;
707 dTick =
std::abs(fHits[jht].PeakTime() - tcl[icl].BeginTim);
708 if (dTick > maxDTick)
continue;
711 << tcl[icl].BeginTim <<
" dTick " << dTick;
713 clpar[0] = fHits[iht].PeakTime();
714 clpar[2] = fHits[iht].WireID().Wire;
715 clpar[1] = (fHits[jht].PeakTime() - fHits[iht].PeakTime()) /
716 ((
float)fHits[jht].WireID().Wire - clpar[2]);
718 std::vector<unsigned int> oWireHits(overlapSize, INT_MAX);
719 std::vector<float> delta(overlapSize, maxDTick);
720 for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
721 iht = tcl[icl].tclhits[ii];
722 if (fHits[iht].
WireID().Wire < eWire)
break;
723 prtime = clpar[0] + clpar[1] * ((float)fHits[iht].
WireID().Wire - clpar[2]);
724 dTick =
std::abs(fHits[iht].PeakTime() - prtime);
725 indx = fHits[iht].WireID().Wire - eWire;
726 if (dTick > delta[indx])
continue;
728 oWireHits[indx] = iht;
731 for (ii = 0; ii < tcl[jcl].tclhits.size(); ++ii) {
732 jht = tcl[jcl].tclhits[tcl[jcl].tclhits.size() - ii - 1];
733 if (fHits[jht].
WireID().Wire > bWire)
break;
734 prtime = clpar[0] + clpar[1] * ((float)fHits[jht].
WireID().Wire - clpar[2]);
735 dTick =
std::abs(fHits[jht].PeakTime() - prtime);
736 indx = fHits[jht].WireID().Wire - eWire;
737 if (dTick > delta[indx])
continue;
739 oWireHits[indx] = jht;
743 for (ii = 0; ii < oWireHits.size(); ++ii) {
744 if (oWireHits[ii] == INT_MAX)
continue;
746 fcl2hits.push_back(iht);
749 if (fcl2hits.size() < 0.5 * overlapSize)
continue;
750 if (fcl2hits.size() < 3)
continue;
751 std::sort(fcl2hits.begin(), fcl2hits.end(),
SortByLowHit);
754 mf::LogVerbatim(
"CC") <<
" Overlap size " << overlapSize <<
" fit chisq " << clChisq
755 <<
" nhits " << fcl2hits.size();
756 if (clChisq > 20)
continue;
758 std::vector<unsigned int> oHits = fcl2hits;
762 unsigned short jclNewSize;
763 for (jclNewSize = 0; jclNewSize < fcl2hits.size(); ++jclNewSize) {
764 iht = fcl2hits[jclNewSize];
765 if (fHits[iht].
WireID().Wire <= bWire)
break;
768 mf::LogVerbatim(
"CC") <<
"jcl old size " << fcl2hits.size() <<
" newSize " << jclNewSize;
769 iht = fcl2hits[fcl2hits.size() - 1];
770 unsigned int iiht = fcl2hits[jclNewSize - 1];
771 mf::LogVerbatim(
"CC") <<
"jcl old last wire " << fHits[iht].WireID().Wire
772 <<
" After resize last wire " << fHits[iiht].WireID().Wire;
774 fcl2hits.resize(jclNewSize);
776 fcl2hits.insert(fcl2hits.end(), oHits.begin(), oHits.end());
778 for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
779 iht = tcl[icl].tclhits[ii];
780 if ((
unsigned int)fHits[iht].WireID().Wire >= eWire)
continue;
781 fcl2hits.insert(fcl2hits.end(), tcl[icl].tclhits.begin() + ii, tcl[icl].tclhits.end());
784 clBeginSlp = tcl[jcl].BeginSlp;
785 clBeginSlpErr = tcl[jcl].BeginSlpErr;
786 clBeginAng = tcl[jcl].BeginAng;
787 clBeginWir = tcl[jcl].BeginWir;
788 clBeginTim = tcl[jcl].BeginTim;
789 clBeginChg = tcl[jcl].BeginChg;
790 clBeginChgNear = tcl[jcl].BeginChgNear;
792 clEndSlp = tcl[icl].EndSlp;
793 clEndSlpErr = tcl[icl].EndSlpErr;
794 clEndAng = tcl[icl].EndAng;
795 clEndWir = tcl[icl].EndWir;
796 clEndTim = tcl[icl].EndTim;
797 clEndChg = tcl[icl].EndChg;
798 clEndChgNear = tcl[icl].EndChgNear;
799 clStopCode = tcl[icl].StopCode;
800 clProcCode = tcl[icl].ProcCode + 500;
801 MakeClusterObsolete(icl);
802 MakeClusterObsolete(jcl);
805 RestoreObsoleteCluster(icl);
806 RestoreObsoleteCluster(jcl);
807 CheckHitClusterAssociations();
810 CheckHitClusterAssociations();
811 tcl[tcl.size() - 1].BeginVtx = tcl[jcl].BeginVtx;
812 tcl[tcl.size() - 1].EndVtx = tcl[icl].BeginVtx;
815 mf::LogVerbatim(
"CC") <<
"MergeOverlap new long cluster ID " << tcl[tcl.size() - 1].ID
816 <<
" in clCTP " << clCTP;
818 if (tcl[icl].ID < 0)
break;
825 void ClusterCrawlerAlg::MakeClusterObsolete(
unsigned short icl)
827 short& ID = tcl[icl].ID;
829 mf::LogError(
"CC") <<
"Trying to make already-obsolete cluster obsolete ID = " << ID;
835 for (
unsigned int iht = 0; iht < tcl[icl].tclhits.size(); ++iht)
836 inClus[tcl[icl].tclhits[iht]] = 0;
841 void ClusterCrawlerAlg::RestoreObsoleteCluster(
unsigned short icl)
843 short& ID = tcl[icl].ID;
845 mf::LogError(
"CC") <<
"Trying to restore non-obsolete cluster ID = " << ID;
850 for (
unsigned short iht = 0; iht < tcl[icl].tclhits.size(); ++iht)
851 inClus[tcl[icl].tclhits[iht]] = ID;
856 void ClusterCrawlerAlg::FclTrimUS(
unsigned short nTrim)
860 if (nTrim == 0)
return;
862 if (nTrim >= fcl2hits.size()) nTrim = fcl2hits.size();
865 for (
unsigned short ii = 0; ii < nTrim; ++ii) {
875 void ClusterCrawlerAlg::CheckHitClusterAssociations()
879 if (fHits.size() != inClus.size()) {
880 mf::LogError(
"CC") <<
"CHCA: Sizes wrong " << fHits.size() <<
" " << inClus.size();
884 unsigned int iht, nErr = 0;
888 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
889 if (tcl[icl].ID < 0)
continue;
891 for (
unsigned short ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
892 iht = tcl[icl].tclhits[ii];
893 if (iht > fHits.size() - 1) {
894 mf::LogError(
"CC") <<
"CHCA: Bad tclhits index " << iht <<
" fHits size " << fHits.size();
897 if (inClus[iht] != clID) {
898 mf::LogError(
"CC") <<
"CHCA: Bad cluster -> hit association. clID " << clID
899 <<
" hit inClus " << inClus[iht] <<
" ProcCode " << tcl[icl].ProcCode
900 <<
" CTP " << tcl[icl].CTP;
902 if (nErr > 10)
return;
909 for (iht = 0; iht < fHits.size(); ++iht) {
910 if (inClus[iht] <= 0)
continue;
911 icl = inClus[iht] - 1;
913 if (tcl[icl].ID < 0) {
914 mf::LogError(
"CC") <<
"CHCA: Hit associated with an obsolete cluster. hit W:T " 915 << fHits[iht].WireID().Wire <<
":" << (int)fHits[iht].PeakTime()
916 <<
" tcl[icl].ID " << tcl[icl].ID;
918 if (nErr > 10)
return;
920 if (std::find(tcl[icl].tclhits.begin(), tcl[icl].tclhits.end(), iht) ==
921 tcl[icl].tclhits.end()) {
922 mf::LogError(
"CC") <<
"CHCA: Bad hit -> cluster association. hit index " << iht <<
" W:T " 923 << fHits[iht].WireID().Wire <<
":" << (int)fHits[iht].PeakTime()
924 <<
" inClus " << inClus[iht];
926 if (nErr > 10)
return;
933 void ClusterCrawlerAlg::RemoveObsoleteHits()
936 unsigned int destHit = 0;
938 if (fHits.size() != inClus.size()) {
939 mf::LogError(
"CC") <<
"RemoveObsoleteHits size mis-match " << fHits.size() <<
" " 945 for (
unsigned int srcHit = 0; srcHit < fHits.size(); ++srcHit) {
946 if (inClus[srcHit] < 0)
continue;
947 if (srcHit != destHit) {
948 fHits[destHit] = std::move(fHits[srcHit]);
949 inClus[destHit] = inClus[srcHit];
950 if (inClus[destHit] > 0) {
952 icl = inClus[destHit] - 1;
953 auto&
hits = tcl[icl].tclhits;
954 auto iHitIndex = std::find(
hits.begin(),
hits.end(), srcHit);
955 if (iHitIndex ==
hits.end()) {
956 mf::LogError(
"CC") <<
"RemoveObsoleteHits: Hit #" << srcHit
957 <<
" not found in cluster ID " << inClus[destHit];
960 *iHitIndex = destHit;
967 fHits.resize(destHit);
968 inClus.resize(destHit);
973 void ClusterCrawlerAlg::ChkClusterDS()
980 prt = (fDebugPlane == 3);
983 float dThCut = fKinkAngCut[fNumPass - 1];
986 mf::LogVerbatim(
"CC") <<
"ChkClusterDS clCTP " << clCTP <<
" kink angle cut " << dThCut;
988 const unsigned short tclsize = tcl.size();
989 bool didMerge, skipit;
990 unsigned short icl, ii, nhm, iv;
994 for (icl = 0; icl < tclsize; ++icl) {
995 if (tcl[icl].ID < 0)
continue;
996 if (tcl[icl].CTP != clCTP)
continue;
998 if (tcl[icl].BeginVtx >= 0)
continue;
1001 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1002 if (vtx[iv].CTP != clCTP)
continue;
1003 if (
std::abs(vtx[iv].Wire - tcl[icl].BeginWir) > 4)
continue;
1004 if (
std::abs(vtx[iv].Time - tcl[icl].BeginTim) > 20)
continue;
1008 if (skipit)
continue;
1011 for (ii = 0; ii < 3; ++ii) {
1013 if (fHits[iht].Multiplicity() > 1) {
1014 MergeHits(iht, didMerge);
1015 if (didMerge) ++nhm;
1020 FitClusterMid(icl, 0, 3);
1021 tcl[icl].BeginTim = clpar[0];
1022 tcl[icl].BeginSlp = clpar[1];
1023 tcl[icl].BeginAng = atan(fScaleF * clpar[1]);
1024 tcl[icl].BeginSlpErr = clparerr[1];
1025 tcl[icl].BeginChg = fAveChg;
1026 tcl[icl].ProcCode += 5000;
1027 if (prt)
mf::LogVerbatim(
"CC") <<
"ChkClusterDS: Merge hits on cluster " << tcl[icl].ID;
1031 float thhits, prevth, hitrms, rmsrat;
1033 std::vector<unsigned int> dshits;
1034 for (icl = 0; icl < tclsize; ++icl) {
1035 if (tcl[icl].ID < 0)
continue;
1036 if (tcl[icl].CTP != clCTP)
continue;
1038 if (tcl[icl].BeginVtx >= 0)
continue;
1041 for (iv = 0; iv < vtx.size(); ++iv) {
1042 if (vtx[iv].CTP != clCTP)
continue;
1043 if (
std::abs(vtx[iv].Wire - tcl[icl].BeginWir) > 4)
continue;
1044 if (
std::abs(vtx[iv].Time - tcl[icl].BeginTim) > 20)
continue;
1048 if (skipit)
continue;
1050 unsigned int ih0 = tcl[icl].tclhits[1];
1051 unsigned int ih1 = tcl[icl].tclhits[0];
1052 const float slp = (fHits[ih1].PeakTime() - fHits[ih0].PeakTime()) /
1053 (fHits[ih1].
WireID().Wire - fHits[ih0].WireID().Wire);
1054 prevth = std::atan(fScaleF * slp);
1057 unsigned int wire = fHits[ih0].WireID().Wire;
1058 hitrms = fHits[ih0].RMS();
1059 float time0 = fHits[ih0].PeakTime();
1064 for (ii = 0; ii < 4; ++ii) {
1066 if (wire > fLastWire)
break;
1067 prtime = time0 + slp;
1069 mf::LogVerbatim(
"CC") <<
"ChkClusterDS: Try to extend " << tcl[icl].ID <<
" to W:T " 1070 << wire <<
" hitrms " << hitrms <<
" prevth " << prevth
1071 <<
" prtime " << (int)prtime;
1073 if (WireHitRange[wire].first == -2)
break;
1074 unsigned int firsthit = WireHitRange[wire].first;
1075 unsigned int lasthit = WireHitRange[wire].second;
1076 bool hitAdded =
false;
1077 for (ih1 = firsthit; ih1 < lasthit; ++ih1) {
1078 if (inClus[ih1] != 0)
continue;
1079 if (prtime < fHits[ih1].PeakTimeMinusRMS(5))
continue;
1080 if (prtime > fHits[ih1].PeakTimePlusRMS(5))
continue;
1081 const float slp = (fHits[ih1].PeakTime() - fHits[ih0].PeakTime()) /
1082 (fHits[ih1].
WireID().Wire - fHits[ih0].WireID().Wire);
1083 thhits = std::atan(fScaleF * slp);
1085 mf::LogVerbatim(
"CC") <<
" theta " << thhits <<
" prevth " << prevth <<
" cut " 1087 if (
std::abs(thhits - prevth) > dThCut)
continue;
1090 if (
std::abs(slp) < fLAClusSlopeCut) {
1091 rmsrat = fHits[ih1].RMS() / hitrms;
1092 ratOK = rmsrat > 0.3 && rmsrat < 3;
1097 MergeHits(ih1, didMerge);
1099 if (prt)
mf::LogVerbatim(
"CC") <<
" rmsrat " << rmsrat <<
" OK? " << ratOK;
1104 dshits.push_back(ih1);
1109 mf::LogVerbatim(
"CC") <<
" Add hit " << fHits[ih1].WireID().Wire <<
":" 1110 << (int)fHits[ih1].PeakTime() <<
" rmsrat " << rmsrat;
1115 if (!hitAdded)
break;
1118 if (dshits.size() > 0) {
1124 if (dshits.size() > 1) std::sort(dshits.begin(), dshits.end(),
SortByLowHit);
1128 for (ii = 0; ii < tcl[icl].tclhits.size(); ++ii) {
1130 iht = tcl[icl].tclhits[ii];
1132 fcl2hits.push_back(iht);
1135 pass = fNumPass - 1;
1137 clBeginChg = fAveChg;
1139 MakeClusterObsolete(icl);
1142 mf::LogError(
"CC") <<
"ChkClusterDS TmpStore failed while extending cluster ID " 1146 const size_t newcl = tcl.size() - 1;
1148 tcl[newcl].BeginVtx = tcl[icl].BeginVtx;
1149 tcl[newcl].EndVtx = tcl[icl].EndVtx;
1155 bool ClusterCrawlerAlg::CrawlVtxChk2()
1161 if (vtx.size() == 0)
return false;
1162 if (fcl2hits.size() == 0)
return false;
1164 unsigned int iht = fcl2hits.size() - 1;
1166 float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1168 float thclus = std::atan(fScaleF * clpar[1]);
1170 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1171 if (vtx[iv].CTP != clCTP)
continue;
1172 if (wire0 < vtx[iv].Wire)
continue;
1173 if (wire0 > vtx[iv].Wire + 10)
continue;
1174 dt = clpar[0] + (vtx[iv].Wire - wire0) * clpar[1] - vtx[iv].Time;
1178 for (icl = 0; icl < tcl.size(); ++icl) {
1179 if (tcl[icl].CTP != clCTP)
continue;
1180 if (tcl[icl].EndVtx != iv)
continue;
1181 if (
std::abs(tcl[icl].EndAng - thclus) < fKinkAngCut[pass])
return true;
1190 bool ClusterCrawlerAlg::CrawlVtxChk(
unsigned int kwire)
1194 if (vtx.size() == 0)
return false;
1195 unsigned int iht = fcl2hits.size() - 1;
1196 float wire0 = (0.5 + fHits[fcl2hits[iht]].WireID().Wire);
1197 float prtime = clpar[0] + (kwire - wire0) * clpar[1];
1198 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1199 if (vtx[iv].CTP != clCTP)
continue;
1200 if ((
unsigned int)(0.5 + vtx[iv].Wire) != kwire)
continue;
1201 if (
std::abs(prtime - vtx[iv].Time) < 10)
return true;
1207 void ClusterCrawlerAlg::VtxConstraint(
unsigned int iwire,
1210 unsigned int& useHit,
1216 doConstrain =
false;
1217 if (vtx.size() == 0)
return;
1219 if (pass == 0)
return;
1221 if (!fFindVertices[pass - 1])
return;
1223 if (jwire > WireHitRange.size() - 1) {
1224 mf::LogError(
"CC") <<
"VtxConstraint fed bad jwire " << jwire <<
" WireHitRange size " 1225 << WireHitRange.size();
1229 unsigned int jfirsthit = WireHitRange[jwire].first;
1230 unsigned int jlasthit = WireHitRange[jwire].second;
1231 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1232 if (vtx[iv].CTP != clCTP)
continue;
1234 if (vtx[iv].Wire > jwire)
continue;
1236 if (vtx[iv].Wire < jwire - 10)
continue;
1239 clpar[1] = (vtx[iv].Time - hit.
PeakTime()) / (vtx[iv].Wire - iwire);
1241 float prtime = clpar[0] + clpar[1] * (jwire - iwire);
1242 for (
unsigned int jhit = jfirsthit; jhit < jlasthit; ++jhit) {
1243 if (inClus[jhit] != 0)
continue;
1244 const float tdiff =
std::abs(fHits[jhit].TimeDistanceAsRMS(prtime));
1256 void ClusterCrawlerAlg::RefineVertexClusters(
unsigned short iv)
1261 std::vector<unsigned short> begClusters;
1262 std::vector<short> begdW;
1263 std::vector<unsigned short> endClusters;
1264 std::vector<short> enddW;
1266 unsigned int vWire = (
unsigned int)(vtx[iv].Wire + 0.5);
1267 unsigned int vWireErr = (
unsigned int)(2 * vtx[iv].WireErr);
1268 unsigned int vWireLo = vWire - vWireErr;
1269 unsigned int vWireHi = vWire + vWireErr;
1271 unsigned short icl, ii;
1273 bool needsWork =
false;
1276 for (icl = 0; icl < tcl.size(); ++icl) {
1277 if (tcl[icl].ID < 0)
continue;
1278 if (tcl[icl].CTP != vtx[iv].CTP)
continue;
1279 if (tcl[icl].BeginVtx == iv) {
1280 dW = vWire - tcl[icl].BeginWir;
1281 if (dW > maxdW) maxdW = dW;
1282 if (dW < mindW) mindW = dW;
1283 if (
std::abs(dW) > 1) needsWork =
true;
1285 begClusters.push_back(icl);
1286 begdW.push_back(dW);
1288 if (tcl[icl].EndVtx == iv) {
1289 dW = vWire - tcl[icl].EndWir;
1290 if (dW > maxdW) maxdW = dW;
1291 if (dW < mindW) mindW = dW;
1292 if (
std::abs(dW) > 1) needsWork =
true;
1293 endClusters.push_back(icl);
1294 enddW.push_back(dW);
1299 mf::LogVerbatim(
"CC") <<
"RefineVertexClusters: vertex " << iv <<
" needsWork " << needsWork
1300 <<
" mindW " << mindW <<
" maxdW " << maxdW <<
" vWireErr " << vWireErr;
1302 if (!needsWork)
return;
1306 if (((
unsigned int)
std::abs(mindW) < vWireErr) && ((
unsigned int)
std::abs(maxdW) < vWireErr) &&
1308 if (vtxprt)
mf::LogVerbatim(
"CC") <<
" Move vtx wire " << vtx[iv].Wire;
1309 vtx[iv].Wire -= (float)(maxdW + mindW) / 2;
1312 vtx[iv].Fixed =
true;
1319 unsigned short newSize;
1320 for (ii = 0; ii < endClusters.size(); ++ii) {
1321 icl = endClusters[ii];
1323 mf::LogVerbatim(
"CC") <<
" endCluster " << tcl[icl].ID <<
" dW " << enddW[ii] <<
" vWire " 1325 if (tcl[icl].EndWir < vWire) {
1328 newSize = fcl2hits.size();
1329 for (
auto hiter = fcl2hits.rbegin(); hiter < fcl2hits.rend(); ++hiter) {
1330 if (fHits[*hiter].
WireID().Wire > vWire)
break;
1334 for (
auto hiter = fcl2hits.begin(); hiter < fcl2hits.end(); ++hiter)
1337 fcl2hits.resize(newSize);
1338 MakeClusterObsolete(icl);
1344 tcl[tcl.size() - 1].EndVtx = iv;
1347 mf::LogVerbatim(
"CC") <<
" modified cluster " << tcl[icl].ID <<
" -> " 1348 << tcl[tcl.size() - 1].ID;
1350 else if (tcl[icl].EndWir > vWire) {
1351 mf::LogVerbatim(
"CC") <<
"RefineVertexClusters: Write some EndVtx code";
1355 if (begClusters.size() > 0)
1356 mf::LogVerbatim(
"CC") <<
"RefineVertexClusters: Write some BeginVtx code";
1358 if (mindW < 0 && maxdW > 0) {
1363 unsigned short clsBigChg = 0;
1368 for (ii = 0; ii < begClusters.size(); ++ii) {
1369 icl = begClusters[ii];
1370 for (iht = 0; iht < tcl[icl].tclhits.size(); ++iht) {
1371 ihit = tcl[icl].tclhits[iht];
1372 if (fHits[ihit].Integral() > bigChg) {
1373 bigChg = fHits[ihit].Integral();
1377 if (fHits[ihit].
WireID().Wire < vWireLo)
break;
1381 for (ii = 0; ii < endClusters.size(); ++ii) {
1382 icl = endClusters[ii];
1383 for (iht = 0; iht < tcl[icl].tclhits.size(); ++iht) {
1384 ihit = tcl[icl].tclhits[tcl[icl].tclhits.size() - 1 - iht];
1385 if (fHits[ihit].Integral() > bigChg) {
1386 bigChg = fHits[ihit].Integral();
1390 if (fHits[ihit].
WireID().Wire > vWireHi)
break;
1395 mf::LogVerbatim(
"CC") <<
" moving vertex location to hit " << fHits[vtxHit].WireID().Wire
1396 <<
":" << (int)fHits[vtxHit].PeakTime() <<
" on cluster " 1397 << tcl[clsBigChg].ID;
1398 vtx[iv].Wire = fHits[vtxHit].WireID().Wire;
1399 vtx[iv].Time = fHits[vtxHit].PeakTime();
1400 vtx[iv].Fixed =
true;
1409 bool ClusterCrawlerAlg::VtxClusterSplit()
1414 vtxprt = (fDebugPlane >= 0 && fDebugWire == 5555);
1418 if (vtx.size() == 0)
return false;
1419 unsigned short tclsize = tcl.size();
1420 if (tclsize < 2)
return false;
1423 bool didSomething =
false;
1425 for (
unsigned short icl = 0; icl < tclsize; ++icl) {
1426 if (tcl[icl].ID < 0)
continue;
1427 if (tcl[icl].CTP != clCTP)
continue;
1429 if (tcl[icl].tclhits.size() < 5)
continue;
1432 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
1433 if (vtx[ivx].CTP != clCTP)
continue;
1435 if (vtx[ivx].NClusters == 0)
continue;
1437 if (tcl[icl].BeginVtx == ivx)
continue;
1438 if (tcl[icl].EndVtx == ivx)
continue;
1440 if (vtx[ivx].Wire < tcl[icl].EndWir)
continue;
1441 if (vtx[ivx].Wire > tcl[icl].BeginWir)
continue;
1443 float hiTime = tcl[icl].BeginTim;
1444 if (tcl[icl].EndTim > hiTime) hiTime = tcl[icl].EndTim;
1445 if (vtx[ivx].Time > hiTime + 5)
continue;
1446 float loTime = tcl[icl].BeginTim;
1447 if (tcl[icl].EndTim < loTime) loTime = tcl[icl].EndTim;
1448 if (vtx[ivx].Time < loTime - 5)
continue;
1452 mf::LogVerbatim(
"CC") <<
" Chk cluster ID " << tcl[icl].ID <<
" with vertex " << ivx;
1456 unsigned short nSplit = 0;
1457 unsigned short nLop = 0;
1459 for (
unsigned short ii = tcl[icl].tclhits.size() - 1; ii > 0; --ii) {
1460 iht = tcl[icl].tclhits[ii];
1462 if (fHits[iht].
WireID().Wire >= vtx[ivx].Wire) {
1465 mf::LogVerbatim(
"CC") <<
"Split cluster " << tcl[icl].ID <<
" at wire " 1466 << fHits[iht].WireID().Wire <<
" nSplit " << nSplit;
1472 if (ihvx < 0)
continue;
1473 if (fabs(fHits[ihvx].PeakTime() - vtx[ivx].Time) > 10)
continue;
1478 if (nSplit > tcl[icl].tclhits.size() / 2) { iclAng = tcl[icl].EndAng; }
1480 iclAng = tcl[icl].BeginAng;
1485 for (
unsigned short jcl = 0; jcl < tclsize; ++jcl) {
1486 if (tcl[jcl].ID < 0)
continue;
1487 if (tcl[jcl].CTP != clCTP)
continue;
1488 if (tcl[jcl].BeginVtx == ivx) {
1489 if (fabs(tcl[jcl].BeginAng - iclAng) > 0.4) {
1495 if (tcl[jcl].EndVtx == ivx) {
1496 if (fabs(tcl[jcl].EndAng - iclAng) > 0.4) {
1510 for (
unsigned short ii = 0; ii < nLop; ++ii) {
1511 unsigned int iht = fcl2hits[fcl2hits.size() - 1];
1513 fcl2hits.pop_back();
1518 MakeClusterObsolete(icl);
1520 if (!TmpStore())
continue;
1521 unsigned short newcl = tcl.size() - 1;
1522 tcl[newcl].BeginVtx = tcl[icl].BeginVtx;
1523 tcl[newcl].EndVtx = ivx;
1529 if (SplitCluster(icl, nSplit, ivx)) {
1530 tcl[tcl.size() - 1].ProcCode += 1000;
1531 tcl[tcl.size() - 2].ProcCode += 1000;
1535 didSomething =
true;
1541 return didSomething;
1546 void ClusterCrawlerAlg::MergeHits(
const unsigned int theHit,
bool& didMerge)
1560 if (theHit > fHits.size() - 1) {
return; }
1565 if (fHits[theHit].GoodnessOfFit() == 6666) {
1567 mf::LogVerbatim(
"CC") <<
"MergeHits Trying to merge already merged hit " 1570 <<
" theHit " << theHit;
1575 if (!mergeAvailable[theHit]) {
return; }
1580 std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(theHit);
1583 if (MultipletRange.second <= MultipletRange.first)
return;
1586 unsigned short nAvailable = 0;
1587 unsigned short nInClus = 0;
1588 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1589 if (jht == theHit)
continue;
1590 if (fHits[jht].GoodnessOfFit() == 6666)
continue;
1591 if (inClus[jht] != 0) {
1597 if (nAvailable == 0)
return;
1599 if (nInClus > 0)
return;
1605 short loTime = 9999;
1607 unsigned short nGaus = 1;
1610 unsigned short nclose = 0;
1612 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1613 if (inClus[jht] < 0)
continue;
1621 if (inClus[jht] != 0)
continue;
1623 if (arg < loTime) loTime = arg;
1625 if (arg > hiTime) hiTime = arg;
1626 if (jht != theHit) ++nGaus;
1628 if (jht != theHit && hitSep < 3) ++nclose;
1631 if (nGaus < 2)
return;
1634 const short int NewMultiplicity = hit.
Multiplicity() + 1 - nGaus;
1636 if (loTime < 0) loTime = 0;
1639 std::vector<double> signal(hiTime - loTime, 0.);
1642 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
1644 if (jht != theHit) {
1646 if (inClus[jht] != 0)
continue;
1652 for (
unsigned short time = loTime; time < hiTime; ++time) {
1653 unsigned short indx = time - loTime;
1654 double arg = (other_hit.
PeakTime() - (double)time) / other_hit.
RMS();
1655 signal[indx] += other_hit.
PeakAmplitude() * exp(-0.5 * arg * arg);
1660 double sigsumt = 0.;
1661 for (
unsigned short time = loTime; time < hiTime; ++time) {
1662 sigsum += signal[time - loTime];
1663 sigsumt += signal[time - loTime] * time;
1669 double aveTime = sigsumt / sigsum;
1672 for (
unsigned short time = loTime; time < hiTime; ++time) {
1673 double dtime = time - aveTime;
1674 sigsumt += signal[time - loTime] * dtime * dtime;
1676 const float RMS = std::sqrt(sigsumt / sigsum);
1678 const float amplitude = chgsum * chgNorm / (2.507 * RMS);
1700 FixMultipletLocalIndices(MultipletRange.first, MultipletRange.second);
1706 void ClusterCrawlerAlg::FixMultipletLocalIndices(
size_t begin,
1708 short int multiplicity )
1720 if (multiplicity < 0) {
1722 for (
size_t iHit = begin; iHit <
end; ++iHit) {
1723 if (inClus[iHit] < 0)
continue;
1729 short int local_index = 0;
1730 for (
size_t iHit = begin; iHit <
end; ++iHit) {
1731 if (inClus[iHit] < 0)
continue;
1762 void ClusterCrawlerAlg::FindStarVertices()
1769 if (tcl.size() < 2)
return;
1774 vtxprt = (fDebugPlane == (int)plane && fDebugHit < 0);
1780 unsigned short vtxSizeIn = vtx.size();
1784 float dsl = 0, dth = 0;
1785 float es1 = 0, es2 = 0;
1786 float eth1 = 0, eth2 = 0;
1787 float bt1 = 0, bt2 = 0;
1788 float et1 = 0, et2 = 0;
1789 float bw1 = 0, bw2 = 0;
1790 float ew1 = 0, ew2 = 0;
1791 float lotime = 0, hitime = 0, nwirecut = 0;
1792 unsigned short tclsize = tcl.size();
1793 for (
unsigned short it1 = 0; it1 < tclsize - 1; ++it1) {
1795 if (tcl[it1].ID < 0)
continue;
1796 if (tcl[it1].CTP != clCTP)
continue;
1798 if (tcl[it1].tclhits.size() > 100) {
1799 dth = tcl[it1].BeginAng - tcl[it1].EndAng;
1802 es1 = tcl[it1].EndSlp;
1803 eth1 = tcl[it1].EndAng;
1804 ew1 = tcl[it1].EndWir;
1805 et1 = tcl[it1].EndTim;
1806 bw1 = tcl[it1].BeginWir;
1807 bt1 = tcl[it1].BeginTim;
1808 for (
unsigned short it2 = it1 + 1; it2 < tclsize; ++it2) {
1809 if (tcl[it2].ID < 0)
continue;
1810 if (tcl[it2].CTP != clCTP)
continue;
1812 if (tcl[it2].tclhits.size() > 100) {
1813 dth = tcl[it2].BeginAng - tcl[it2].EndAng;
1814 if (
std::abs(dth) < 0.05)
continue;
1816 es2 = tcl[it2].EndSlp;
1817 eth2 = tcl[it2].EndAng;
1818 ew2 = tcl[it2].EndWir;
1819 et2 = tcl[it2].EndTim;
1820 bw2 = tcl[it2].BeginWir;
1821 bt2 = tcl[it2].BeginTim;
1824 if (dth < 0.3)
continue;
1826 fvw = (et1 - ew1 * es1 - et2 + ew2 * es2) / dsl;
1828 if (fvw < ew1 || fvw > bw1)
continue;
1829 if (fvw < ew2 || fvw > bw2)
continue;
1831 mf::LogVerbatim(
"CC") <<
"Chk clusters " << tcl[it1].ID <<
" " << tcl[it2].ID
1832 <<
" topo5 vtx wire " << fvw;
1835 if (tcl[it1].tclhits.size() > tcl[it2].tclhits.size()) {
1836 if (tcl[it1].tclhits.size() > 20) {
1837 nwirecut = 0.5 * tcl[it1].tclhits.size();
1838 if ((fvw - ew1) > nwirecut)
continue;
1842 if (tcl[it2].tclhits.size() > 20) {
1843 nwirecut = 0.5 * tcl[it2].tclhits.size();
1844 if ((fvw - ew2) > nwirecut)
continue;
1847 fvt = et1 + (fvw - ew1) * es1;
1850 if (et1 < lotime) lotime = et1;
1851 if (bt1 < lotime) lotime = bt1;
1852 if (et2 < lotime) lotime = et2;
1853 if (bt2 < lotime) lotime = bt2;
1855 if (et1 > hitime) hitime = et1;
1856 if (bt1 > hitime) hitime = bt1;
1857 if (et2 > hitime) hitime = et2;
1858 if (bt2 > hitime) hitime = bt2;
1859 if (fvt < lotime || fvt > hitime)
continue;
1861 mf::LogVerbatim(
"CC") <<
" vertex time " << fvt <<
" lotime " << lotime <<
" hitime " 1863 unsigned int vw = (0.5 + fvw);
1865 unsigned int pos1 = 0;
1866 for (
unsigned short ii = 0; ii < tcl[it1].tclhits.size(); ++ii) {
1867 if (fHits[tcl[it1].tclhits[ii]].
WireID().Wire <= vw) {
1868 if (
std::abs(
int(fHits[tcl[it1].tclhits[ii]].PeakTime() - fvt)) < 10) pos1 = ii;
1873 if (pos1 == 0)
continue;
1874 unsigned short pos2 = 0;
1875 for (
unsigned short ii = 0; ii < tcl[it2].tclhits.size(); ++ii) {
1876 if (fHits[tcl[it2].tclhits[ii]].
WireID().Wire <= vw) {
1877 if (
std::abs(
int(fHits[tcl[it2].tclhits[ii]].PeakTime() - fvt)) < 10) pos2 = ii;
1882 if (pos2 == 0)
continue;
1884 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1885 if (
std::abs(fvw - vtx[iv].Wire) < 2 &&
std::abs(fvt - vtx[iv].Time) < 10)
continue;
1895 newvx.
Fixed =
false;
1896 vtx.push_back(newvx);
1897 unsigned short ivx = vtx.size() - 1;
1899 mf::LogVerbatim(
"CC") <<
" new vertex " << ivx <<
" cluster " << tcl[it1].ID
1900 <<
" split pos " << pos1;
1901 if (!SplitCluster(it1, pos1, ivx))
continue;
1902 tcl[tcl.size() - 1].ProcCode += 1000;
1903 tcl[tcl.size() - 2].ProcCode += 1000;
1905 mf::LogVerbatim(
"CC") <<
" new vertex " << ivx <<
" cluster " << tcl[it2].ID
1906 <<
" split pos " << pos2;
1907 if (!SplitCluster(it2, pos2, ivx))
continue;
1908 tcl[tcl.size() - 1].ProcCode += 1000;
1909 tcl[tcl.size() - 2].ProcCode += 1000;
1915 if (vtx.size() > vtxSizeIn) {
1919 VertexCluster(vtx.size() - 1);
1925 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
1926 if (vtx[iv].CTP != clCTP)
continue;
1927 mf::LogVerbatim(
"CC") <<
"vtx " << iv <<
" wire " << vtx[iv].Wire <<
" time " 1928 << (int)vtx[iv].Time <<
" NClusters " << vtx[iv].NClusters <<
" topo " 1937 void ClusterCrawlerAlg::VertexCluster(
unsigned short iv)
1940 if (vtx[iv].NClusters == 0)
return;
1942 short dwb, dwe, dtb, dte;
1945 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
1946 if (tcl[icl].ID < 0)
continue;
1947 if (tcl[icl].CTP != vtx[iv].CTP)
continue;
1949 dwb = vtx[iv].Wire - tcl[icl].BeginWir;
1950 dtb = vtx[iv].Time - tcl[icl].BeginTim;
1951 dwe = vtx[iv].Wire - tcl[icl].EndWir;
1952 dte = vtx[iv].Time - tcl[icl].EndTim;
1954 float drb = dwb * dwb + dtb * dtb;
1955 float dre = dwe * dwe + dte * dte;
1957 bool bCloser = (drb < dre);
1961 if (tcl[icl].BeginChgNear > fChgNearCut)
continue;
1964 if (tcl[icl].EndChgNear > fChgNearCut)
continue;
1968 mf::LogVerbatim(
"CC") <<
"VertexCluster: Try icl ID " << tcl[icl].ID <<
" w vtx " << iv
1969 <<
" dwb " << dwb <<
" dwe " << dwe <<
" drb " << drb <<
" dre " 1970 << dre <<
" Begin closer? " << bCloser;
1972 if (tcl[icl].BeginVtx < 0 && bCloser && dwb > -3 && dwb < 3 && tcl[icl].EndVtx != iv) {
1973 sigOK = ChkSignal(tcl[icl].BeginWir, tcl[icl].BeginTim, vtx[iv].Wire, vtx[iv].Time);
1975 mf::LogVerbatim(
"CC") <<
" Attach cluster Begin to vtx? " << iv <<
" sigOK " << sigOK;
1978 mf::LogVerbatim(
"CC") <<
" check ClusterVertexChi " << ClusterVertexChi(icl, 0, iv);
1979 if (ClusterVertexChi(icl, 0, iv) < fVertex2DCut) {
1981 tcl[icl].BeginVtx = iv;
1983 if (vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
1984 tcl[icl].BeginVtx = -99;
1991 if (tcl[icl].EndVtx < 0 && !bCloser && dwe > -3 && dwe < 3 && tcl[icl].BeginVtx != iv) {
1992 sigOK = ChkSignal(tcl[icl].EndWir, tcl[icl].EndTim, vtx[iv].Wire, vtx[iv].Time);
1994 mf::LogVerbatim(
"CC") <<
" Attach cluster End to vtx? " << iv <<
" sigOK " << sigOK;
1997 mf::LogVerbatim(
"CC") <<
" check ClusterVertexChi " << ClusterVertexChi(icl, 1, iv);
1998 if (ClusterVertexChi(icl, 1, iv) < 3) {
2000 tcl[icl].EndVtx = iv;
2002 if (vtx[iv].ChiDOF > fVertex2DCut || vtx[iv].WireErr > fVertex2DWireErrCut) {
2003 tcl[icl].EndVtx = -99;
2013 void ClusterCrawlerAlg::FitAllVtx(
CTP_t inCTP)
2016 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
2017 if (vtx[iv].CTP != inCTP)
continue;
2024 void ClusterCrawlerAlg::FindVertices()
2028 if (tcl.size() < 2)
return;
2031 std::vector<CluLen> clulens;
2033 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
2034 if (tcl[icl].ID < 0)
continue;
2035 if (tcl[icl].CTP != clCTP)
continue;
2036 if (tcl[icl].BeginVtx >= 0 && tcl[icl].EndVtx >= 0)
continue;
2038 clulen.length = tcl[icl].tclhits.size();
2039 clulens.push_back(clulen);
2041 if (
empty(clulens))
return;
2042 std::sort(clulens.begin(), clulens.end(),
greaterThan);
2044 float nwires = fNumWires;
2045 float maxtime = fMaxTime;
2047 unsigned short vtxSizeIn = vtx.size();
2049 vtxprt = (fDebugPlane == (short)plane && fDebugHit < 0);
2051 mf::LogVerbatim(
"CC") <<
"FindVertices plane " << plane <<
" pass " << pass;
2055 float es1 = 0, eth1 = 0, ew1 = 0, et1 = 0;
2056 float bs1 = 0, bth1 = 0, bw1 = 0, bt1 = 0;
2057 float es2 = 0, eth2 = 0, ew2 = 0, et2 = 0;
2058 float bs2 = 0, bth2 = 0, bw2 = 0, bt2 = 0;
2059 float dth = 0, dsl = 0, fvw = 0, fvt = 0;
2061 unsigned int vw = 0, pass1, pass2, ii1, it1, ii2, it2;
2063 for (ii1 = 0; ii1 < clulens.size() - 1; ++ii1) {
2064 it1 = clulens[ii1].index;
2065 es1 = tcl[it1].EndSlp;
2066 eth1 = tcl[it1].EndAng;
2067 ew1 = tcl[it1].EndWir;
2068 et1 = tcl[it1].EndTim;
2069 bs1 = tcl[it1].BeginSlp;
2070 bth1 = tcl[it1].BeginAng;
2071 bw1 = tcl[it1].BeginWir;
2072 bt1 = tcl[it1].BeginTim;
2073 pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
2074 for (ii2 = ii1 + 1; ii2 < clulens.size(); ++ii2) {
2075 it2 = clulens[ii2].index;
2079 if (tcl[it1].tclhits.size() < 5 && tcl[it2].tclhits.size() < 5)
continue;
2080 es2 = tcl[it2].EndSlp;
2081 eth2 = tcl[it2].EndAng;
2082 ew2 = tcl[it2].EndWir;
2083 et2 = tcl[it2].EndTim;
2084 bs2 = tcl[it2].BeginSlp;
2085 bth2 = tcl[it2].BeginAng;
2086 bw2 = tcl[it2].BeginWir;
2087 bt2 = tcl[it2].BeginTim;
2088 pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
2089 if (pass1 < pass2) { angcut = fKinkAngCut[pass2]; }
2091 angcut = fKinkAngCut[pass1];
2094 dth = fabs(eth1 - eth2);
2095 if (tcl[it1].EndVtx < 0 && tcl[it2].EndVtx < 0 && dth > 0.1) {
2098 fvw = (et1 - ew1 * es1 - et2 + ew2 * es2) / dsl;
2100 if (fvw > 0. && fvw < nwires) {
2105 if (vw >= fFirstWire - 1 && fvw <= ew1 + 3 && fvw <= ew2 + 3 && fvw > (ew1 - 10) &&
2107 fvt = et1 + (fvw - ew1) * es1;
2110 <<
"Chk clusters topo1 " << tcl[it1].ID <<
" " << tcl[it2].ID <<
" vtx wire " 2111 << vw <<
" time " << (int)fvt <<
" dth " << dth;
2112 if (fvt > 0 && fvt < maxtime) {
2116 SigOK = ChkSignal(vw, fvt, vw, fvt);
2120 SigOK = ChkSignal(vw, fvt, vw, fvt);
2123 if (SigOK) ChkVertex(fvw, fvt, it1, it2, 1);
2130 if (tcl[it1].EndVtx < 0 && tcl[it2].BeginVtx < 0 && dth > angcut) {
2132 if (fabs(ew1 - bw2) < 3 && fabs(et1 - bt2) < 500) { fvw = 0.5 * (ew1 + bw2); }
2134 fvw = (et1 - ew1 * es1 - bt2 + bw2 * bs2) / dsl;
2136 if (fvw > 0 && fvw < nwires) {
2141 if (fvw <= ew1 + 2 && fvw >= bw2 - 2) {
2142 fvt = et1 + (vw - ew1) * es1;
2143 fvt += bt2 + (vw - bw2) * bs2;
2147 <<
"Chk clusters topo2 " << tcl[it1].ID <<
" " << tcl[it2].ID <<
" vtx wire " 2148 << vw <<
" time " << (int)fvt <<
" dth " << dth;
2149 if (fvt > 0. && fvt < maxtime) {
2150 ChkVertex(fvw, fvt, it1, it2, 2);
2157 if (tcl[it1].BeginVtx < 0 && tcl[it2].EndVtx < 0 && dth > angcut) {
2159 if (fabs(bw1 - ew2) < 3 && fabs(bt1 - et2) < 500) { fvw = 0.5 * (bw1 + ew2); }
2161 fvw = (et2 - ew2 * es2 - bt1 + bw1 * bs1) / dsl;
2163 if (fvw > 0 && fvw < nwires) {
2167 if (fvw <= ew2 + 2 && fvw >= bw1 - 2) {
2168 fvt = et2 + (fvw - ew2) * es2;
2169 fvt += bt1 + (fvw - bw1) * es1;
2173 <<
"Chk clusters topo3 " << tcl[it1].ID <<
" " << tcl[it2].ID <<
" vtx wire " 2174 << vw <<
" time " << (int)fvt <<
" dth " << dth;
2175 if (fvt > 0. && fvt < maxtime) {
2176 ChkVertex(fvw, fvt, it1, it2, 3);
2183 if (tcl[it1].BeginVtx < 0 && tcl[it2].BeginVtx < 0 && dth > 0.1) {
2187 fvw = (bt1 - bw1 * bs1 - bt2 + bw2 * bs2) / dsl;
2189 mf::LogVerbatim(
"CC") <<
"Chk clusters topo4 " << bw1 <<
":" << (int)bt1 <<
" " << bw2
2190 <<
":" << (
int)bt2 <<
" fvw " << fvw <<
" nwires " << nwires;
2191 if (fvw > 0 && fvw < nwires) {
2197 if (tcl[it1].tclhits.size() < 2 * dwcut) dwcut = tcl[it1].tclhits.size() / 2;
2198 if (tcl[it2].tclhits.size() < 2 * dwcut) dwcut = tcl[it2].tclhits.size() / 2;
2199 if (fvw <= fLastWire + 1 && fvw >= bw1 - dwcut && fvw <= bw1 + dwcut &&
2200 fvw >= bw2 - dwcut && fvw <= bw1 + dwcut) {
2201 fvt = bt1 + (fvw - bw1) * bs1;
2204 <<
" vtx wire " << vw <<
" time " << fvt <<
" dth " << dth <<
" dwcut " << dwcut;
2205 if (fvt > 0. && fvt < maxtime) {
2209 SigOK = ChkSignal(vw, fvt, vw, fvt);
2213 SigOK = ChkSignal(vw, fvt, vw, fvt);
2216 if (SigOK) ChkVertex(fvw, fvt, it1, it2, 4);
2226 for (
unsigned short it = 0; it < tcl.size(); ++it) {
2227 if (tcl[it].ID < 0)
continue;
2228 if (tcl[it].CTP != clCTP)
continue;
2229 if (tcl[it].BeginVtx > -1 && tcl[it].BeginVtx == tcl[it].EndVtx) {
2230 unsigned short iv = tcl[it].BeginVtx;
2231 float dwir = tcl[it].BeginWir - vtx[iv].Wire;
2232 float dtim = tcl[it].BeginTim - vtx[iv].Time;
2233 float rbeg = dwir * dwir + dtim * dtim;
2234 dwir = tcl[it].EndWir - vtx[iv].Wire;
2235 dtim = tcl[it].EndTim - vtx[iv].Time;
2236 float rend = dwir * dwir + dtim * dtim;
2237 if (rend < rbeg) { tcl[it].EndVtx = -99; }
2239 tcl[it].BeginVtx = -99;
2244 if (vtx.size() > vtxSizeIn) FitAllVtx(clCTP);
2247 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
2248 if (vtx[ivx].CTP != clCTP)
continue;
2249 if (vtx[ivx].NClusters == 1) {
2250 vtx[ivx].NClusters = 0;
2251 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
2252 if (tcl[icl].CTP != clCTP)
continue;
2253 if (tcl[icl].BeginVtx == ivx) {
2254 tcl[icl].BeginVtx = -99;
2257 if (tcl[icl].EndVtx == ivx) {
2258 tcl[icl].EndVtx = -99;
2268 void ClusterCrawlerAlg::ClusterVertex(
unsigned short it)
2272 if (vtx.size() == 0)
return;
2274 unsigned short iv, jv;
2275 short dwib, dwjb, dwie, dwje;
2276 bool matchEnd, matchBegin;
2278 for (iv = 0; iv < vtx.size(); ++iv) {
2280 if (vtx[iv].CTP != clCTP)
continue;
2282 if (vtx[iv].NClusters == 0)
continue;
2286 if (tcl[it].tclhits.size() < 6) {
2288 dwib =
std::abs(vtx[iv].Wire - tcl[it].BeginWir);
2289 if (dwib > 2) dwib = 2;
2290 dwie =
std::abs(vtx[iv].Wire - tcl[it].EndWir);
2291 if (dwie > 2) dwie = 2;
2294 for (jv = 0; jv < vtx.size(); ++jv) {
2295 if (iv == jv)
continue;
2296 if (
std::abs(vtx[jv].Time - tcl[it].BeginTim) < 50) {
2297 if (
std::abs(vtx[jv].Wire - tcl[it].BeginWir) < dwjb)
2298 dwjb =
std::abs(vtx[jv].Wire - tcl[it].BeginWir);
2300 if (
std::abs(vtx[jv].Time - tcl[it].EndTim) < 50) {
2301 if (
std::abs(vtx[jv].Wire - tcl[it].EndWir) < dwje)
2302 dwje =
std::abs(vtx[jv].Wire - tcl[it].EndWir);
2305 matchEnd = tcl[it].EndVtx != iv && dwie < 3 && dwie < dwje && dwie < dwib;
2306 matchBegin = tcl[it].BeginVtx != iv && dwib < 3 && dwib < dwjb && dwib < dwie;
2309 matchEnd = tcl[it].EndVtx < 0 && vtx[iv].Wire <= tcl[it].EndWir + 2;
2310 matchBegin = tcl[it].BeginVtx < 0 && vtx[iv].Wire >= tcl[it].BeginWir - 2;
2314 mf::LogVerbatim(
"CC") <<
" Match End chi " << ClusterVertexChi(it, 1, iv) <<
" to vtx " 2315 << iv <<
" signalOK " 2317 vtx[iv].Wire, vtx[iv].Time, tcl[it].EndWir, tcl[it].EndTim);
2318 if (ClusterVertexChi(it, 1, iv) < fVertex2DCut &&
2319 ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].EndWir, tcl[it].EndTim)) {
2321 tcl[it].EndVtx = iv;
2325 mf::LogVerbatim(
"CC") <<
" Add End " << tcl[it].ID <<
" to vtx " << iv <<
" NClusters " 2326 << vtx[iv].NClusters;
2327 if (vtx[iv].ChiDOF < fVertex2DCut && vtx[iv].WireErr < fVertex2DWireErrCut)
return;
2329 mf::LogVerbatim(
"CC") <<
" Bad fit. ChiDOF " << vtx[iv].ChiDOF <<
" WireErr " 2330 << vtx[iv].WireErr <<
" Undo it";
2331 tcl[it].EndVtx = -99;
2338 mf::LogVerbatim(
"CC") <<
" Match Begin chi " << ClusterVertexChi(it, 0, iv) <<
" to vtx " 2339 << iv <<
" signalOK " 2340 << ChkSignal(vtx[iv].Wire,
2344 if (ClusterVertexChi(it, 0, iv) < fVertex2DCut &&
2345 ChkSignal(vtx[iv].Wire, vtx[iv].Time, tcl[it].BeginWir, tcl[it].BeginTim)) {
2347 tcl[it].BeginVtx = iv;
2351 mf::LogVerbatim(
"CC") <<
" Add Begin " << tcl[it].ID <<
" to vtx " << iv
2352 <<
" NClusters " << vtx[iv].NClusters;
2353 if (vtx[iv].ChiDOF < fVertex2DCut && vtx[iv].WireErr < fVertex2DWireErrCut)
return;
2355 mf::LogVerbatim(
"CC") <<
" Bad fit. ChiDOF " << vtx[iv].ChiDOF <<
" WireErr " 2356 << vtx[iv].WireErr <<
" Undo it";
2357 tcl[it].BeginVtx = -99;
2365 void ClusterCrawlerAlg::ChkVertex(
float fvw,
2380 mf::LogVerbatim(
"CC") <<
" ChkVertex " << tcl[it1].EndWir <<
":" << (int)tcl[it1].EndTim
2381 <<
" - " << tcl[it1].BeginWir <<
":" << (
int)tcl[it1].BeginTim
2382 <<
" and " << tcl[it2].EndWir <<
":" << (int)tcl[it2].EndTim <<
" - " 2383 << tcl[it2].BeginWir <<
":" << (
int)tcl[it2].BeginTim <<
" topo " 2384 << topo <<
" fvw " << fvw <<
" fvt " << fvt;
2386 unsigned int vw = (
unsigned int)(0.5 + fvw);
2392 if (tcl[it1].tclhits.size() < 10 && tcl[it2].tclhits.size() < 10) {
2393 for (
unsigned short it = 0; it < tcl.size(); ++it) {
2394 if (it == it1 || it == it2)
continue;
2395 if (tcl[it].ID < 0)
continue;
2396 if (tcl[it].CTP != clCTP)
continue;
2397 if (tcl[it].tclhits.size() < 100)
continue;
2398 if (
std::abs(tcl[it].BeginAng - tcl[it].EndAng) > 0.1)
continue;
2400 if (vw < tcl[it].EndWir + 5)
continue;
2401 if (vw > tcl[it].BeginWir - 5)
continue;
2402 for (
unsigned short ii = 0; ii < tcl[it].tclhits.size(); ++ii) {
2403 iht = tcl[it].tclhits[ii];
2404 if (fHits[iht].
WireID().Wire <= vw) {
2405 if (
std::abs(fHits[iht].PeakTime() - fvt) < 60)
return;
2412 unsigned short nFitOK = 0;
2413 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
2414 if (vtx[iv].CTP != clCTP)
continue;
2416 if (PointVertexChi(fvw, fvt, iv) > 300)
continue;
2419 << PointVertexChi(fvw, fvt, iv);
2421 if ((topo == 1 || topo == 2) && tcl[it1].EndVtx < 0) {
2422 if (ChkSignal(vw, fvt, tcl[it1].EndWir, tcl[it1].EndTim)) {
2424 tcl[it1].EndVtx = iv;
2427 mf::LogVerbatim(
"CC") <<
" FitVtx " << iv <<
" WireErr " << vtx[iv].WireErr
2428 <<
" ChiDOF " << vtx[iv].ChiDOF;
2429 if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2432 tcl[it1].EndVtx = -99;
2437 else if ((topo == 3 || topo == 4) && tcl[it1].BeginVtx < 0) {
2438 if (ChkSignal(vw, fvt, tcl[it1].BeginWir, tcl[it1].BeginTim)) {
2439 tcl[it1].BeginVtx = iv;
2442 mf::LogVerbatim(
"CC") <<
" FitVtx " << iv <<
" WireErr " << vtx[iv].WireErr
2443 <<
" ChiDOF " << vtx[iv].ChiDOF;
2444 if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2447 tcl[it1].BeginVtx = -99;
2452 if ((topo == 1 || topo == 3) && tcl[it2].EndVtx < 0) {
2453 if (ChkSignal(vw, fvt, tcl[it2].EndWir, tcl[it2].EndTim)) {
2454 tcl[it2].EndVtx = iv;
2457 mf::LogVerbatim(
"CC") <<
" FitVtx " << iv <<
" WireErr " << vtx[iv].WireErr
2458 <<
" ChiDOF " << vtx[iv].ChiDOF;
2459 if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2462 tcl[it2].EndVtx = -99;
2467 else if ((topo == 2 || topo == 4) && tcl[it2].BeginVtx < 0) {
2468 if (ChkSignal(vw, fvt, tcl[it2].BeginWir, tcl[it2].BeginTim)) {
2469 tcl[it2].BeginVtx = iv;
2472 mf::LogVerbatim(
"CC") <<
" FitVtx " << iv <<
" WireErr " << vtx[iv].WireErr
2473 <<
" ChiDOF " << vtx[iv].ChiDOF;
2474 if (vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].ChiDOF < 5) { ++nFitOK; }
2477 tcl[it2].BeginVtx = -99;
2483 if (vtxprt)
mf::LogVerbatim(
"CC") <<
" Attached " << nFitOK <<
" clusters to vertex " << iv;
2491 if (topo == 1 || topo == 2) { SigOK = ChkSignal(vw, fvt, tcl[it1].EndWir, tcl[it1].EndTim); }
2493 SigOK = ChkSignal(vw, fvt, tcl[it1].BeginWir, tcl[it1].BeginTim);
2497 if (topo == 1 || topo == 3) { SigOK = ChkSignal(vw, fvt, tcl[it2].EndWir, tcl[it2].EndTim); }
2499 SigOK = ChkSignal(vw, fvt, tcl[it2].BeginWir, tcl[it2].BeginTim);
2508 newvx.
Fixed =
false;
2509 vtx.push_back(newvx);
2510 unsigned short iv = vtx.size() - 1;
2511 if (topo == 1 || topo == 2) {
2512 if (tcl[it1].EndVtx >= 0) {
2516 tcl[it1].EndVtx = iv;
2519 if (tcl[it1].BeginVtx >= 0) {
2523 tcl[it1].BeginVtx = iv;
2525 if (topo == 1 || topo == 3) {
2526 if (tcl[it2].EndVtx >= 0) {
2530 tcl[it2].EndVtx = iv;
2533 if (tcl[it2].BeginVtx >= 0) {
2537 tcl[it2].BeginVtx = iv;
2542 if (vtx[iv].ChiDOF < 5 && vtx[iv].WireErr < fVertex2DWireErrCut && vtx[iv].TimeErr < 20) {
2544 mf::LogVerbatim(
"CC") <<
" New vtx " << iv <<
" in plane " << plane <<
" topo " << topo
2545 <<
" cls " << tcl[it1].ID <<
" " << tcl[it2].ID <<
" W:T " << (int)vw
2546 <<
":" << (
int)fvt <<
" NClusters " << vtx[iv].NClusters;
2548 if (fRefineVertexClusters) RefineVertexClusters(iv);
2552 mf::LogVerbatim(
"CC") <<
" Bad vtx fit " << vtx[iv].ChiDOF <<
" wire err " 2553 << vtx[iv].WireErr <<
" TimeErr " << vtx[iv].TimeErr;
2556 if (tcl[it1].BeginVtx == iv) tcl[it1].BeginVtx = -99;
2557 if (tcl[it1].EndVtx == iv) tcl[it1].EndVtx = -99;
2558 if (tcl[it2].BeginVtx == iv) tcl[it2].BeginVtx = -99;
2559 if (tcl[it2].EndVtx == iv) tcl[it2].EndVtx = -99;
2565 bool ClusterCrawlerAlg::ChkSignal(
unsigned int iht,
unsigned int jht)
2567 if (iht > fHits.size() - 1)
return false;
2568 if (jht > fHits.size() - 1)
return false;
2569 unsigned int wire1 = fHits[iht].WireID().Wire;
2570 float time1 = fHits[iht].PeakTime();
2571 unsigned int wire2 = fHits[jht].WireID().Wire;
2572 float time2 = fHits[jht].PeakTime();
2573 return ChkSignal(wire1, time1, wire2, time2);
2577 bool ClusterCrawlerAlg::ChkSignal(
unsigned int wire1,
2587 const float gausAmp[20] = {1, 0.99, 0.96, 0.90, 0.84, 0.75, 0.67, 0.58, 0.49, 0.40,
2588 0.32, 0.26, 0.20, 0.15, 0.11, 0.08, 0.06, 0.04, 0.03, 0.02};
2591 if (fMinAmp[plane] <= 0)
return true;
2594 unsigned int wireb = wire1;
2595 float timeb = time1;
2596 unsigned int wiree = wire2;
2597 float timee = time2;
2599 if (wiree > wireb) {
2605 if (wiree < fFirstWire || wiree > fLastWire)
return false;
2606 if (wireb < fFirstWire || wireb > fLastWire)
return false;
2611 bool oneWire =
false;
2612 float prTime, prTimeLo = 0, prTimeHi = 0;
2613 if (wireb == wiree) {
2615 if (time1 < time2) {
2625 slope = (timeb - timee) / (wireb - wiree);
2629 unsigned short nmissed = 0;
2630 for (
unsigned int wire = wiree; wire < wireb + 1; ++wire) {
2631 if (oneWire) { prTime = (prTimeLo + prTimeHi) / 2; }
2633 prTime = timee + (wire - wire0) * slope;
2636 if (WireHitRange[wire].first == -1)
continue;
2638 if (WireHitRange[wire].first == -2) ++nmissed;
2639 unsigned int firsthit = WireHitRange[wire].first;
2640 unsigned int lasthit = WireHitRange[wire].second;
2642 for (
unsigned int khit = firsthit; khit < lasthit; ++khit) {
2646 if (prTime < fHits[khit].StartTick())
continue;
2647 if (prTime > fHits[khit].EndTick())
continue;
2652 if (fHits[khit].PeakTime() - prTime > 500)
continue;
2653 bin =
std::abs(fHits[khit].PeakTime() - prTime) / fHits[khit].RMS();
2655 if (bin > 19)
continue;
2656 if (bin < 0)
continue;
2658 amp += fHits[khit].PeakAmplitude() * gausAmp[
bin];
2661 if (amp < fMinAmp[plane]) ++nmissed;
2663 if (nmissed > fAllowNoHitWire)
return false;
2669 bool ClusterCrawlerAlg::SplitCluster(
unsigned short icl,
unsigned short pos,
unsigned short ivx)
2673 if (tcl[icl].ID < 0)
return false;
2676 MakeClusterObsolete(icl);
2678 unsigned short ii, iclnew;
2684 clBeginSlp = tcl[icl].BeginSlp;
2685 clBeginSlpErr = tcl[icl].BeginSlpErr;
2686 clBeginAng = tcl[icl].BeginAng;
2687 clBeginWir = tcl[icl].BeginWir;
2688 clBeginTim = tcl[icl].BeginTim;
2689 clBeginChg = tcl[icl].BeginChg;
2691 clProcCode = tcl[icl].ProcCode;
2696 for (ii = 0; ii < pos; ++ii) {
2697 iht = tcl[icl].tclhits[ii];
2698 fcl2hits.push_back(iht);
2701 pass = tcl[icl].ProcCode - 10 * (tcl[icl].ProcCode / 10);
2702 if (pass > fNumPass - 1) pass = fNumPass - 1;
2705 clEndSlp = clpar[1];
2706 clEndSlpErr = clparerr[1];
2707 clEndAng = std::atan(fScaleF * clEndSlp);
2712 RestoreObsoleteCluster(icl);
2716 iclnew = tcl.size() - 1;
2717 tcl[iclnew].EndVtx = ivx;
2718 tcl[iclnew].BeginVtx = tcl[icl].BeginVtx;
2720 mf::LogVerbatim(
"CC") <<
"SplitCluster made cluster " << iclnew <<
" attached to Begin vtx " 2724 if (pos < tcl[icl].tclhits.size() - 3) {
2727 clEndSlp = tcl[icl].EndSlp;
2728 clEndSlpErr = tcl[icl].EndSlpErr;
2729 clEndAng = std::atan(fScaleF * clEndSlp);
2730 clEndWir = tcl[icl].EndWir;
2731 clEndTim = tcl[icl].EndTim;
2732 clEndChg = tcl[icl].EndChg;
2734 clProcCode = tcl[icl].ProcCode;
2739 bool didFit =
false;
2740 for (ii = pos; ii < tcl[icl].tclhits.size(); ++ii) {
2741 iht = tcl[icl].tclhits[ii];
2742 if (inClus[iht] != 0) {
2743 RestoreObsoleteCluster(icl);
2746 fcl2hits.push_back(iht);
2748 if (fcl2hits.size() == fMaxHitsFit[pass] || fcl2hits.size() == fMinHits[pass]) {
2750 clBeginSlp = clpar[1];
2751 clBeginAng = std::atan(fScaleF * clBeginSlp);
2752 clBeginSlpErr = clparerr[1];
2755 if ((
unsigned short)fcl2hits.size() == fNHitsAve[pass] + 1) {
2757 clBeginChg = fAveChg;
2765 clBeginChg = fAveChg;
2769 MakeClusterObsolete(tcl.size() - 1);
2770 RestoreObsoleteCluster(icl);
2774 iclnew = tcl.size() - 1;
2775 tcl[iclnew].BeginVtx = ivx;
2776 tcl[iclnew].EndVtx = tcl[icl].EndVtx;
2778 mf::LogVerbatim(
"CC") <<
"SplitCluster made cluster " << iclnew <<
" attached to End vtx " 2786 void ClusterCrawlerAlg::ChkMerge()
2791 if (tcl.size() < 2)
return;
2796 prt = (fDebugPlane == (short)plane && fDebugWire < 0);
2799 unsigned short it1, it2, nh1, pass1, pass2;
2800 float bs1, bth1, bt1, bc1, es1, eth1, et1, ec1;
2801 float bs2, bth2, bt2, bc2, es2, eth2, et2, ec2;
2802 int bw1, ew1, bw2, ew2, ndead;
2803 float dth, dw, angcut, chgrat, chgcut, dtim, timecut, bigslp;
2804 bool bothLong, NoVtx;
2806 int skipcut, tclsize = tcl.size();
2809 for (it1 = 0; it1 < tclsize - 1; ++it1) {
2811 if (tcl[it1].ID < 0)
continue;
2812 if (tcl[it1].CTP != clCTP)
continue;
2813 bs1 = tcl[it1].BeginSlp;
2815 bth1 = std::atan(fScaleF * bs1);
2817 bw1 = tcl[it1].BeginWir;
2818 bt1 = tcl[it1].BeginTim;
2819 bc1 = tcl[it1].BeginChg;
2820 es1 = tcl[it1].EndSlp;
2821 eth1 = tcl[it1].EndAng;
2822 ew1 = tcl[it1].EndWir;
2823 et1 = tcl[it1].EndTim;
2824 ec1 = tcl[it1].EndChg;
2825 nh1 = tcl[it1].tclhits.size();
2826 pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
2827 if (pass1 > fNumPass) pass1 = fNumPass;
2828 for (it2 = it1 + 1; it2 < tclsize; ++it2) {
2830 if (tcl[it1].ID < 0)
continue;
2831 if (tcl[it2].ID < 0)
continue;
2833 if (tcl[it2].CTP != clCTP)
continue;
2836 if (!ChkMergedClusterHitFrac(it1, it2)) {
continue; }
2837 bs2 = tcl[it2].BeginSlp;
2838 bth2 = std::atan(fScaleF * bs2);
2839 bw2 = tcl[it2].BeginWir;
2840 bt2 = tcl[it2].BeginTim;
2841 bc2 = tcl[it2].BeginChg;
2842 es2 = tcl[it2].EndSlp;
2843 eth2 = tcl[it2].EndAng;
2844 ew2 = tcl[it2].EndWir;
2845 et2 = tcl[it2].EndTim;
2846 ec2 = tcl[it2].EndChg;
2847 pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
2848 if (pass2 > fNumPass) pass2 = fNumPass;
2850 angcut = fKinkAngCut[pass1];
2851 if (fKinkAngCut[pass2] > angcut) angcut = fKinkAngCut[pass2];
2852 skipcut = fMaxWirSkip[pass1];
2853 if (fMaxWirSkip[pass2] > skipcut) skipcut = fMaxWirSkip[pass2];
2854 chgcut = fMergeChgCut[pass1];
2855 if (fMergeChgCut[pass2] > chgcut) chgcut = fMergeChgCut[pass2];
2857 bothLong = (nh1 > 100 && tcl[it2].tclhits.size() > 100);
2865 dw = ew1 - bw2 - ndead;
2867 NoVtx = (tcl[it1].EndVtx < 0) && (tcl[it2].BeginVtx < 0);
2868 if (prt && bw2 < (ew1 + maxOverlap))
2869 mf::LogVerbatim(
"CC") <<
"Chk1 ID1-2 " << tcl[it1].ID <<
"-" << tcl[it2].ID <<
" " << ew1
2870 <<
":" << (int)et1 <<
" " << bw2 <<
":" << (
int)bt2 <<
" dw " << dw
2871 <<
" ndead " << ndead <<
" skipcut " << skipcut <<
" dth " << dth
2872 <<
" angcut " << angcut;
2873 if (NoVtx && bw2 < (ew1 + maxOverlap) && dw < skipcut && dth < angcut) {
2874 chgrat = 2 * fabs(bc2 - ec1) / (bc2 + ec1);
2876 if (bothLong && dth < 0.05) chgrat = 0.;
2878 dtim = fabs(bt2 + (ew1 - bw2) * bs2 - et1);
2881 timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2883 mf::LogVerbatim(
"CC") <<
" dtim " << dtim <<
" timecut " << (int)timecut <<
" ec1 " 2884 << ec1 <<
" bc2 " << bc2 <<
" chgrat " << chgrat <<
" chgcut " 2885 << chgcut <<
" es1 " << es1 <<
" ChkSignal " 2886 << ChkSignal(ew1, et1, bw2, bt2);
2887 if (chgrat < chgcut && dtim < timecut) {
2889 if (ChkSignal(ew1, et1, bw2, bt2)) {
2890 DoMerge(it2, it1, 10);
2891 tclsize = tcl.size();
2899 dth = fabs(bth1 - eth2);
2901 dw = ew2 - bw1 - ndead;
2902 if (prt && bw1 < (ew2 + maxOverlap) && dw < skipcut)
2903 mf::LogVerbatim(
"CC") <<
"Chk2 ID1-2 " << tcl[it1].ID <<
"-" << tcl[it2].ID <<
" " << bw1
2904 <<
":" << (int)bt1 <<
" " << bw2 <<
":" << (
int)et2 <<
" dw " << dw
2905 <<
" ndead " << ndead <<
" skipcut " << skipcut <<
" dth " << dth
2906 <<
" angcut " << angcut;
2908 NoVtx = (tcl[it2].EndVtx < 0) && (tcl[it1].BeginVtx < 0);
2909 if (NoVtx && bw1 < (ew2 + maxOverlap) && dw < skipcut && dth < angcut) {
2910 chgrat = 2 * fabs((bc1 - ec2) / (bc1 + ec2));
2912 if (bothLong && dth < 0.05) chgrat = 0.;
2914 dtim =
std::abs(bt1 + (ew2 - bw1) * bs1 - et2);
2917 timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2919 mf::LogVerbatim(
"CC") <<
" dtim " << dtim <<
" err " << dtim <<
" timecut " 2920 << (int)timecut <<
" chgrat " << chgrat <<
" chgcut " << chgcut
2921 <<
" ChkSignal " << ChkSignal(bw1, bt1, ew2, et2);
2923 if (chgrat < chgcut && dtim < timecut) {
2924 if (ChkSignal(bw1, bt1, ew2, et2)) {
2925 DoMerge(it1, it2, 10);
2926 tclsize = tcl.size();
2932 if (bw2 < bw1 && ew2 > ew1) {
2935 dth = fabs(eth2 - eth1);
2936 dtim = fabs(et1 + (ew2 - ew1 - 1) * es1 - et2);
2939 timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2941 short nmiss1 = bw1 - ew1 + 1 - tcl[it1].tclhits.size();
2943 short nin2 = tcl[it2].tclhits.size();
2945 mf::LogVerbatim(
"CC") <<
"cl2: " << ew2 <<
":" << (int)et2 <<
" - " << bw2 <<
":" 2946 << (
int)bt2 <<
" within cl1 " << ew1 <<
":" << (int)et1 <<
" - " 2947 << bw1 <<
":" << (
int)bt1 <<
" ? dth " << dth <<
" dtim " << dtim
2948 <<
" nmissed " << nmiss1 <<
" timecut " << timecut
2949 <<
" FIX THIS CODE";
2954 if (dth < 1 && dtim < timecut && nmiss1 >= nin2) ChkMerge12(it1, it2, didit);
2956 tclsize = tcl.size();
2961 if (bw1 < bw2 && ew1 > ew2) {
2965 dtim =
std::abs(et2 + (ew1 - ew2 - 1) * es2 - et1);
2968 timecut = fTimeDelta[pass2] * AngleFactor(bigslp);
2970 short nmiss2 = bw2 - ew2 + 1 - tcl[it2].tclhits.size();
2972 short nin1 = tcl[it1].tclhits.size();
2974 mf::LogVerbatim(
"CC") <<
"cl1: " << ew1 <<
":" << (int)et1 <<
" - " << bw1 <<
":" 2975 << (
int)bt1 <<
" within cl2 " << ew2 <<
":" << (int)et2 <<
" - " 2976 << bw2 <<
":" << (
int)bt2 <<
" ? dth " << dth <<
" dtim " << dtim
2977 <<
" nmissed " << nmiss2 <<
" timecut " << timecut
2978 <<
" FIX THIS CODE";
2982 if (dth < 1 && dtim < timecut && nmiss2 >= nin1) ChkMerge12(it2, it1, didit);
2984 tclsize = tcl.size();
2989 if (tcl[it1].ID < 0)
break;
2991 if (tcl[it1].ID < 0)
continue;
2996 void ClusterCrawlerAlg::ChkMerge12(
unsigned short it1,
unsigned short it2,
bool& didit)
3006 if (prt)
mf::LogVerbatim(
"CC") <<
"ChkMerge12 " << tcl[it1].ID <<
" " << tcl[it2].ID;
3011 int ew1 = tcl[it1].
EndWir;
3012 int bw1 = tcl[it1].BeginWir;
3013 unsigned int iht,
hit;
3015 std::vector<unsigned int> cl1hits(bw1 + 1 - ew1);
3017 for (iht = 0; iht < cl1.
tclhits.size(); ++iht) {
3019 wire = fHits[hit].WireID().Wire;
3020 if (wire - ew1 < 0 || wire - ew1 > (
int)cl1hits.size()) {
return; }
3021 cl1hits[wire - ew1] = hit;
3023 unsigned int ew2 = tcl[it2].EndWir;
3024 float et2 = tcl[it2].EndTim;
3026 unsigned int wiron1 = 0;
3029 for (wire = ew2 - 1; wire > ew1; --wire) {
3030 if (cl1hits[wire - ew1] > 0) {
3036 if (prt)
mf::LogVerbatim(
"CC") <<
"chk next US wire " << wiron1 <<
" missed " << nmiss;
3037 if (wiron1 == 0)
return;
3038 if (nmiss > fMaxWirSkip[pass])
return;
3042 unsigned int hiton2;
3044 unsigned short nfit = 0;
3045 for (iht = 0; iht < tcl[it2].tclhits.size(); ++iht) {
3046 hiton2 = tcl[it2].tclhits[iht];
3047 wiron2 = fHits[hiton2].WireID().Wire;
3048 if (wiron2 < ew1 || wiron2 > bw1)
return;
3049 if (cl1hits[wiron2 - ew1] == 0) ++nfit;
3052 if (nfit < tcl[it2].tclhits.size())
return;
3055 unsigned short pass1 = tcl[it1].ProcCode - 10 * (tcl[it1].ProcCode / 10);
3056 unsigned short pass2 = tcl[it2].ProcCode - 10 * (tcl[it2].ProcCode / 10);
3057 unsigned short cpass = pass1;
3059 if (pass2 < pass1) cpass = pass2;
3062 if ((
int)wiron1 - ew1 < 0)
return;
3063 unsigned int hiton1 = cl1hits[wiron1 - ew1];
3064 if (hiton1 > fHits.size() - 1) {
return; }
3066 float timon1 = fHits[hiton1].PeakTime();
3067 float dtim =
std::abs(et2 + (wiron1 - ew2) * tcl[it2].EndSlp - timon1);
3068 if (dtim > fTimeDelta[cpass])
return;
3071 FitClusterMid(it1, hiton1, 3);
3072 if (clChisq > 20.)
return;
3075 float dth =
std::abs(std::atan(fScaleF * clpar[1]) - std::atan(fScaleF * tcl[it2].EndSlp));
3076 if (prt)
mf::LogVerbatim(
"CC") <<
"US dtheta " << dth <<
" cut " << fKinkAngCut[cpass];
3077 if (dth > fKinkAngCut[cpass])
return;
3079 float chgrat = 2 *
std::abs(fAveChg - tcl[it2].EndChg) / (fAveChg + tcl[it2].EndChg);
3080 if (prt)
mf::LogVerbatim(
"CC") <<
"US chgrat " << chgrat <<
" cut " << fMergeChgCut[pass];
3083 SigOK = ChkSignal(wiron1, timon1, ew2, et2);
3088 unsigned int bw2 = tcl[it2].BeginWir;
3089 float bt2 = tcl[it2].BeginTim;
3092 for (wire = bw2 + 1; wire < bw1; ++wire) {
3093 if (cl1hits[wire - ew1] > 0) {
3099 if (wiron1 == 0)
return;
3100 if (nmiss > fMaxWirSkip[pass])
return;
3103 hiton1 = cl1hits[wiron1 - ew1];
3104 if (hiton1 > fHits.size() - 1) {
return; }
3105 timon1 = fHits[hiton1].PeakTime();
3106 dtim =
std::abs(bt2 - (wiron1 - bw2) * tcl[it2].BeginSlp - timon1);
3107 if (dtim > fTimeDelta[cpass])
return;
3108 FitClusterMid(it1, hiton1, -3);
3109 if (clChisq > 20.)
return;
3111 dth =
std::abs(std::atan(fScaleF * clpar[1]) - std::atan(fScaleF * tcl[it2].BeginSlp));
3112 if (prt)
mf::LogVerbatim(
"CC") <<
"DS dtheta " << dth <<
" cut " << fKinkAngCut[cpass];
3113 if (dth > fKinkAngCut[cpass])
return;
3115 chgrat = 2 *
std::abs(fAveChg - tcl[it2].BeginChg) / (fAveChg + tcl[it2].BeginChg);
3116 if (prt)
mf::LogVerbatim(
"CC") <<
"DS chgrat " << chgrat <<
" cut " << fMergeChgCut[pass];
3118 SigOK = ChkSignal(wiron1, timon1, bw2, bt2);
3124 DoMerge(it1, it2, 100);
3129 void ClusterCrawlerAlg::DoMerge(
unsigned short it1,
unsigned short it2,
short inProcCode)
3136 if (cl1.
tclhits.size() < 3)
return;
3137 if (cl2.
tclhits.size() < 3)
return;
3139 unsigned int lowire, hiwire, whsize, ii, iht, indx;
3142 unsigned int fithit;
3157 whsize = hiwire + 2 - lowire;
3158 std::vector<int> wirehit(whsize, -1);
3160 for (ii = 0; ii < cl2.
tclhits.size(); ++ii) {
3162 indx = fHits[iht].WireID().Wire - lowire;
3163 wirehit[indx] = iht;
3166 for (ii = 0; ii < cl1.
tclhits.size(); ++ii) {
3168 indx = fHits[iht].WireID().Wire - lowire;
3169 wirehit[indx] = iht;
3173 for (std::vector<int>::reverse_iterator rit = wirehit.rbegin(); rit != wirehit.rend(); ++rit) {
3174 if (*rit < 0)
continue;
3175 fcl2hits.push_back(*rit);
3180 FitClusterMid(fcl2hits, fithit, nhitfit);
3181 if (clChisq > 5)
return;
3184 MakeClusterObsolete(it1);
3185 MakeClusterObsolete(it2);
3189 short del1Vtx = -99;
3190 short del2Vtx = -99;
3239 if (!TmpStore())
return;
3240 unsigned short itnew = tcl.size() - 1;
3242 mf::LogVerbatim(
"CC") <<
"DoMerge " << cl1.
ID <<
" " << cl2.
ID <<
" -> " << tcl[itnew].ID;
3244 tcl[itnew].ProcCode = inProcCode + pass;
3247 if (del1Vtx >= 0 && del1Vtx == del2Vtx) vtx[del1Vtx].NClusters = 0;
3249 tcl[itnew].BeginVtx = begVtx;
3250 tcl[itnew].EndVtx = endVtx;
3254 void ClusterCrawlerAlg::PrintVertices()
3259 if (vtx3.size() > 0) {
3262 <<
"****** 3D vertices ******************************************__2DVtx_Indx__*******\n";
3264 <<
"Vtx Cstat TPC Proc X Y Z XEr YEr ZEr pln0 pln1 pln2 Wire\n";
3265 for (
unsigned short iv = 0; iv < vtx3.size(); ++iv) {
3266 myprt <<
std::right << std::setw(3) << std::fixed << iv << std::setprecision(1);
3267 myprt <<
std::right << std::setw(7) << vtx3[iv].CStat;
3268 myprt <<
std::right << std::setw(5) << vtx3[iv].TPC;
3269 myprt <<
std::right << std::setw(5) << vtx3[iv].ProcCode;
3270 myprt <<
std::right << std::setw(8) << vtx3[iv].X;
3271 myprt <<
std::right << std::setw(8) << vtx3[iv].Y;
3272 myprt <<
std::right << std::setw(8) << vtx3[iv].Z;
3273 myprt <<
std::right << std::setw(5) << vtx3[iv].XErr;
3274 myprt <<
std::right << std::setw(5) << vtx3[iv].YErr;
3275 myprt <<
std::right << std::setw(5) << vtx3[iv].ZErr;
3276 myprt <<
std::right << std::setw(5) << vtx3[iv].Ptr2D[0];
3277 myprt <<
std::right << std::setw(5) << vtx3[iv].Ptr2D[1];
3278 myprt <<
std::right << std::setw(5) << vtx3[iv].Ptr2D[2];
3279 myprt <<
std::right << std::setw(5) << vtx3[iv].Wire;
3280 if (vtx3[iv].Wire < 0) { myprt <<
" Matched in all planes"; }
3282 myprt <<
" Incomplete";
3288 if (vtx.size() > 0) {
3290 myprt <<
"************ 2D vertices ************\n";
3291 myprt <<
"Vtx CTP wire error tick error ChiDOF NCl topo cluster IDs\n";
3292 for (
unsigned short iv = 0; iv < vtx.size(); ++iv) {
3293 if (fDebugPlane < 3 && fDebugPlane != (
int)vtx[iv].CTP)
continue;
3294 myprt <<
std::right << std::setw(3) << std::fixed << iv << std::setprecision(1);
3295 myprt <<
std::right << std::setw(6) << vtx[iv].CTP;
3296 myprt <<
std::right << std::setw(8) << vtx[iv].Wire <<
" +/- ";
3297 myprt <<
std::right << std::setw(4) << vtx[iv].WireErr;
3298 myprt <<
std::right << std::setw(8) << vtx[iv].Time <<
" +/- ";
3299 myprt <<
std::right << std::setw(4) << vtx[iv].TimeErr;
3300 myprt <<
std::right << std::setw(8) << vtx[iv].ChiDOF;
3301 myprt <<
std::right << std::setw(5) << vtx[iv].NClusters;
3302 myprt <<
std::right << std::setw(6) << vtx[iv].Topo;
3305 for (
unsigned short ii = 0; ii < tcl.size(); ++ii) {
3306 if (fDebugPlane < 3 && fDebugPlane != (
int)tcl[ii].CTP)
continue;
3307 if (tcl[ii].ID < 0)
continue;
3308 if (tcl[ii].BeginVtx == (
short)iv) myprt <<
std::right << std::setw(4) << tcl[ii].ID;
3309 if (tcl[ii].EndVtx == (
short)iv) myprt <<
std::right << std::setw(4) << tcl[ii].ID;
3326 float aveRMS, aveRes;
3327 myprt <<
"*************************************** Clusters " 3328 "*********************************************************************\n";
3329 myprt <<
" ID CTP nht Stop Proc beg_W:T bAng bSlp Err bChg end_W:T eAng eSlp " 3330 "Err eChg bVx eVx aveRMS Qual cnt\n";
3331 for (
unsigned short ii = 0; ii < tcl.size(); ++ii) {
3333 if (fDebugPlane < 3 && fDebugPlane != (
int)tcl[ii].CTP)
continue;
3334 myprt <<
std::right << std::setw(4) << tcl[ii].ID;
3335 myprt <<
std::right << std::setw(3) << tcl[ii].CTP;
3336 myprt <<
std::right << std::setw(5) << tcl[ii].tclhits.size();
3337 myprt <<
std::right << std::setw(4) << tcl[ii].StopCode;
3338 myprt <<
std::right << std::setw(6) << tcl[ii].ProcCode;
3339 unsigned int iTime = tcl[ii].BeginTim;
3340 myprt <<
std::right << std::setw(6) << tcl[ii].BeginWir <<
":" << iTime;
3341 if (iTime < 10) { myprt <<
" "; }
3342 else if (iTime < 100) {
3345 else if (iTime < 1000)
3347 myprt <<
std::right << std::setw(7) << std::fixed << std::setprecision(2) << tcl[ii].BeginAng;
3348 if (
std::abs(tcl[ii].BeginSlp) < 100) {
3349 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(2)
3350 << tcl[ii].BeginSlp;
3353 myprt <<
std::right << std::setw(6) << (int)tcl[ii].BeginSlp;
3355 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(2)
3356 << tcl[ii].BeginSlpErr;
3357 myprt <<
std::right << std::setw(5) << (int)tcl[ii].BeginChg;
3358 iTime = tcl[ii].EndTim;
3359 myprt <<
std::right << std::setw(6) << tcl[ii].EndWir <<
":" << iTime;
3360 if (iTime < 10) { myprt <<
" "; }
3361 else if (iTime < 100) {
3364 else if (iTime < 1000)
3366 myprt <<
std::right << std::setw(7) << std::fixed << std::setprecision(2) << tcl[ii].EndAng;
3367 if (
std::abs(tcl[ii].EndSlp) < 100) {
3368 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(2) << tcl[ii].EndSlp;
3371 myprt <<
std::right << std::setw(6) << (int)tcl[ii].EndSlp;
3373 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(2)
3374 << tcl[ii].EndSlpErr;
3375 myprt <<
std::right << std::setw(5) << (int)tcl[ii].EndChg;
3376 myprt <<
std::right << std::setw(5) << tcl[ii].BeginVtx;
3377 myprt <<
std::right << std::setw(5) << tcl[ii].EndVtx;
3379 unsigned int iht = 0;
3380 for (
unsigned short jj = 0; jj < tcl[ii].tclhits.size(); ++jj) {
3381 iht = tcl[ii].tclhits[jj];
3382 aveRMS += fHits[iht].RMS();
3384 aveRMS /= (float)tcl[ii].tclhits.size();
3385 myprt <<
std::right << std::setw(5) << std::fixed << std::setprecision(1) << aveRMS;
3388 unsigned int hit0, hit1, hit2, cnt = 0;
3390 for (
unsigned short iht = 1; iht < tcl[ii].tclhits.size() - 1; ++iht) {
3391 hit1 = tcl[ii].tclhits[iht];
3392 hit0 = tcl[ii].tclhits[iht - 1];
3393 hit2 = tcl[ii].tclhits[iht + 1];
3395 if (fHits[hit1].
WireID().Wire + 1 != fHits[hit0].WireID().Wire)
continue;
3396 if (fHits[hit2].
WireID().Wire + 1 != fHits[hit1].WireID().Wire)
continue;
3397 arg = (fHits[hit0].PeakTime() + fHits[hit2].PeakTime()) / 2 - fHits[hit1].PeakTime();
3398 aveRes += arg * arg;
3402 aveRes /= (float)cnt;
3403 aveRes = sqrt(aveRes);
3405 aveRes /= (aveRMS * fHitErrFac);
3406 myprt <<
std::right << std::setw(6) << std::fixed << std::setprecision(1) << aveRes;
3407 myprt <<
std::right << std::setw(5) << std::fixed << cnt;
3411 myprt <<
std::right << std::setw(5) << std::fixed << cnt;
3419 void ClusterCrawlerAlg::TmpGet(
unsigned short it1)
3424 if (it1 > tcl.size())
return;
3426 clBeginSlp = tcl[it1].BeginSlp;
3427 clBeginSlpErr = tcl[it1].BeginSlpErr;
3428 clBeginAng = tcl[it1].BeginAng;
3429 clBeginWir = tcl[it1].BeginWir;
3430 clBeginTim = tcl[it1].BeginTim;
3431 clBeginChg = tcl[it1].BeginChg;
3432 clBeginChgNear = tcl[it1].BeginChgNear;
3433 clEndSlp = tcl[it1].EndSlp;
3434 clEndSlpErr = tcl[it1].EndSlpErr;
3435 clEndAng = tcl[it1].EndAng;
3436 clEndWir = tcl[it1].EndWir;
3437 clEndTim = tcl[it1].EndTim;
3438 clEndChg = tcl[it1].EndChg;
3439 clEndChgNear = tcl[it1].EndChgNear;
3440 clStopCode = tcl[it1].StopCode;
3441 clProcCode = tcl[it1].ProcCode;
3442 clCTP = tcl[it1].CTP;
3443 fcl2hits = tcl[it1].tclhits;
3447 bool ClusterCrawlerAlg::TmpStore()
3450 if (fcl2hits.size() < 2)
return false;
3451 if (fcl2hits.size() > fHits.size())
return false;
3453 if (NClusters == SHRT_MAX)
return false;
3457 unsigned int hit0 = fcl2hits[0];
3459 unsigned int tCST = fHits[hit0].WireID().Cryostat;
3460 unsigned int tTPC = fHits[hit0].WireID().TPC;
3461 unsigned int tPlane = fHits[hit0].WireID().Plane;
3462 unsigned int lastWire = 0;
3464 for (
unsigned short it = 0; it < fcl2hits.size(); ++it) {
3466 if (inClus[hit] != 0) {
3471 if (fHits[hit].
WireID().Cryostat != tCST || fHits[hit].WireID().TPC != tTPC ||
3472 fHits[hit].WireID().Plane != tPlane) {
3477 if (clProcCode < 900 && it > 0 && fHits[hit].
WireID().Wire >= lastWire) {
3481 lastWire = fHits[hit].WireID().Wire;
3482 inClus[hit] = NClusters;
3488 if (clEndChg <= 0) {
3490 unsigned int ih0 = fcl2hits.size() - 2;
3491 hit = fcl2hits[ih0];
3492 clEndChg = fHits[hit].Integral();
3493 hit = fcl2hits[ih0 - 1];
3494 clEndChg += fHits[hit].Integral();
3495 clEndChg = clEndChg / 2.;
3497 if (clBeginChg <= 0) {
3500 clBeginChg = fHits[hit].Integral();
3502 clBeginChg += fHits[hit].Integral();
3503 clBeginChg = clBeginChg / 2.;
3507 hit = fcl2hits[fcl2hits.size() - 1];
3512 clstr.
ID = NClusters;
3515 clstr.
BeginAng = std::atan(fScaleF * clBeginSlp);
3516 clstr.
BeginWir = fHits[hit0].WireID().Wire;
3517 clstr.
BeginTim = fHits[hit0].PeakTime();
3522 clstr.
EndAng = std::atan(fScaleF * clEndSlp);
3523 clstr.
EndWir = fHits[hit].WireID().Wire;
3524 clstr.
EndTim = fHits[hit].PeakTime();
3533 tcl.push_back(clstr);
3539 void ClusterCrawlerAlg::LACrawlUS()
3544 unsigned int dhit = fcl2hits[0];
3545 short dwir = fHits[dhit].WireID().Wire;
3548 if (fDebugPlane == (
short)plane && dwir == fDebugWire && fDebugHit > 0)
3549 prt =
std::abs(fHits[dhit].PeakTime() - fDebugHit) < 40;
3553 myprt <<
"******************* LACrawlUS PASS " << pass <<
" Hits ";
3554 for (
unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3555 unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3556 myprt << fHits[iht].WireID().Wire <<
":" << (int)fHits[iht].PeakTime() <<
" ";
3565 unsigned short kinkOnWire = 0;
3566 unsigned int it = fcl2hits.size() - 1;
3567 unsigned int lasthit = fcl2hits[it];
3568 unsigned int lastwire = fHits[lasthit].WireID().Wire;
3569 unsigned int prevHit, prevWire;
3570 bool ChkCharge =
false;
3571 for (
unsigned int nextwire = lastwire - 1; nextwire >= fFirstWire; --nextwire) {
3573 mf::LogVerbatim(
"CC") <<
"LACrawlUS: next wire " << nextwire <<
" HitRange " 3574 << WireHitRange[nextwire].first;
3576 if (CrawlVtxChk(nextwire)) {
3582 AddLAHit(nextwire, ChkCharge, HitOK, SigOK);
3584 mf::LogVerbatim(
"CC") <<
"LACrawlUS: HitOK " << HitOK <<
" SigOK " << SigOK
3585 <<
" nmissed SigOK " << nmissed <<
" cut " << fAllowNoHitWire;
3586 if (SigOK) nmissed = 0;
3589 if (nmissed > fAllowNoHitWire) {
3598 prevHit = fcl2hits[fcl2hits.size() - 2];
3599 prevWire = fHits[prevHit].WireID().Wire;
3600 if (prevWire > nextwire + 2) {
3601 if (!ChkSignal(fcl2hits[fcl2hits.size() - 1], fcl2hits[fcl2hits.size() - 2])) {
3611 if (fcl2hits.size() == 4) {
3613 for (
unsigned short kk = 0; kk < fcl2hits.size() - 1; ++kk) {
3614 unsigned int hit = fcl2hits[kk];
3615 if (mergeAvailable[hit]) MergeHits(hit, didMerge);
3619 clBeginSlp = clpar[1];
3624 unsigned short chsiz = chifits.size() - 1;
3626 if (chsiz < 6)
continue;
3627 if (fKinkChiRat[pass] <= 0)
continue;
3628 if (chifits.size() != fcl2hits.size()) {
3629 mf::LogError(
"CC") <<
"LACrawlUS: chifits size error " << chifits.size() <<
" " 3634 mf::LogVerbatim(
"CC") <<
"Kink chk " << chifits[chsiz] <<
" " << chifits[chsiz - 1] <<
" " 3635 << chifits[chsiz - 2] <<
" " << chifits[chsiz - 3];
3636 if (chifits[chsiz - 1] > fKinkChiRat[pass] * chifits[chsiz - 2] &&
3637 chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz - 1]) {
3639 unsigned int ih0 = fcl2hits.size() - 1;
3640 unsigned int hit0 = fcl2hits[ih0];
3641 unsigned int ih2 = ih0 - 2;
3642 unsigned int hit2 = fcl2hits[ih2];
3643 float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
3644 float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
3645 float th02 = std::atan(fScaleF * dt02 / dw02);
3647 unsigned int ih3 = ih2 - 1;
3648 unsigned int hit3 = fcl2hits[ih3];
3649 unsigned int ih5 = ih3 - 2;
3650 unsigned int hit5 = fcl2hits[ih5];
3651 float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
3652 float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
3653 float th35 = std::atan(fScaleF * dt35 / dw35);
3656 mf::LogVerbatim(
"CC") <<
" Kink angle " << std::setprecision(3) << dth <<
" cut " 3657 << fKinkAngCut[pass];
3658 if (dth > fKinkAngCut[pass]) {
3664 if (kinkOnWire > 0) {
3665 if (kinkOnWire - nextwire < 4) {
3668 <<
"Hit a second kink. kinkOnWire = " << kinkOnWire <<
" Stopping";
3674 kinkOnWire = nextwire;
3680 CheckClusterHitFrac(prt);
3683 if (prt)
mf::LogVerbatim(
"CC") <<
"LACrawlUS done. Nhits = " << fcl2hits.size();
3688 void ClusterCrawlerAlg::CrawlUS()
3692 if (fcl2hits.size() < 2)
return;
3694 unsigned int dhit = fcl2hits[0];
3695 int dwir = fHits[dhit].WireID().Wire;
3699 if (fDebugPlane == (
short)plane && dwir == fDebugWire && fDebugHit > 0)
3700 prt =
std::abs(fHits[dhit].PeakTime() - fDebugHit) < 20;
3704 myprt <<
"******************* Start CrawlUS on pass " << pass <<
" Hits: ";
3705 for (
unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
3706 unsigned int iht = fcl2hits[fcl2hits.size() - 1 - ii];
3707 myprt << fHits[iht].WireID().Wire <<
":" << (int)fHits[iht].PeakTime() <<
" ";
3718 short nHitAfterSkip = 0;
3719 bool DidaSkip =
false;
3720 bool PostSkip =
false;
3721 unsigned int it = fcl2hits.size() - 1;
3722 unsigned int lasthit = fcl2hits[it];
3723 if (lasthit > fHits.size() - 1) {
3724 mf::LogError(
"CC") <<
"CrawlUS bad lasthit " << lasthit;
3727 unsigned int lastwire = fHits[lasthit].WireID().Wire;
3728 if (prt)
mf::LogVerbatim(
"CC") <<
"CrawlUS: last wire " << lastwire <<
" hit " << lasthit;
3730 unsigned int lastWireWithSignal = lastwire;
3731 unsigned short nDroppedHit = 0;
3733 for (
unsigned int nextwire = lastwire - 1; nextwire > fFirstWire; --nextwire) {
3735 mf::LogVerbatim(
"CC") <<
"CrawlUS: next wire " << nextwire <<
" HitRange " 3736 << WireHitRange[nextwire].first;
3738 if (CrawlVtxChk(nextwire)) {
3744 if (
std::abs(clpar[1]) > fLAClusSlopeCut) {
3745 if (prt)
mf::LogVerbatim(
"CC") <<
">>>>> CrawlUS: Switching to LACrawlUS";
3750 AddHit(nextwire, HitOK, SigOK);
3752 mf::LogVerbatim(
"CC") <<
"CrawlUS: HitOK " << HitOK <<
" SigOK " << SigOK <<
" nmissed " 3754 if (SigOK) lastWireWithSignal = nextwire;
3761 if (PostSkip && nmissed > fMinWirAfterSkip[pass]) {
3763 if ((
int)(fcl2hits.size() - nHitAfterSkip) < 4) {
3767 if (prt)
mf::LogVerbatim(
"CC") <<
" PostSkip && nmissed = " << nmissed;
3769 FclTrimUS(nHitAfterSkip);
3771 if (clChisq > 90.) {
3786 lasthit = fcl2hits[fcl2hits.size() - 1];
3787 if ((lastWireWithSignal - nextwire) > fAllowNoHitWire) {
3790 <<
"No hit or signal on wire " << nextwire <<
" last wire with signal " 3791 << lastWireWithSignal <<
" exceeding fAllowNoHitWire " << fAllowNoHitWire
3799 mf::LogVerbatim(
"CC") <<
" CrawlUS check clChisq " << clChisq <<
" cut " << fChiCut[pass];
3800 if (clChisq > fChiCut[pass]) {
3801 if (fcl2hits.size() < 3) {
3806 if (prt)
mf::LogVerbatim(
"CC") <<
"ADD- Bad clChisq " << clChisq <<
" dropping hit";
3810 if (nDroppedHit > 4) {
3813 <<
" Too many dropped hits: " << nDroppedHit <<
" Stop crawling";
3816 if (clChisq > fChiCut[pass]) {
3819 <<
" Bad clChisq " << clChisq <<
" after dropping hit. Stop crawling";
3827 if (chifits.size() > 5 && fKinkChiRat[pass] > 0) {
3828 if (chifits.size() != fcl2hits.size()) {
3829 mf::LogError(
"CC") <<
"CrawlUS: chifits size error " << chifits.size() <<
" " 3833 unsigned short chsiz = chifits.size() - 1;
3835 mf::LogVerbatim(
"CC") <<
"Kink chk " << chifits[chsiz] <<
" " << chifits[chsiz - 1]
3836 <<
" " << chifits[chsiz - 2] <<
" " << chifits[chsiz - 3];
3837 if (chifits[chsiz - 1] > fKinkChiRat[pass] * chifits[chsiz - 2] &&
3838 chifits[chsiz] > fKinkChiRat[pass] * chifits[chsiz - 1]) {
3839 if (fcl2hits.size() != chifits.size()) {
3840 mf::LogError(
"CC") <<
"bad kink check size " << chifits.size() <<
" " 3841 << fcl2hits.size() <<
" plane " << plane <<
" cluster " << dwir
3845 if (EndKinkAngle() > fKinkAngCut[pass]) {
3848 <<
"******************* Stopped tracking - kink angle " << EndKinkAngle() <<
" > " 3849 << fKinkAngCut[pass] <<
" Removing 3 hits";
3859 if (fcl2hits.size() == fMaxHitsFit[pass] || fcl2hits.size() == fMinHits[pass]) {
3860 clBeginSlp = clpar[1];
3861 clBeginSlpErr = clparerr[1];
3864 if (clBeginChg <= 0 && fAveChg > 0) {
3865 clBeginChg = fAveChg;
3881 if (nHitAfterSkip == fMinWirAfterSkip[pass]) PostSkip =
false;
3884 if (clChisq > fChiCut[pass]) {
3888 unsigned short lopped = 0;
3889 for (
unsigned short nlop = 0; nlop < 4; ++nlop) {
3890 unsigned short cfsize = chifits.size() - 1;
3891 chirat = chifits[cfsize] / chifits[cfsize - 1];
3894 <<
"chirat " << chirat <<
" last hit " << fcl2hits[fcl2hits.size() - 1];
3895 if (chirat < 1.2)
break;
3896 if (prt)
mf::LogVerbatim(
"CC") <<
"<<ADD- Bad chisq. Bad chirat " << chirat;
3899 if (fcl2hits.size() < 6)
break;
3900 if (chifits.size() < 6)
break;
3902 if (fcl2hits.size() < 6) {
3904 if (prt)
mf::LogVerbatim(
"CC") <<
"Bad fit chisq - short cluster. Break";
3907 if (lopped == 0 && fcl2hits.size() > 5) {
3915 mf::LogVerbatim(
"CC") <<
"Bad fit chisq - removed " << lopped <<
" hits. Continue";
3920 mf::LogVerbatim(
"CC") <<
"******************* CrawlUS normal stop. size " << fcl2hits.size();
3924 if (fcl2hits.size() > 5) {
3927 mf::LogVerbatim(
"CC") <<
"EndKinkAngle check " << EndKinkAngle() <<
" cut " 3928 << fKinkAngCut[pass];
3929 if (EndKinkAngle() > fKinkAngCut[pass]) {
3938 if ((
unsigned short)fcl2hits.size() > fMinWirAfterSkip[pass] + 3) {
3939 unsigned int ih0 = fcl2hits.size() - 1;
3940 unsigned int hit0 = fcl2hits[ih0];
3941 unsigned int uswir = fHits[hit0].WireID().Wire;
3942 unsigned int nxtwir;
3943 unsigned short nAdjHit = 0;
3944 for (
unsigned short ii = ih0 - 1; ii > 0; --ii) {
3945 nxtwir = fHits[fcl2hits[ii]].WireID().Wire;
3947 if (nxtwir != uswir + 1)
break;
3949 if (nAdjHit == fMinWirAfterSkip[pass])
break;
3953 if (nAdjHit < fMinWirAfterSkip[pass]) {
3954 if (prt)
mf::LogVerbatim(
"CC") <<
"fMinWirAfterSkip removes " << nAdjHit <<
" hits ";
3961 if (!reFit && fcl2hits.size() > 3) {
3962 float chirat = chifits[chifits.size() - 1] / chifits[chifits.size() - 2];
3964 mf::LogVerbatim(
"CC") <<
"Last hit chirat " << chirat <<
" cut " << fKinkChiRat[pass];
3966 mf::LogVerbatim(
"CC") <<
"Check " << clChisq <<
" " << chifits[chifits.size() - 1] <<
" " 3967 << chifits[chifits.size() - 2];
3968 if (chirat > fKinkChiRat[pass]) {
3979 CheckClusterHitFrac(prt);
3981 mf::LogVerbatim(
"CC") <<
"******************* CrawlUS done. Size " << fcl2hits.size()
3982 <<
" min length for this pass " << fMinHits[pass];
3988 float ClusterCrawlerAlg::EndKinkAngle()
3992 unsigned int ih0 = fcl2hits.size() - 1;
3993 unsigned int hit0 = fcl2hits[ih0];
3994 unsigned int ih2 = ih0 - 2;
3995 unsigned int hit2 = fcl2hits[ih2];
3996 float dt02 = fHits[hit2].PeakTime() - fHits[hit0].PeakTime();
3997 float dw02 = fHits[hit2].WireID().Wire - fHits[hit0].WireID().Wire;
3998 float th02 = std::atan(fScaleF * dt02 / dw02);
4000 unsigned int ih3 = ih2 - 1;
4001 unsigned int hit3 = fcl2hits[ih3];
4002 unsigned int ih5 = ih3 - 2;
4003 unsigned int hit5 = fcl2hits[ih5];
4004 float dt35 = fHits[hit5].PeakTime() - fHits[hit3].PeakTime();
4005 float dw35 = fHits[hit5].WireID().Wire - fHits[hit3].WireID().Wire;
4006 float th35 = std::atan(fScaleF * dt35 / dw35);
4011 bool ClusterCrawlerAlg::ChkMergedClusterHitFrac(
unsigned short it1,
unsigned short it2)
4015 if (it1 > tcl.size() - 1)
return false;
4016 if (it2 > tcl.size() - 1)
return false;
4017 unsigned int eWire = 99999;
4018 unsigned int bWire = 0, wire;
4019 if (tcl[it1].BeginWir > bWire) bWire = tcl[it1].BeginWir;
4020 if (tcl[it2].BeginWir > bWire) bWire = tcl[it2].BeginWir;
4021 if (tcl[it1].EndWir < eWire) eWire = tcl[it1].EndWir;
4022 if (tcl[it2].EndWir < eWire) eWire = tcl[it2].EndWir;
4023 unsigned int mergedClusterLength = bWire - eWire + 1;
4025 std::vector<bool> cHits(mergedClusterLength,
false);
4027 unsigned int ii, iht, indx;
4028 for (ii = 0; ii < tcl[it1].tclhits.size(); ++ii) {
4029 iht = tcl[it1].tclhits[ii];
4030 if (iht > fHits.size() - 1) {
4031 mf::LogError(
"CC") <<
"ChkMergedClusterHitFrac bad iht ";
4034 indx = fHits[iht].WireID().Wire - eWire;
4037 for (ii = 0; ii < tcl[it2].tclhits.size(); ++ii) {
4038 iht = tcl[it2].tclhits[ii];
4039 if (iht > fHits.size() - 1) {
4040 mf::LogError(
"CC") <<
"ChkMergedClusterHitFrac bad iht ";
4043 indx = fHits[iht].WireID().Wire - eWire;
4047 for (ii = 0; ii < cHits.size(); ++ii) {
4049 if (WireHitRange[wire].first == -1) cHits[ii] =
true;
4052 float nhits = std::count(cHits.begin(), cHits.end(),
true);
4053 float hitFrac = nhits / (float)cHits.size();
4054 return (hitFrac > fMinHitFrac);
4058 void ClusterCrawlerAlg::CheckClusterHitFrac(
bool prt)
4063 unsigned int iht = fcl2hits[fcl2hits.size() - 1];
4064 clEndWir = fHits[iht].WireID().Wire;
4065 clBeginWir = fHits[fcl2hits[0]].WireID().Wire;
4066 float hitFrac = (float)(fcl2hits.size() +
DeadWireCount()) / (
float)(clBeginWir - clEndWir + 1);
4068 if (hitFrac < fMinHitFrac) {
4070 mf::LogVerbatim(
"CC") <<
"CheckClusterHitFrac: Poor hit fraction " << hitFrac
4071 <<
" clBeginWir " << clBeginWir <<
" clEndWir " << clEndWir
4072 <<
" size " << fcl2hits.size() <<
" DeadWireCount " 4085 if (fcl2hits.size() < 5) {
4086 unsigned short nsing = 0;
4087 for (
unsigned short iht = 0; iht < fcl2hits.size(); ++iht)
4088 if (fHits[fcl2hits[iht]].Multiplicity() == 1) ++nsing;
4089 hitFrac = (float)nsing / (
float)fcl2hits.size();
4090 if (hitFrac < fMinHitFrac) {
4093 mf::LogVerbatim(
"CC") <<
"CheckClusterHitFrac: Poor short track hit fraction " << hitFrac;
4100 if (clBeginChg <= 0) {
4101 unsigned int iht, nht = 0;
4102 for (
unsigned short ii = 0; ii < fcl2hits.size(); ++ii) {
4104 clBeginChg += fHits[iht].Integral();
4106 if (nht == 8)
break;
4108 clBeginChg /= (float)nht;
4111 unsigned short cnt = chgNear.size() / 2;
4113 if (chgNear.size() > 60) cnt = 30;
4116 for (
unsigned short ids = 0; ids < cnt; ++ids) {
4117 clBeginChgNear += chgNear[ids];
4118 clEndChgNear += chgNear[chgNear.size() - 1 - ids];
4120 clBeginChgNear /= (float)cnt;
4121 clEndChgNear /= (float)cnt;
4126 void ClusterCrawlerAlg::FitClusterMid(
unsigned short it1,
unsigned int ihtin,
short nhit)
4128 FitClusterMid(tcl[it1].tclhits, ihtin, nhit);
4132 void ClusterCrawlerAlg::FitClusterMid(std::vector<unsigned int>& hitVec,
4145 if (hitVec.size() < 3)
return;
4147 std::vector<float> xwir;
4148 std::vector<float> ytim;
4149 std::vector<float> ytimerr2;
4151 unsigned short ii, hitcnt = 0, nht = 0, usnhit;
4161 for (ii = 0; ii < hitVec.size(); ++ii) {
4163 if (iht > fHits.size() - 1) {
4170 wire0 = fHits[iht].WireID().Wire;
4174 xwir.push_back((
float)fHits[iht].
WireID().Wire - wire0);
4175 ytim.push_back(fHits[iht].PeakTime());
4177 float terr = fHitErrFac * fHits[iht].RMS();
4178 ytimerr2.push_back(terr * terr);
4179 fAveChg += fHits[iht].Integral();
4181 if (hitcnt == usnhit)
break;
4189 for (
auto ii = hitVec.crbegin(); ii != hitVec.crend(); ++ii) {
4191 if (iht > fHits.size() - 1) {
4198 wire0 = fHits[iht].WireID().Wire;
4202 xwir.push_back((
float)fHits[iht].
WireID().Wire - wire0);
4203 ytim.push_back(fHits[iht].PeakTime());
4204 float terr = fHitErrFac * fHits[iht].RMS();
4205 ytimerr2.push_back(terr * terr);
4206 fAveChg += fHits[iht].Integral();
4208 if (hitcnt == usnhit)
break;
4214 if (nht < 2)
return;
4215 fAveChg = fAveChg / (float)nht;
4220 float intcpterr = 0.;
4221 float slopeerr = 0.;
4223 fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4225 if (clChisq > fChiCut[0])
return;
4229 clparerr[0] = intcpterr;
4230 clparerr[1] = slopeerr;
4234 void ClusterCrawlerAlg::FitCluster()
4243 if (pass > fNumPass - 1) {
4244 mf::LogError(
"CC") <<
"FitCluster called on invalid pass " << pass;
4248 unsigned short ii, nht = 0;
4250 nht = fcl2hits.size();
4253 if (nht > fLAClusMaxHitsFit) nht = fLAClusMaxHitsFit;
4256 if (nht > fMaxHitsFit[pass]) nht = fMaxHitsFit[pass];
4258 if (nht < 2)
return;
4260 std::vector<float> xwir;
4261 std::vector<float> ytim;
4262 std::vector<float> ytimerr2;
4264 float angfactor = AngleFactor(clpar[1]);
4267 unsigned int wire0 = fHits[fcl2hits[fcl2hits.size() - 1]].WireID().Wire;
4269 float terr, qave = 0, qwt;
4270 for (ii = 0; ii < nht; ++ii) {
4271 ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4272 qave += fHits[ihit].Integral();
4275 for (ii = 0; ii < nht; ++ii) {
4276 ihit = fcl2hits[fcl2hits.size() - 1 - ii];
4277 wire = fHits[ihit].WireID().Wire;
4278 xwir.push_back(wire - wire0);
4279 ytim.push_back(fHits[ihit].PeakTime());
4282 terr = fHitErrFac * fHits[ihit].RMS() * fHits[ihit].Multiplicity();
4285 qwt = (fHits[ihit].Integral() / qave) - 1;
4286 if (qwt < 1) qwt = 1;
4289 if (terr < 0.01) terr = 0.01;
4290 ytimerr2.push_back(angfactor * terr * terr);
4292 CalculateAveHitWidth();
4295 myprt <<
"FitCluster W:T ";
4296 unsigned short cnt = 0;
4297 for (std::vector<unsigned int>::reverse_iterator it = fcl2hits.rbegin();
4298 it != fcl2hits.rend();
4300 unsigned int ihit = *it;
4301 unsigned short wire = fHits[ihit].WireID().Wire;
4302 myprt << wire <<
":" << (short)fHits[ihit].PeakTime() <<
" ";
4311 if (xwir.size() < 2)
return;
4315 float intcpterr = 0.;
4316 float slopeerr = 0.;
4318 fLinFitAlg.LinFit(xwir, ytim, ytimerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4320 if (chidof > fChiCut[0])
return;
4324 clparerr[0] = intcpterr;
4325 clparerr[1] = slopeerr;
4328 mf::LogVerbatim(
"CC") <<
"nht " << nht <<
" fitpar " << (int)clpar[0] <<
"+/-" 4329 << (
int)intcpterr <<
" " << clpar[1] <<
"+/-" << slopeerr <<
" clChisq " 4333 float ClusterCrawlerAlg::AngleFactor(
float slope)
4339 if (slp > 15) slp = 15;
4341 float angfac = 1 + 0.03 * slp * slp;
4346 void ClusterCrawlerAlg::CalculateAveHitWidth()
4349 for (
unsigned short ii = 0; ii < fcl2hits.size(); ++ii)
4350 fAveHitWidth += fHits[fcl2hits[ii]].EndTick() - fHits[fcl2hits[ii]].StartTick();
4351 fAveHitWidth /= (float)fcl2hits.size();
4355 void ClusterCrawlerAlg::FitClusterChg()
4360 if (fcl2hits.size() == 0)
return;
4361 unsigned int ih0 = fcl2hits.size() - 1;
4363 if (pass >= fNumPass) {
4364 mf::LogError(
"CC") <<
"FitClusterChg bad pass " << pass;
4372 unsigned short nhave = fLAClusMaxHitsFit;
4373 if (nhave > fcl2hits.size()) nhave = fcl2hits.size();
4378 for (
unsigned short ii = 0; ii < nhave; ++ii) {
4379 iht = fcl2hits[fcl2hits.size() - 1 - ii];
4380 fAveChg += fHits[iht].Integral();
4381 fAveHitWidth += (fHits[iht].EndTick() - fHits[iht].StartTick());
4383 fAveChg /= (float)fcl2hits.size();
4384 fAveHitWidth /= (float)fcl2hits.size();
4389 unsigned short fitLen = fNHitsAve[pass];
4393 fcl2hits.size() > 5 &&
4394 fcl2hits.size() < fitLen)
4398 if (fNHitsAve[pass] < 1)
return;
4400 if (fNHitsAve[pass] == 1) {
4402 fAveChg = fHits[fcl2hits[ih0]].Integral();
4405 else if (fNHitsAve[pass] == 2) {
4407 fAveChg = (fHits[fcl2hits[ih0]].Integral() + fHits[fcl2hits[ih0 - 1]].Integral()) / 2.;
4410 else if ((
unsigned short)fcl2hits.size() > fitLen) {
4412 std::vector<float> xwir;
4413 std::vector<float> ychg;
4414 std::vector<float> ychgerr2;
4416 unsigned int wire0 = fHits[fcl2hits[fcl2hits.size() - 1]].WireID().Wire;
4418 unsigned short npt = 0;
4419 unsigned short imlast = 0;
4423 for (
unsigned int ii = fcl2hits.size() - 1; ii > 0; --ii) {
4425 float chg = fHits[fcl2hits[ii]].Integral();
4428 if (npt == fitLen) {
4435 rms = std::sqrt((rms - fnpt * ave * ave) / (fnpt - 1));
4436 float chgcut = ave + rms;
4439 for (
unsigned short ii = fcl2hits.size() - 1; ii > imlast; --ii) {
4440 wire = fHits[fcl2hits[ii]].WireID().Wire;
4441 chg = fHits[fcl2hits[ii]].Integral();
4442 if (chg > chgcut)
continue;
4443 xwir.push_back((
float)(wire - wire0));
4444 ychg.push_back(chg);
4445 ychgerr2.push_back(chg);
4447 if (ychg.size() < 3)
return;
4453 fLinFitAlg.LinFit(xwir, ychg, ychgerr2, intcpt, slope, intcpterr, slopeerr, chidof);
4455 mf::LogVerbatim(
"CC") <<
"FitClusterChg wire " << wire0 <<
" chidof " << (int)chidof
4456 <<
" npt " << xwir.size() <<
" charge = " << (int)intcpt
4457 <<
" slope = " << (
int)slope <<
" first ave " << (int)ave <<
" rms " 4459 if (chidof > 100.)
return;
4462 if (intcpt > ave)
return;
4465 ave = intcpt / fAveChg;
4466 if (ave > 1.3)
return;
4467 if (ave < 0.77)
return;
4475 void ClusterCrawlerAlg::AddLAHit(
unsigned int kwire,
bool& ChkCharge,
bool& HitOK,
bool& SigOK)
4483 if (kwire < fFirstWire || kwire > fLastWire)
return;
4485 if (fcl2hits.size() == 0)
return;
4488 if (WireHitRange[kwire].first == -1) {
4493 if (WireHitRange[kwire].first == -2)
return;
4495 unsigned int firsthit = WireHitRange[kwire].first;
4496 unsigned int lasthit = WireHitRange[kwire].second;
4499 float timeDiff = 40 * AngleFactor(clpar[1]);
4503 unsigned int lastClHit = UINT_MAX;
4504 if (fcl2hits.size() > 0) {
4505 lastClHit = fcl2hits[fcl2hits.size() - 1];
4506 if (lastClHit == 0) {
4507 fAveChg = fHits[lastClHit].Integral();
4508 fAveHitWidth = fHits[lastClHit].EndTick() - fHits[lastClHit].StartTick();
4513 float prtime = clpar[0] + ((float)kwire - clpar[2]) * clpar[1];
4514 float chgWinLo = prtime - fChgNearWindow;
4515 float chgWinHi = prtime + fChgNearWindow;
4516 float chgrat, hitWidth;
4517 float hitWidthCut = 0.5 * fAveHitWidth;
4521 mf::LogVerbatim(
"CC") <<
"AddLAHit: wire " << kwire <<
" prtime " << prtime
4522 <<
" max timeDiff " << timeDiff <<
" fAveChg " << fAveChg;
4523 unsigned int imbest = 0;
4525 for (khit = firsthit; khit < lasthit; ++khit) {
4527 if (inClus[khit] < 0)
continue;
4528 dtime =
std::abs(fHits[khit].PeakTime() - prtime);
4529 hitWidth = fHits[khit].EndTick() - fHits[khit].StartTick();
4531 if (ChkCharge && fAveChg > 0) { chgrat = fHits[khit].Integral() / fAveChg; }
4533 mf::LogVerbatim(
"CC") <<
" Chk W:T " << kwire <<
":" << (short)fHits[khit].PeakTime()
4534 <<
" dT " << std::fixed << std::setprecision(1) << dtime <<
" InClus " 4535 << inClus[khit] <<
" mult " << fHits[khit].Multiplicity() <<
" width " 4536 << (int)hitWidth <<
" MergeAvail " << mergeAvailable[khit] <<
" Chi2 " 4537 << std::fixed << std::setprecision(2) << fHits[khit].GoodnessOfFit()
4538 <<
" Charge " << (int)fHits[khit].Integral() <<
" chgrat " 4539 << std::fixed << std::setprecision(1) << chgrat <<
" index " << khit;
4541 if (fHits[khit].PeakTime() > chgWinLo && fHits[khit].PeakTime() < chgWinHi)
4542 cnear += fHits[khit].Integral();
4544 if (prtime < fHits[khit].StartTick() - timeDiff)
continue;
4545 if (prtime > fHits[khit].EndTick() + timeDiff)
continue;
4548 if (inClus[khit] > 0)
continue;
4550 if (hitWidth < hitWidthCut)
continue;
4552 if (chgrat < 0.1)
continue;
4553 if (dtime < timeDiff) {
4565 mf::LogVerbatim(
"CC") <<
" Pick hit time " << (int)fHits[imbest].PeakTime() <<
" hit index " 4570 if (lastClHit != UINT_MAX && fHits[imbest].Multiplicity() > 1) {
4571 bool doMerge =
true;
4574 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
4575 if (vtx[ivx].CTP != clCTP)
continue;
4577 mf::LogVerbatim(
"CC") <<
" close vtx chk W:T " << vtx[ivx].Wire <<
":" 4578 << (int)vtx[ivx].Time;
4579 if (
std::abs(kwire - vtx[ivx].Wire) < 5 &&
4580 std::abs(
int(fHits[imbest].PeakTime() - vtx[ivx].Time)) < 20) {
4581 if (prt)
mf::LogVerbatim(
"CC") <<
" Close to a vertex. Don't merge hits";
4588 unsigned short nused = 0;
4590 float multipletChg = 0.;
4591 float chicut = AngleFactor(clpar[1]) * fHitMergeChiCut * fHits[lastClHit].RMS();
4593 std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(imbest);
4594 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
4595 if (inClus[jht] < 0)
continue;
4596 if (inClus[jht] == 0)
4597 multipletChg += fHits[jht].Integral();
4601 if (jht > MultipletRange.first) {
4603 float hitRMS = fHits[jht].RMS();
4604 if (fHits[jht - 1].RMS() > hitRMS) hitRMS = fHits[jht - 1].RMS();
4606 std::abs(fHits[jht].PeakTime() - fHits[jht - 1].PeakTime()) / hitRMS;
4607 if (prt)
mf::LogVerbatim(
"CC") <<
" Hit RMS chisq " << tdiff <<
" chicut " << chicut;
4608 if (tdiff > chicut) doMerge =
false;
4612 if (!doMerge)
mf::LogVerbatim(
"CC") <<
" Hits are well separated. Don't merge them ";
4614 if (doMerge && nused == 0) {
4619 float chgrat = multipletChg / fHits[lastClHit].Integral();
4621 mf::LogVerbatim(
"CC") <<
" merge hits charge check " << (int)multipletChg
4622 <<
" Previous hit charge " << (
int)fHits[lastClHit].Integral();
4623 if (chgrat > 2) doMerge =
false;
4631 MergeHits(imbest, didMerge);
4636 fcl2hits.push_back(imbest);
4639 chifits.push_back(clChisq);
4640 hitNear.push_back(hnear);
4642 cnear -= fHits[imbest].Integral();
4643 if (cnear < 0) cnear = 0;
4645 cnear /= fHits[imbest].Integral();
4646 chgNear.push_back(cnear);
4648 hitWidth = fHits[imbest].EndTick() - fHits[imbest].StartTick();
4650 << timeDiff <<
" clChisq " << clChisq <<
" Chg " 4651 << (int)fHits[imbest].Integral() <<
" AveChg " << (int)fAveChg
4652 <<
" width " << (
int)hitWidth <<
" AveWidth " << (int)fAveHitWidth
4653 <<
" fcl2hits size " << fcl2hits.size();
4656 if (clChisq > fChiCut[pass]) {
4661 if (prt)
mf::LogVerbatim(
"CC") <<
" LADD- Removed bad hit. Stopped tracking";
4666 bool ClusterCrawlerAlg::ClusterHitsOK(
short nHitChk)
4679 if (fcl2hits.size() == 0)
return true;
4681 unsigned short nHitToChk = fcl2hits.size();
4682 if (nHitChk > 0) nHitToChk = nHitChk + 1;
4683 unsigned short ii, indx;
4689 if (plane < wireReadoutGeom->Nplanes(
geo::TPCID(cstat, tpc)) - 1) tol = 40;
4692 (fHits[fcl2hits[0]].PeakTime() > fHits[fcl2hits[fcl2hits.size() - 1]].PeakTime());
4695 for (ii = 0; ii < nHitToChk; ++ii) {
4696 indx = fcl2hits.size() - 1 - ii;
4697 mf::LogVerbatim(
"CC") <<
"ClusterHitsOK chk " << fHits[fcl2hits[indx]].WireID().Wire
4698 <<
" start " << fHits[fcl2hits[indx]].StartTick() <<
" peak " 4699 << fHits[fcl2hits[indx]].PeakTime() <<
" end " 4700 << fHits[fcl2hits[indx]].EndTick() <<
" posSlope " << posSlope;
4705 for (ii = 0; ii < nHitToChk - 1; ++ii) {
4706 indx = fcl2hits.size() - 1 - ii;
4709 fHits[fcl2hits[indx - 1]].
WireID().Wire) > 1)
4712 std::max(fHits[fcl2hits[indx]].StartTick(), fHits[fcl2hits[indx - 1]].StartTick());
4713 loEndTick = std::min(fHits[fcl2hits[indx]].EndTick(), fHits[fcl2hits[indx - 1]].EndTick());
4715 if (loEndTick + tol < hiStartTick) {
return false; }
4718 if (loEndTick + tol < hiStartTick) {
return false; }
4725 void ClusterCrawlerAlg::AddHit(
unsigned int kwire,
bool& HitOK,
bool& SigOK)
4736 if (kwire < fFirstWire || kwire > fLastWire)
return;
4738 unsigned int lastClHit = UINT_MAX;
4739 if (fcl2hits.size() > 0) lastClHit = fcl2hits[fcl2hits.size() - 1];
4742 unsigned int wire0 = clpar[2];
4745 if (fAllowNoHitWire == 0) {
4746 if (WireHitRange[kwire].first == -2)
return;
4750 if (WireHitRange[kwire].first == -2 && (wire0 - kwire) > fAllowNoHitWire) {
4756 if (WireHitRange[kwire].first == -1) {
4761 unsigned int firsthit = WireHitRange[kwire].first;
4762 unsigned int lasthit = WireHitRange[kwire].second;
4765 float dw = (float)kwire - (
float)wire0;
4766 float prtime = clpar[0] + dw * clpar[1];
4767 if (prtime < 0 || (
unsigned int)prtime > fMaxTime)
return;
4770 float prtimerr2 =
std::abs(dw) * clparerr[1] * clparerr[1];
4774 if (lastClHit != UINT_MAX) hiterr = 3 * fHitErrFac * fHits[lastClHit].RMS();
4775 float err = std::sqrt(prtimerr2 + hiterr * hiterr);
4777 float hitWin = fClProjErrFac * err;
4779 float prtimeLo = prtime - hitWin;
4780 float prtimeHi = prtime + hitWin;
4781 float chgWinLo = prtime - fChgNearWindow;
4782 float chgWinHi = prtime + fChgNearWindow;
4784 mf::LogVerbatim(
"CC") <<
"AddHit: wire " << kwire <<
" prtime Lo " << (int)prtimeLo
4785 <<
" prtime " << (
int)prtime <<
" Hi " << (int)prtimeHi <<
" prtimerr " 4786 << sqrt(prtimerr2) <<
" hiterr " << hiterr <<
" fAveChg " 4787 << (int)fAveChg <<
" fAveHitWidth " << std::setprecision(3)
4791 unsigned int imbest = INT_MAX;
4792 float best = 9999., dtime;
4794 float hitTime, hitChg, hitStartTick, hitEndTick;
4795 for (
unsigned int khit = firsthit; khit < lasthit; ++khit) {
4797 if (inClus[khit] < 0)
continue;
4798 hitTime = fHits[khit].PeakTime();
4799 dtime =
std::abs(hitTime - prtime);
4800 if (dtime > 1000)
continue;
4801 hitStartTick = fHits[khit].StartTick();
4802 hitEndTick = fHits[khit].EndTick();
4804 if (fAveChg > 0) dtime *=
std::abs(fHits[khit].Integral() - fAveChg) / fAveChg;
4805 if (prt &&
std::abs(dtime) < 100) {
4807 << std::setprecision(1) << (hitTime - prtime) <<
" InClus " 4808 << inClus[khit] <<
" mult " << fHits[khit].Multiplicity() <<
" RMS " 4809 << std::fixed << std::setprecision(1) << fHits[khit].RMS() <<
" Chi2 " 4810 << std::fixed << std::setprecision(1) << fHits[khit].GoodnessOfFit()
4811 <<
" Charge " << (int)fHits[khit].Integral() <<
" Peak " << std::fixed
4812 << std::setprecision(1) << fHits[khit].PeakAmplitude() <<
" LoT " 4813 << (int)hitStartTick <<
" HiT " << (
int)hitEndTick <<
" index " 4817 if (fHits[khit].StartTick() > chgWinLo && fHits[khit].EndTick() < chgWinHi)
4818 cnear += fHits[khit].Integral();
4820 if (prtimeHi < hitStartTick)
continue;
4821 if (prtimeLo > hitEndTick)
continue;
4824 if (hitTime < prtimeLo)
continue;
4825 if (hitTime > prtimeHi)
continue;
4827 if (inClus[khit] > 0)
continue;
4835 if (fAllowNoHitWire == 0)
return;
4837 mf::LogVerbatim(
"CC") <<
" wire0 " << wire0 <<
" kwire " << kwire <<
" max " 4838 << fAllowNoHitWire <<
" imbest " << imbest;
4839 if ((wire0 - kwire) > fAllowNoHitWire)
return;
4843 if (imbest == INT_MAX)
return;
4852 bool didMerge =
false;
4853 if (lastClHit != UINT_MAX && fAveHitWidth > 0 && fHitMergeChiCut > 0 &&
4855 bool doMerge =
true;
4856 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
4857 if (
std::abs(kwire - vtx[ivx].Wire) < 10 &&
4864 if (hit.
LocalIndex() != 0 && imbest == 0) doMerge =
false;
4868 if (hit.
LocalIndex() == 0) { oht = imbest + 1; }
4875 hitSep /= hit.
RMS();
4877 float totChg = hitChg + other_hit.
Integral();
4878 float lastHitChg = fAveChg;
4879 if (lastHitChg < 0) lastHitChg = fHits[lastClHit].Integral();
4882 mf::LogVerbatim(
"CC") <<
" Chk hit merge hitsep " << hitSep <<
" dChg " 4883 <<
std::abs(totChg - lastHitChg) <<
" Cut " 4885 if (inClus[oht] == 0 && hitSep < fHitMergeChiCut) {
4887 MergeHits(imbest, didMerge);
4897 float chgrat = (hitChg - fAveChg) / fAveChg;
4898 if (prt)
mf::LogVerbatim(
"CC") <<
" Chgrat " << std::setprecision(2) << chgrat;
4901 if (chgrat > 3 * fChgCut[pass]) {
4903 mf::LogVerbatim(
"CC") <<
" fails 3 x high charge cut " << fChgCut[pass] <<
" on pass " 4911 float bigchgcut = 1.5 * fChgCut[pass];
4912 bool lasthitbig =
false;
4913 bool lasthitlow =
false;
4915 float lastchgrat = (fHits[lastClHit].Integral() - fAveChg) / fAveChg;
4916 lasthitbig = (lastchgrat > bigchgcut);
4917 lasthitlow = (lastchgrat < -fChgCut[pass]);
4921 if (lasthitlow && chgrat < -fChgCut[pass]) {
4922 if (prt)
mf::LogVerbatim(
"CC") <<
" fails low charge cut. Stop crawling.";
4928 if (lasthitbig && chgrat > fChgCut[pass]) {
4930 mf::LogVerbatim(
"CC") <<
" fails 2nd hit high charge cut. Last hit was high also. ";
4935 if (chgrat > fChgCut[pass]) {
4936 if (best > 2 * err) {
4937 if (prt)
mf::LogVerbatim(
"CC") <<
" high charge && bad dT= " << best <<
" err= " << err;
4943 fitChg = (chgrat <
std::abs(fChgCut[pass]));
4947 fcl2hits.push_back(imbest);
4949 if (fcl2hits.size() == 3) std::sort(fcl2hits.begin(), fcl2hits.end(),
SortByLowHit);
4951 chifits.push_back(clChisq);
4952 hitNear.push_back(hnear);
4954 cnear -= fHits[imbest].Integral();
4955 if (cnear < 0) cnear = 0;
4957 cnear /= fHits[imbest].Integral();
4958 chgNear.push_back(cnear);
4963 if (chgNear.size() != fcl2hits.size()) {
4970 <<
" clChisq " << clChisq <<
" Chg " << (int)fHits[imbest].Integral()
4971 <<
" AveChg " << (int)fAveChg <<
" fcl2hits size " << fcl2hits.size();
4973 if (!fitChg)
return;
4979 void ClusterCrawlerAlg::ChkClusterNearbyHits(
bool prt)
4986 if (fHitMergeChiCut <= 0)
return;
4988 if (hitNear.size() != fcl2hits.size()) {
4989 mf::LogWarning(
"CC") <<
"Coding error: hitNear size != fcl2hits";
4994 if (hitNear.size() < 12)
return;
4997 unsigned short ii, indx;
4998 unsigned short merged = 0;
4999 unsigned short notmerged = 0;
5000 for (ii = 0; ii < 6; ++ii) {
5001 indx = hitNear.size() - 1 - ii;
5002 if (hitNear[indx] > 0) ++notmerged;
5003 if (hitNear[indx] < 0) ++merged;
5007 mf::LogVerbatim(
"CC") <<
"ChkClusterNearbyHits: nearby hits merged " << merged
5008 <<
" not merged " << notmerged;
5010 if (notmerged < 2)
return;
5016 for (ii = 0; ii < 6; ++ii) {
5017 indx = fcl2hits.size() - 1 - ii;
5018 const unsigned int iht = fcl2hits[indx];
5022 if (hit.
LocalIndex() != 0 && iht == 0)
continue;
5025 if (hit.
LocalIndex() == 0) { oht = iht + 1; }
5032 hitSep /= hit.
RMS();
5033 if (hitSep < fHitMergeChiCut && inClus[oht] == 0) {
5036 << fHits[iht].WireID().Wire <<
":" << fHits[iht].PeakTime();
5037 MergeHits(iht, didMerge);
5038 if (didMerge) hitNear[indx] = -1;
5047 if (prt)
mf::LogVerbatim(
"CC") <<
"ChkClusterNearbyHits refit cluster. fAveChg= " << fAveChg;
5052 void ClusterCrawlerAlg::FitVtx(
unsigned short iv)
5054 std::vector<float>
x;
5055 std::vector<float>
y;
5056 std::vector<float> ey2;
5060 if (vtx[iv].Fixed)
return;
5063 vtx[iv].ChiDOF = 99;
5067 std::vector<unsigned short> vcl;
5068 for (icl = 0; icl < tcl.size(); ++icl) {
5069 if (tcl[icl].ID < 0)
continue;
5070 if (tcl[icl].CTP != vtx[iv].CTP)
continue;
5071 if (tcl[icl].EndVtx == iv) vcl.push_back(icl);
5072 if (tcl[icl].BeginVtx == iv) vcl.push_back(icl);
5075 vtx[iv].NClusters = vcl.size();
5077 if (vcl.size() == 0)
return;
5083 unsigned short indx = tcl[icl].tclhits.size() - 1;
5084 unsigned int hit = tcl[icl].tclhits[indx];
5085 float minTimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5087 if (vcl.size() == 1) {
5090 if (tcl[icl].EndVtx == iv) {
5091 vtx[iv].Wire = tcl[icl].EndWir;
5092 vtx[iv].WireErr = 1;
5093 vtx[iv].Time = tcl[icl].EndTim;
5095 indx = tcl[icl].tclhits.size() - 1;
5096 hit = tcl[icl].tclhits[indx];
5097 vtx[iv].TimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5100 if (tcl[icl].BeginVtx == iv) {
5101 vtx[iv].Wire = tcl[icl].BeginWir;
5102 vtx[iv].WireErr = 1;
5103 vtx[iv].Time = tcl[icl].BeginTim;
5105 hit = tcl[icl].tclhits[0];
5106 vtx[iv].TimeErr = fHitErrFac * fHits[hit].RMS() * fHits[hit].Multiplicity();
5112 std::vector<double> slps;
5113 std::vector<double> slperrs;
5114 for (
unsigned short ii = 0; ii < vcl.size(); ++ii) {
5116 if (tcl[icl].EndVtx == iv) {
5117 x.push_back(tcl[icl].EndSlp);
5118 slps.push_back(tcl[icl].EndSlp);
5119 slperrs.push_back(tcl[icl].EndSlpErr);
5120 arg = tcl[icl].EndSlp * tcl[icl].EndWir - tcl[icl].EndTim;
5122 if (tcl[icl].EndSlpErr > 0.) { arg = tcl[icl].EndSlpErr * tcl[icl].EndWir; }
5124 arg = .1 * tcl[icl].EndWir;
5126 ey2.push_back(arg * arg);
5128 else if (tcl[icl].BeginVtx == iv) {
5129 x.push_back(tcl[icl].BeginSlp);
5130 slps.push_back(tcl[icl].BeginSlp);
5131 slperrs.push_back(tcl[icl].BeginSlpErr);
5132 arg = tcl[icl].BeginSlp * tcl[icl].BeginWir - tcl[icl].BeginTim;
5134 if (tcl[icl].BeginSlpErr > 0.) { arg = tcl[icl].BeginSlpErr * tcl[icl].BeginWir; }
5136 arg = .1 * tcl[icl].BeginWir;
5138 ey2.push_back(arg * arg);
5141 if (x.size() < 2)
return;
5144 double sumerr = 0, cnt = 0;
5145 for (
unsigned short ii = 0; ii < slps.size() - 1; ++ii) {
5146 for (
unsigned short jj = ii + 1; jj < slps.size(); ++jj) {
5147 arg = std::min(slperrs[ii], slperrs[jj]);
5148 arg /= (slps[ii] - slps[jj]);
5149 sumerr += arg * arg;
5156 float vTimeErr = 0.;
5158 float vWireErr = 0.;
5160 fLinFitAlg.LinFit(x, y, ey2, vTime, vWire, vTimeErr, vWireErr, chiDOF);
5161 if (chiDOF > 900)
return;
5164 if (vTime < 0 || vTime > fMaxTime)
return;
5167 if (vWire < 0 || vWire > wireReadoutGeom->Nwires(iplID))
return;
5168 vtx[iv].ChiDOF = chiDOF;
5169 vtx[iv].Wire = vWire;
5170 vtx[iv].Time = vTime;
5171 vtx[iv].WireErr = vWire * sqrt(sumerr);
5172 vtx[iv].TimeErr = vTime * fabs(sumerr);
5174 if (vtx[iv].WireErr < 1) vtx[iv].WireErr = 2;
5176 if (vtx[iv].TimeErr < minTimeErr) vtx[iv].TimeErr = minTimeErr;
5186 if (
empty(vtx3))
return;
5188 const unsigned int cstat = tpcid.
Cryostat;
5189 const unsigned int tpc = tpcid.
TPC;
5191 unsigned int thePlane, theWire;
5195 for (
unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5197 if (vtx3[ivx].Wire < 0)
continue;
5198 if (vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc)
continue;
5201 theWire = vtx3[ivx].Wire;
5202 for (plane = 0; plane < 3; ++plane) {
5203 if (vtx3[ivx].Ptr2D[plane] >= 0)
continue;
5207 if (thePlane > 2)
continue;
5209 clCTP =
EncodeCTP(cstat, tpc, thePlane);
5212 vnew.
Wire = theWire;
5213 vnew.
Time = theTime;
5217 vtx.push_back(vnew);
5218 unsigned short ivnew = vtx.size() - 1;
5219 std::vector<short> vclIndex;
5220 for (
unsigned short icl = 0; icl < tcl.size(); ++icl) {
5221 if (tcl[icl].ID < 0)
continue;
5222 if (tcl[icl].CTP != clCTP)
continue;
5226 if (dwb > 10 && dwe > 10)
continue;
5227 if (dwb < dwe && dwb < 10 && tcl[icl].BeginVtx < 0) {
5229 if (theWire < tcl[icl].BeginWir + 5)
continue;
5230 if (ClusterVertexChi(icl, 0, ivnew) > fVertex3DCut)
continue;
5231 tcl[icl].BeginVtx = ivnew;
5232 vclIndex.push_back(icl);
5234 else if (dwe < 10 && tcl[icl].EndVtx < 0) {
5236 if (theWire > tcl[icl].EndWir - 5)
continue;
5237 if (ClusterVertexChi(icl, 1, ivnew) > fVertex3DCut)
continue;
5238 tcl[icl].EndVtx = ivnew;
5239 vclIndex.push_back(icl);
5242 bool goodVtx =
false;
5243 if (vclIndex.size() > 0) {
5245 goodVtx = (vtx[ivnew].ChiDOF < fVertex3DCut);
5246 vtx3[ivx].Ptr2D[thePlane] = ivnew;
5249 vtx3[ivx].Ptr2D[thePlane] = ivnew;
5250 vtx3[ivx].Wire = -1;
5255 for (
unsigned short ii = 0; ii < vclIndex.size(); ++ii) {
5256 unsigned short icl = vclIndex[ii];
5257 if (tcl[icl].BeginVtx == ivnew) tcl[icl].BeginVtx = -99;
5258 if (tcl[icl].EndVtx == ivnew) tcl[icl].EndVtx = -99;
5270 if (
empty(vtx3))
return;
5272 const unsigned int cstat = tpcid.
Cryostat;
5273 const unsigned int tpc = tpcid.
TPC;
5275 vtxprt = (fDebugPlane >= 0) && (fDebugHit == 6666);
5277 unsigned int lastplane = 5, kcl, kclID;
5279 unsigned int thePlane, theWire, plane;
5280 unsigned int loWire, hiWire;
5282 for (
unsigned short ivx = 0; ivx < vtx3.size(); ++ivx) {
5283 if (vtx3[ivx].CStat != cstat || vtx3[ivx].TPC != tpc)
continue;
5286 mf::LogVerbatim(
"CC") <<
"Vtx3ClusterSplit ivx " << ivx <<
" Ptr2D " << vtx3[ivx].Ptr2D[0]
5287 <<
" " << vtx3[ivx].Ptr2D[1] <<
" " << vtx3[ivx].Ptr2D[2] <<
" wire " 5289 if (vtx3[ivx].Wire < 0)
continue;
5292 theWire = vtx3[ivx].Wire;
5293 for (plane = 0; plane < 3; ++plane) {
5294 if (vtx3[ivx].Ptr2D[plane] >= 0)
continue;
5298 if (thePlane > 2)
continue;
5300 (
double)vtx3[ivx].
X, (
int)thePlane, (
int)tpcid.
TPC, (
int)tpcid.
Cryostat);
5302 if (thePlane != lastplane) {
5305 lastplane = thePlane;
5308 std::vector<short> clIDs;
5309 if (theWire > fFirstWire + 5) { loWire = theWire - 5; }
5311 loWire = fFirstWire;
5313 if (theWire < fLastWire - 5) { hiWire = theWire + 5; }
5318 mf::LogVerbatim(
"CC") <<
"3DVtx " << ivx <<
" look for cluster hits near P:W:T " << thePlane
5319 <<
":" << theWire <<
":" << (int)theTime <<
" Wire range " << loWire
5320 <<
" to " << hiWire;
5321 for (
unsigned int wire = loWire; wire < hiWire; ++wire) {
5323 if (WireHitRange[wire].first < 0)
continue;
5324 unsigned int firsthit = WireHitRange[wire].first;
5325 unsigned int lasthit = WireHitRange[wire].second;
5326 for (
unsigned int khit = firsthit; khit < lasthit; ++khit) {
5328 if (inClus[khit] <= 0)
continue;
5329 if ((
unsigned int)inClus[khit] > tcl.size() + 1) {
5330 mf::LogError(
"CC") <<
"Invalid hit InClus. " << khit <<
" " << inClus[khit];
5334 if (theTime < fHits[khit].StartTick() - 20)
continue;
5335 if (theTime > fHits[khit].EndTick() + 20)
continue;
5336 kclID = inClus[khit];
5339 if (tcl[kcl].ID < 0)
continue;
5341 if (tcl[kcl].tclhits.size() < 6)
continue;
5343 if (tcl[kcl].tclhits.size() > 100 &&
std::abs(tcl[kcl].BeginAng - tcl[kcl].EndAng) < 0.1)
5347 mf::LogVerbatim(
"CC") <<
"Bingo " << ivx <<
" plane " << thePlane <<
" wire " << wire
5348 <<
" hit " << fHits[khit].WireID().Wire <<
":" 5349 << (int)fHits[khit].PeakTime() <<
" inClus " << inClus[khit]
5350 <<
" P:W:T " << thePlane <<
":" << tcl[kcl].BeginWir <<
":" 5351 << (int)tcl[kcl].BeginTim;
5352 if (std::find(clIDs.begin(), clIDs.end(), kclID) == clIDs.end()) {
5353 clIDs.push_back(kclID);
5357 if (clIDs.size() == 0)
continue;
5359 for (
unsigned int ii = 0; ii < clIDs.size(); ++ii)
5362 unsigned short ii, icl, jj;
5369 unsigned short i2Dvx = 0;
5370 for (ii = 0; ii < 3; ++ii) {
5371 if (ii == thePlane)
continue;
5372 i2Dvx = vtx3[ivx].Ptr2D[ii];
5373 if (i2Dvx > vtx.size() - 1) {
5374 mf::LogError(
"CC") <<
"Vtx3ClusterSplit: Coding error";
5377 if (vtx[i2Dvx].TimeErr > tErr) tErr = vtx[i2Dvx].TimeErr;
5381 for (ii = 0; ii < clIDs.size(); ++ii) {
5382 icl = clIDs[ii] - 1;
5384 for (jj = 0; jj < tcl[icl].tclhits.size(); ++jj) {
5385 iht = tcl[icl].tclhits[jj];
5386 if (fHits[iht].
WireID().Wire < theWire) {
5388 if (jj > 3) nhitfit = -3;
5389 FitClusterMid(icl, iht, nhitfit);
5390 float doca = DoCA(-1, 1, theWire, theTime);
5392 mf::LogVerbatim(
"CC") <<
" cls " << icl <<
" DoCA " << doca <<
" tErr " << tErr;
5393 if ((doca / tErr) > 2) clIDs[ii] = -1;
5403 for (ii = 0; ii < clIDs.size(); ++ii)
5408 unsigned short nok = 0;
5409 for (ii = 0; ii < clIDs.size(); ++ii)
5410 if (clIDs[ii] >= 0) ++nok;
5411 if (nok == 0)
continue;
5415 vnew.
Wire = theWire;
5417 vnew.
Time = theTime;
5422 vtx.push_back(vnew);
5424 unsigned short ivnew = vtx.size() - 1;
5426 mf::LogVerbatim(
"CC") <<
"Make new 2D vtx " << ivnew <<
" in plane " << thePlane
5427 <<
" from 3D vtx " << ivx;
5428 vtx3[ivx].Ptr2D[thePlane] = ivnew;
5430 for (ii = 0; ii < clIDs.size(); ++ii) {
5431 if (clIDs[ii] < 0)
continue;
5432 icl = clIDs[ii] - 1;
5435 unsigned short pos = 0;
5436 for (
unsigned short jj = 0; jj < tcl[icl].tclhits.size(); ++jj) {
5437 iht = tcl[icl].tclhits[jj];
5438 if (fHits[iht].
WireID().Wire < theWire) {
5445 tcl[icl].BeginVtx = ivnew;
5448 else if (pos > tcl[icl].tclhits.size()) {
5450 tcl[icl].EndVtx = ivnew;
5455 if (vtxprt)
mf::LogVerbatim(
"CC") <<
"Split cluster " << clIDs[ii] <<
" at pos " << pos;
5456 if (!SplitCluster(icl, pos, ivnew)) {
5460 tcl[icl].ProcCode += 10000;
5461 tcl[tcl.size() - 1].ProcCode += 10000;
5466 if (vtx[ivnew].ChiDOF < 5 && vtx[ivnew].WireErr < fVertex2DWireErrCut) {
5468 vtx3[ivx].Wire = -1;
5472 mf::LogVerbatim(
"CC") <<
"Bad vtx fit " << ivnew <<
" ChiDOF " << vtx[ivnew].ChiDOF
5473 <<
" WireErr " << vtx[ivnew].WireErr;
5476 vtx3[ivx].Ptr2D[thePlane] = -1;
5478 for (jj = 0; jj < tcl.size(); ++jj) {
5479 if (tcl[jj].BeginVtx == ivnew) tcl[jj].BeginVtx = -99;
5480 if (tcl[jj].EndVtx == ivnew) tcl[jj].EndVtx = -99;
5495 unsigned int nPln = wireReadoutGeom->Nplanes(
geo::TPCID(cstat, tpc));
5496 if (nPln != 3)
return;
5498 float ew1, ew2, bw2, fvw;
5505 unsigned short longClIndex;
5506 unsigned short shortClIndex;
5507 unsigned short splitPos;
5509 std::array<std::vector<Hammer>, 3> hamrVec;
5513 for (ipl = 0; ipl < 3; ++ipl) {
5515 for (
unsigned short ic1 = 0; ic1 < tcl.size(); ++ic1) {
5516 if (tcl[ic1].ID < 0)
continue;
5518 if (tcl[ic1].tclhits.size() < 20)
continue;
5519 if (tcl[ic1].CTP != clCTP)
continue;
5521 if (tcl[ic1].EndVtx >= 0)
continue;
5522 ew1 = tcl[ic1].EndWir;
5523 for (
unsigned short ic2 = 0; ic2 < tcl.size(); ++ic2) {
5524 if (tcl[ic2].ID < 0)
continue;
5526 if (tcl[ic2].tclhits.size() > 20)
continue;
5528 if (tcl[ic2].tclhits.size() < 6)
continue;
5529 if (tcl[ic2].CTP != clCTP)
continue;
5530 ew2 = tcl[ic2].EndWir;
5531 bw2 = tcl[ic2].BeginWir;
5534 if (ew1 < ew2 || ew1 > bw2)
continue;
5538 unsigned short spos = 0;
5539 for (
unsigned short ii = 0; ii < tcl[ic2].tclhits.size(); ++ii) {
5540 unsigned int iht = tcl[ic2].tclhits[ii];
5541 float dw = fHits[iht].WireID().Wire - tcl[ic1].EndWir;
5542 float dt = fabs(fHits[iht].PeakTime() - tcl[ic1].EndTim - tcl[ic1].EndSlp * dw);
5549 if (ibst < 0)
continue;
5550 fvw = 0.5 + fHits[ibst].WireID().Wire;
5553 aHam.Wire = (0.5 + fvw);
5554 aHam.Tick = fHits[ibst].PeakTime();
5555 aHam.X = det_prop.
ConvertTicksToX((
double)aHam.Tick, (
int)ipl, (
int)tpc, (
int)cstat);
5556 aHam.longClIndex = ic1;
5557 aHam.shortClIndex = ic2;
5558 aHam.splitPos = spos;
5559 unsigned short indx = hamrVec[ipl].size();
5560 hamrVec[ipl].resize(indx + 1);
5561 hamrVec[ipl][indx] = aHam;
5568 unsigned short noham = 0;
5569 for (ipl = 0; ipl < 3; ++ipl)
5570 if (hamrVec[ipl].
size() == 0) ++noham;
5571 if (noham > 1)
return;
5578 float YLo = world.Y() - thetpc.
HalfHeight() + 1;
5579 float YHi = world.Y() + thetpc.
HalfHeight() - 1;
5580 float ZLo = world.Z() - thetpc.
Length() / 2 + 1;
5581 float ZHi = world.Z() + thetpc.
Length() / 2 - 1;
5585 unsigned short icl, jpl, jcl, kpl, splitPos;
5586 for (ipl = 0; ipl < 3; ++ipl) {
5587 if (hamrVec[ipl].
size() == 0)
continue;
5588 jpl = (ipl + 1) % nPln;
5589 kpl = (jpl + 1) % nPln;
5590 for (
unsigned short ii = 0; ii < hamrVec[ipl].size(); ++ii) {
5591 if (hamrVec[ipl][ii].Used)
continue;
5592 for (
unsigned short jj = 0; jj < hamrVec[jpl].size(); ++jj) {
5593 if (hamrVec[jpl][jj].Used)
continue;
5594 dX = hamrVec[ipl][ii].X - hamrVec[jpl][jj].X;
5595 if (fabs(dX) > fVertex3DCut)
continue;
5598 auto const intersection =
5599 wireReadoutGeom->WireIDsIntersect(
geo::WireID{plane_i, hamrVec[ipl][ii].Wire},
5601 if (!intersection)
continue;
5603 auto const [
y,
z] = std::make_pair(intersection->y, intersection->z);
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 = wireReadoutGeom->Plane({cstat, tpc, kpl}).NearestWireID(WPos).Wire;
5671 vtx3.push_back(newVtx3);
5686 unsigned int nplanes = wireReadoutGeom->Nplanes(tpcid);
5692 float YLo = world.Y() - TPC.
HalfHeight() + 1;
5693 float YHi = world.Y() + TPC.
HalfHeight() - 1;
5694 float ZLo = world.Z() - TPC.
Length() / 2 + 1;
5695 float ZHi = world.Z() + TPC.
Length() / 2 - 1;
5697 vtxprt = (fDebugPlane >= 0) && (fDebugHit == 6666);
5705 float wirePitch = wireReadoutGeom->FirstPlane(tpcid).WirePitch();
5708 std::vector<float> vX(vtx.size());
5709 std::vector<float> vXsigma(vtx.size());
5711 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5712 if (vtx[ivx].NClusters == 0)
continue;
5714 if (iplID.
TPC != tpc || iplID.
Cryostat != cstat)
continue;
5719 (
double)(vtx[ivx].Time + vtx[ivx].TimeErr), (
int)iplID.
Plane, (
int)tpc, (
int)cstat);
5720 vXsigma[ivx] = fabs(vXp - vX[ivx]);
5724 std::array<std::vector<unsigned short>, 3> vIndex;
5725 unsigned short indx, ipl;
5726 for (
unsigned short ivx = 0; ivx < vtx.size(); ++ivx) {
5727 if (vtx[ivx].NClusters == 0)
continue;
5729 if (iplID.
TPC != tpc || iplID.
Cryostat != cstat)
continue;
5731 if (ipl > 2)
continue;
5732 indx = vIndex[ipl].size();
5733 vIndex[ipl].resize(indx + 1);
5734 vIndex[ipl][indx] = ivx;
5738 std::vector<short> vPtr;
5739 for (
unsigned short ii = 0; ii < vtx.size(); ++ii)
5743 std::vector<Vtx3Store> v3temp;
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;
5794 auto const intersection = wireReadoutGeom->WireIDsIntersect(
5796 if (!intersection)
continue;
5797 auto const [
y,
z] = std::make_pair(intersection->y, intersection->z);
5798 if (y < YLo || y > YHi || z < ZLo || z > ZHi)
continue;
5801 kpl = 3 - ipl - jpl;
5802 kX = 0.5 * (vX[ivx] + vX[jvx]);
5806 kWire = wireReadoutGeom->Plane({cstat, tpc, kpl}).NearestWireID(WPos).Wire;
5812 kpl = 3 - ipl - jpl;
5816 tmpIndex[ipl] = ivx;
5817 tmpIndex[jpl] = jvx;
5819 v3d.
Ptr2D = tmpIndex;
5823 float yzSigma = wirePitch * sqrt(vtx[ivx].WireErr * vtx[ivx].WireErr +
5824 vtx[jvx].WireErr * vtx[jvx].WireErr);
5831 v3temp.push_back(v3d);
5835 <<
"VtxMatch: 2 Plane match ivx " << ivx <<
" P:W:T " << ipl <<
":" 5836 << (int)vtx[ivx].Wire <<
":" << (
int)vtx[ivx].Time <<
" jvx " << jvx <<
" P:W:T " 5837 << jpl <<
":" << (int)vtx[jvx].Wire <<
":" << (
int)vtx[jvx].Time <<
" dXChi " 5838 << dXChi <<
" yzSigma " << yzSigma;
5840 if (nplanes == 2)
continue;
5842 best = fVertex3DCut;
5843 for (kk = 0; kk < vIndex[kpl].size(); ++kk) {
5844 kvx = vIndex[kpl][kk];
5845 if (vPtr[kvx] >= 0)
continue;
5847 float dW = wirePitch * (vtx[kvx].Wire -
kWire) / yzSigma;
5849 float dX = (vX[kvx] -
kX) / dXSigma;
5850 float kChi = 0.5 * sqrt(dW * dW + dX * dX);
5853 xbest = (vX[kvx] + 2 *
kX) / 3;
5856 t2dIndex[ipl] = ivx;
5857 t2dIndex[jpl] = jvx;
5858 t2dIndex[kpl] = kvx;
5859 v3dBest = v3temp.size() - 1;
5864 <<
" kvx " << kvx <<
" kpl " << kpl <<
" wire " << (int)vtx[kvx].Wire <<
" kTime " 5865 << (
int)vtx[kvx].Time <<
" kChi " << kChi <<
" best " << best <<
" dW " 5866 << vtx[kvx].Wire -
kWire;
5870 mf::LogVerbatim(
"CC") <<
" done best = " << best <<
" fVertex3DCut " << fVertex3DCut;
5871 if (nplanes > 2 && best < fVertex3DCut) {
5873 if (v3dBest > v3temp.size() - 1) {
5874 mf::LogError(
"CC") <<
"VtxMatch: bad v3dBest " << v3dBest;
5878 v3d.
Ptr2D = t2dIndex;
5884 vtx3.push_back(v3d);
5887 for (
unsigned short jj = 0; jj < 3; ++jj)
5888 if (t2dIndex[jj] >= 0) vPtr[t2dIndex[jj]] = vtx3.size() - 1;
5892 <<
"New 3D vtx " << vtx3.size() <<
" X " << v3d.
X <<
" Y " << v3d.
Y <<
" Z " 5893 << v3d.
Z <<
" t2dIndex " << t2dIndex[0] <<
" " << t2dIndex[1] <<
" " 5894 << t2dIndex[2] <<
" best Chi " << best;
5906 unsigned short vsize = vtx3.size();
5907 for (
unsigned short it = 0; it < v3temp.size(); ++it) {
5909 for (
unsigned short i3d = 0; i3d < vsize; ++i3d) {
5910 for (
unsigned short plane = 0; plane < 3; ++plane) {
5911 if (v3temp[it].Ptr2D[plane] == vtx3[i3d].Ptr2D[plane]) {
5919 if (keepit) vtx3.push_back(v3temp[it]);
5924 for (
unsigned short iv3 = 0; iv3 < vtx3.size(); ++iv3) {
5925 vtx3[iv3].Ptr2D[2] = 666;
5930 for (
unsigned short it = 0; it < vtx3.size(); ++it) {
5931 mf::LogVerbatim(
"CC") <<
"vtx3 " << it <<
" Ptr2D " << vtx3[it].Ptr2D[0] <<
" " 5932 << vtx3[it].Ptr2D[1] <<
" " << vtx3[it].Ptr2D[2] <<
" wire " 5940 void ClusterCrawlerAlg::GetHitRange(
CTP_t CTP)
5946 unsigned int nwires = wireReadoutGeom->Nwires(planeID);
5947 WireHitRange.resize(nwires + 1);
5953 unsigned int wire, iht;
5954 unsigned int nHitInPlane;
5955 std::pair<int, int> flag;
5960 for (
auto& apair : WireHitRange)
5965 std::vector<bool> firsthit;
5966 firsthit.resize(nwires + 1,
true);
5967 bool firstwire =
true;
5968 for (iht = 0; iht < fHits.size(); ++iht) {
5969 if (fHits[iht].
WireID().asPlaneID() != planeID)
continue;
5970 wire = fHits[iht].WireID().Wire;
5972 if (firsthit[wire]) {
5973 WireHitRange[wire].first = iht;
5974 firsthit[wire] =
false;
5980 WireHitRange[wire].second = iht + 1;
5981 fLastWire = wire + 1;
5985 lariov::ChannelStatusProvider
const& channelStatus =
5990 unsigned int nbad = 0;
5991 for (wire = 0; wire < nwires; ++wire) {
5993 if (!channelStatus.IsGood(chan)) {
5994 WireHitRange[wire] = flag;
5999 if (mergeAvailable.size() < fHits.size())
6001 <<
"GetHitRange: Invalid mergeAvailable vector size " << mergeAvailable.size()
6003 unsigned int firstHit, lastHit;
6006 float maxRMS, chiSep, peakCut;
6007 for (wire = 0; wire < nwires; ++wire) {
6009 if (WireHitRange[wire].first < 0)
continue;
6010 firstHit = WireHitRange[wire].first;
6011 lastHit = WireHitRange[wire].second;
6012 for (iht = firstHit; iht < lastHit; ++iht) {
6013 if (fHits[iht].
WireID().Wire != wire)
6015 <<
"Bad WireHitRange on wire " << wire <<
"\n";
6017 if (fHits[iht].Multiplicity() > 1) {
6018 peakCut = 0.6 * fHits[iht].PeakAmplitude();
6019 std::pair<size_t, size_t> MultipletRange = FindHitMultiplet(iht);
6020 for (
size_t jht = MultipletRange.first; jht < MultipletRange.second; ++jht) {
6021 if (jht == iht)
continue;
6023 if (fHits[jht].PeakAmplitude() < peakCut)
continue;
6024 maxRMS = std::max(fHits[iht].RMS(), fHits[jht].RMS());
6025 chiSep =
std::abs(fHits[iht].PeakTime() - fHits[jht].PeakTime()) / maxRMS;
6026 if (chiSep < fHitMergeChiCut) {
6027 mergeAvailable[iht] =
true;
6034 if (cnt != nHitInPlane)
6035 mf::LogWarning(
"CC") <<
"Bad WireHitRange count " << cnt <<
" " << nHitInPlane <<
"\n";
6037 if (!fMergeAllHits)
return;
6041 for (wire = 0; wire < nwires; ++wire) {
6042 if (WireHitRange[wire].first < 0)
continue;
6043 firstHit = WireHitRange[wire].first;
6044 lastHit = WireHitRange[wire].second;
6045 for (iht = firstHit; iht < lastHit; ++iht) {
6046 if (!mergeAvailable[iht])
continue;
6048 if (fHits[iht].GoodnessOfFit() == 6666)
continue;
6049 MergeHits(iht, didMerge);
6050 mergeAvailable[iht] =
false;
6059 if (inWire1 > inWire2) {
6061 unsigned int tmp = inWire1;
6066 unsigned int wire, ndead = 0;
6067 for (wire = inWire1; wire < inWire2; ++wire)
6068 if (WireHitRange[wire].first == -1) ++ndead;
6076 if (fcl2hits.size() < 2)
return 0;
6077 unsigned int wire, ndead = 0;
6078 unsigned int iht = fcl2hits[fcl2hits.size() - 1];
6079 unsigned int eWire = fHits[iht].WireID().Wire;
6081 unsigned int bWire = fHits[iht].WireID().Wire + 1;
6082 for (wire = eWire; wire < bWire; ++wire)
6083 if (WireHitRange[wire].first == -1) ++ndead;
6088 bool ClusterCrawlerAlg::areInSameMultiplet(
recob::Hit const& first_hit,
6096 std::pair<size_t, size_t> ClusterCrawlerAlg::FindHitMultiplet(
size_t iHit)
const 6098 std::pair<size_t, size_t> range{iHit, iHit};
6100 range.first = iHit - fHits[iHit].LocalIndex();
6101 range.second = range.first + fHits[iHit].Multiplicity();
6107 bool ClusterCrawlerAlg::CheckHitDuplicates(std::string location,
6108 std::string marker )
const 6111 unsigned int nDuplicates = 0;
6112 std::set<unsigned int>
hits;
6113 for (
unsigned int hit : fcl2hits) {
6114 if (hits.count(
hit)) {
6117 log <<
"Hit #" <<
hit 6118 <<
" being included twice in the future cluster (ID=" << (tcl.size() + 1)
6119 <<
"?) at location: " << location;
6120 if (!marker.empty()) log <<
" (marker: '" << marker <<
"')";
6124 return nDuplicates > 0;
6128 float ClusterCrawlerAlg::DoCA(
short icl,
unsigned short end,
float vwire,
float vtick)
6133 if (icl > (
short)tcl.size())
return 9999;
6135 float cwire, cslp, ctick;
6138 if (fcl2hits.size() == 0)
return 9999;
6154 cwire = tcl[icl].BeginWir;
6155 cslp = tcl[icl].BeginSlp;
6156 ctick = tcl[icl].BeginTim;
6159 cwire = tcl[icl].EndWir;
6160 cslp = tcl[icl].EndSlp;
6161 ctick = tcl[icl].EndTim;
6166 float docaW = (vwire + cslp * (vtick - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6167 float dW = docaW - vwire;
6168 float dT = ctick + (vwire - cwire) * cslp - vtick;
6169 return sqrt(dW * dW + dT * dT);
6174 float ClusterCrawlerAlg::ClusterVertexChi(
short icl,
unsigned short end,
unsigned short ivx)
6178 if (icl > (
short)tcl.size())
return 9999;
6179 if (ivx > vtx.size())
return 9999;
6181 float cwire, cslp, cslpErr, ctick;
6184 if (fcl2hits.size() == 0)
return 9999;
6189 cslpErr = clBeginSlpErr;
6195 cslpErr = clparerr[1];
6202 cwire = tcl[icl].BeginWir;
6203 cslp = tcl[icl].BeginSlp;
6204 cslpErr = tcl[icl].BeginSlpErr;
6205 ctick = tcl[icl].BeginTim;
6208 cwire = tcl[icl].EndWir;
6209 cslp = tcl[icl].EndSlp;
6210 cslpErr = tcl[icl].EndSlpErr;
6211 ctick = tcl[icl].EndTim;
6217 (vtx[ivx].Wire + cslp * (vtx[ivx].Time - ctick) + cwire * cslp * cslp) / (1 + cslp * cslp);
6218 float dW = docaW - vtx[ivx].Wire;
6219 float chi = dW / vtx[ivx].WireErr;
6220 float totChi = chi * chi;
6221 dW = vtx[ivx].Wire - cwire;
6222 float dT = ctick + dW * cslp - vtx[ivx].Time;
6223 if (cslpErr < 1
E-3) cslpErr = 1
E-3;
6225 cslpErr *= AngleFactor(cslp);
6227 float dTErr = dW * cslpErr;
6231 dTErr += vtx[ivx].TimeErr * vtx[ivx].TimeErr;
6232 if (dTErr < 1
E-3) dTErr = 1
E-3;
6233 totChi += dT * dT / dTErr;
6241 float ClusterCrawlerAlg::PointVertexChi(
float wire,
float tick,
unsigned short ivx)
6245 if (ivx > vtx.size())
return 9999;
6247 float dW = wire - vtx[ivx].Wire;
6248 float chi = dW / vtx[ivx].WireErr;
6249 float totChi = chi * chi;
6250 float dT = tick - vtx[ivx].Time;
6251 chi = dT / vtx[ivx].TimeErr;
6252 totChi += chi * chi;
6262 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 .
WireID suggestedWireID() const
Returns a better wire ID.
struct of temporary 2D vertices (end points)
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].
double Efield(unsigned int planegap=0) const
kV/cm
int TDCtick_t
Type representing a TDC tick.
span(IterB &&b, IterE &&e, Adaptor &&adaptor) -> span< std::invoke_result_t< Adaptor, IterB >, std::invoke_result_t< Adaptor, IterE >>
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 the physical 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
float HitSummedADC() const
The sum of calibrated ADC counts of the hit (0. by default)
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
float ROISummedADC() const
The sum of calibrated ADC counts of the ROI (0. by default)
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)
Exception thrown on invalid wire number.
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.
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 .