17 #include "art/Framework/Services/Registry/ServiceHandle.h"
25 #include "TDecompSVD.h"
39 namespace lar_cluster3d {
46 , m_hiThresholdFrac(.05)
47 , m_loThresholdFrac(0.85)
50 , m_numSkippedHits(10)
51 , m_maxLoopsPerCluster(3)
53 , m_pcaAlg(pset.
get<fhicl::ParameterSet>(
"PrincipalComponentsAlg"))
54 , m_displayHist(
false)
58 m_rhoBins = pset.get<
int>(
"HalfRhoBins", 75);
68 m_geometry = art::ServiceHandle<geo::Geometry const>{}.get();
84 const reco::HitPairListPtr::const_iterator& itr)
88 const Eigen::Vector3f&
93 reco::HitPairListPtr::const_iterator
102 reco::HitPairListPtr::const_iterator
185 size_t peakCountLeft(0);
186 size_t peakCountRight(0);
188 for (
const auto& binIndex : left)
189 peakCountLeft = std::max(peakCountLeft,
m_accMap[binIndex].getAccumulatorValues().
size());
190 for (
const auto& binIndex : right)
191 peakCountRight = std::max(peakCountRight,
m_accMap[binIndex].getAccumulatorValues().
size());
193 return peakCountLeft > peakCountRight;
206 const HoughSeedFinderAlg::RhoThetaAccumulatorBinMap::iterator&
right)
208 size_t leftSize = left->second.getAccumulatorValues().size();
209 size_t rightSize = right->second.getAccumulatorValues().size();
211 return leftSize > rightSize;
219 size_t threshold)
const
226 for (
int rhoIdx = curBin.first - 1; rhoIdx <= curBin.first + 1; rhoIdx++) {
227 for (
int jdx = curBin.second - 1; jdx <= curBin.second + 1; jdx++) {
229 if (rhoIdx == curBin.first && jdx == curBin.second)
continue;
239 BinIndex binIndex(rhoIdx, thetaIdx);
240 RhoThetaAccumulatorBinMap::iterator mapItr = rhoThetaAccumulatorBinMap.find(binIndex);
242 if (mapItr != rhoThetaAccumulatorBinMap.end()) {
243 if (mapItr->second.getAccumulatorValues().size() >= threshold)
244 neighborPts.push_back(binIndex);
257 size_t threshold)
const
264 houghCluster.push_back(curBin);
266 for (
auto& binIndex : neighborPts) {
274 HoughRegionQuery(binIndex, rhoThetaAccumulatorBinMap, nextNeighborPts, threshold);
276 if (!nextNeighborPts.empty()) {
277 for (
auto& neighborIdx : nextNeighborPts) {
278 neighborPts.push_back(neighborIdx);
284 houghCluster.push_back(binIndex);
295 return *left < *
right;
313 int planeToCheck = (
m_plane + 1) % 3;
315 return left->
getHits()[planeToCheck]->WireID().Wire <
316 right->
getHits()[planeToCheck]->WireID().Wire;
327 return left.second < right.second;
347 outputList = inputHitList;
359 std::map<size_t, reco::HitPairListPtr> gapHitListMap;
362 double arcLenLastHit = inputHitList.front()->getArclenToPoca();
365 for (
const auto& hit3D : inputHitList) {
367 double arcLen = hit3D->getArclenToPoca();
368 double deltaArcLen = arcLen - arcLenLastHit;
371 gapHitListMap[continuousHitList.size()] = continuousHitList;
372 continuousHitList.clear();
375 continuousHitList.emplace_back(hit3D);
377 arcLenLastHit = arcLen;
380 if (!continuousHitList.empty()) gapHitListMap[continuousHitList.size()] = continuousHitList;
383 std::map<size_t, reco::HitPairListPtr>::reverse_iterator longestListItr =
384 gapHitListMap.rbegin();
386 if (longestListItr != gapHitListMap.rend()) {
387 size_t nContinuousHits = longestListItr->first;
390 outputList.resize(nContinuousHits);
391 std::copy(longestList.begin(), longestList.end(), outputList.begin());
413 static int histCount(0);
414 const double maxTheta(M_PI);
415 const double thetaBinSize(maxTheta /
double(
m_thetaBins));
419 Eigen::Vector3f pcaCenter(
426 double maxRho = std::sqrt(eigenVal0 * eigenVal0 + eigenVal1 * eigenVal1) * 2. / 3.;
427 double rhoBinSize = maxRho / double(
m_rhoBins);
429 if (rhoBinSize < rhoBinSizeMin) rhoBinSize = rhoBinSizeMin;
435 size_t maxBinCount(0);
436 int nAccepted3DHits(0);
439 for (reco::HitPairListPtr::const_iterator hit3DItr = hitPairListPtr.begin();
440 hit3DItr != hitPairListPtr.end();
450 Eigen::Vector3f hit3DPosition(
452 Eigen::Vector3f pcaToHitVec = hit3DPosition - pcaCenter;
453 Eigen::Vector3f pcaToHitPlaneVec(pcaToHitVec.dot(planeVec0), pcaToHitVec.dot(planeVec1), 0.);
454 double xPcaToHit = pcaToHitPlaneVec[0];
455 double yPcaToHit = pcaToHitPlaneVec[1];
462 for (
int thetaIdx = 0; thetaIdx <
m_thetaBins; thetaIdx++) {
464 double theta = thetaBinSize * double(thetaIdx);
467 double rho = xPcaToHit * std::cos(theta) + yPcaToHit * std::sin(theta);
470 int rhoIdx = std::round(rho / rhoBinSize);
473 BinIndex binIndex(rhoIdx, thetaIdx);
475 rhoThetaAccumulatorBinMap[binIndex].addAccumulatorValue(accValue);
477 if (rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues().
size() > maxBinCount)
478 maxBinCount = rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues().size();
484 std::ostringstream ostr;
485 ostr <<
"Hough Histogram " << histCount++;
486 m_Canvases.emplace_back(
new TCanvas(ostr.str().c_str(), ostr.str().c_str(), 1000, 1000));
488 std::ostringstream ostr2;
491 m_Canvases.back()->GetFrame()->SetFillColor(46);
500 TPad*
p =
new TPad(ostr2.str().c_str(), ostr2.str().c_str(), zmin,
xmin, zmax, xmax);
501 p->SetBit(kCanDelete);
502 p->Range(zmin, xmin, zmax, xmax);
503 p->SetFillStyle(4000);
507 TH2D* houghHist =
new TH2D(
"HoughHist",
516 for (
const auto& rhoThetaMap : rhoThetaAccumulatorBinMap) {
517 houghHist->Fill(rhoThetaMap.first.first,
518 rhoThetaMap.first.second + 0.5,
519 rhoThetaMap.second.getAccumulatorValues().size());
522 houghHist->SetBit(kCanDelete);
534 std::list<RhoThetaAccumulatorBinMap::iterator> binIndexList;
536 for (RhoThetaAccumulatorBinMap::iterator mapItr = rhoThetaAccumulatorBinMap.begin();
537 mapItr != rhoThetaAccumulatorBinMap.end();
539 binIndexList.push_back(mapItr);
543 for (
auto& mapItr : binIndexList) {
546 if (mapItr->second.isInCluster())
continue;
553 if (mapItr->second.getAccumulatorValues().size() < thresholdLo) {
554 mapItr->second.setNoise();
559 thresholdHi = std::max(
566 HoughRegionQuery(curBin, rhoThetaAccumulatorBinMap, neighborhood, thresholdHi);
573 curBin, neighborhood, houghCluster, rhoThetaAccumulatorBinMap, thresholdHi);
577 if (!houghClusters.empty()) houghClusters.sort(
SortHoughClusterList(rhoThetaAccumulatorBinMap));
592 if (!seedFullPca.
getSvdOK())
return false;
604 std::set<const reco::ClusterHit2D*> seedHitSet;
610 for (reco::HitPairListPtr::iterator peakBinItr = seed3DHits.begin();
611 peakBinItr != seed3DHits.end();
618 seedHit3DList.clear();
622 seedHit3DList.push_back(hit3D);
625 seedHitSet.insert(
hit);
643 if (!seedPca.
getSvdOK())
return false;
650 double seedCenter[3] = {
656 double arcLen = seedHit3DList.front()->getArclenToPoca();
657 double seedStart[3] = {seedCenter[0] + arcLen * seedDir[0],
658 seedCenter[1] + arcLen * seedDir[1],
659 seedCenter[2] + arcLen * seedDir[2]};
665 if (seedHitSet.size() >= 10) {
670 LineFit2DHits(seedHitSet, seedStart[0], newSeedPos, newSeedDir, chiDOF);
675 seedDir[0] * newSeedDir[0] + seedDir[1] * newSeedDir[1] + seedDir[2] * newSeedDir[2];
677 if (cosAng < 0.) newSeedDir *= -1.;
679 seedStart[0] = newSeedPos[0];
680 seedStart[1] = newSeedPos[1];
681 seedStart[2] = newSeedPos[2];
682 seedDir[0] = newSeedDir[0];
683 seedDir[1] = newSeedDir[1];
684 seedDir[2] = newSeedDir[2];
692 if (seed3DHits.size() > 100) {
699 size_t numToKeep = seed3DHits.size() - 10;
701 reco::HitPairListPtr::iterator endItr = seed3DHits.begin();
703 std::advance(endItr, numToKeep);
705 seed3DHits.erase(endItr, seed3DHits.end());
723 typedef std::map<size_t, SeedHitPairListPairVec> SizeToSeedToHitMap;
725 SizeToSeedToHitMap seedHitPairMap;
737 while (!hitPairListPtr.empty()) {
742 if (eigenVal0 > 5. && eigenVal1 > 0.001) {
749 findHoughClusters(hitPairListPtr, pca, nLoops, rhoThetaAccumulatorBinMap, houghClusters);
752 if (houghClusters.empty())
break;
760 std::set<const reco::ClusterHit3D*> masterHitPtrList;
761 std::set<const reco::ClusterHit3D*> peakBinPtrList;
763 size_t firstPeakCount(0);
766 for (
auto& houghCluster : houghClusters) {
767 BinIndex peakBin = houghCluster.front();
768 size_t peakCount = 0;
769 size_t totalHits = 0;
772 std::set<const reco::ClusterHit3D*> localHitPtrList;
775 for (
auto& binIndex : houghCluster) {
777 std::set<const reco::ClusterHit3D*> tempHitPtrList;
780 for (
auto& hitItr : rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues()) {
781 reco::HitPairListPtr::const_iterator hit3DItr = hitItr.getHitIterator();
783 tempHitPtrList.insert(*hit3DItr);
787 totalHits += tempHitPtrList.size();
790 std::set<const reco::ClusterHit3D*> tempHit3DSet;
792 std::set_difference(tempHitPtrList.begin(),
793 tempHitPtrList.end(),
794 masterHitPtrList.begin(),
795 masterHitPtrList.end(),
796 std::inserter(tempHit3DSet, tempHit3DSet.end()));
798 tempHitPtrList = tempHit3DSet;
800 size_t binCount = tempHitPtrList.size();
802 if (peakCount < binCount) {
803 peakCount = binCount;
805 peakBinPtrList = tempHitPtrList;
809 localHitPtrList.insert(tempHitPtrList.begin(), tempHitPtrList.end());
814 if (!firstPeakCount) firstPeakCount = peakCount;
817 if (peakCount < firstPeakCount / 10)
continue;
825 for (
const auto& hit3D : localHitPtrList)
826 allPeakBinHits.push_back(hit3D);
836 if (
buildSeed(peakBinHits, seedHitPair)) {
838 seedHitPairMap[peakBinHits.size()].push_back(seedHitPair);
841 if (seedHitPairMap.size() == 1) {
842 for (
const auto& hit3D : peakBinHits)
843 hit3D->setStatusBit(0x40000000);
854 masterHitPtrList.insert(peakBinHits.begin(), peakBinHits.end());
856 if (hitPairListPtr.size() - masterHitPtrList.size() <
m_minimum3DHits)
break;
860 if (masterHitPtrList.empty())
break;
866 hitPairListPtr.sort();
868 reco::HitPairListPtr::iterator newListEnd = std::set_difference(hitPairListPtr.begin(),
869 hitPairListPtr.end(),
870 masterHitPtrList.begin(),
871 masterHitPtrList.end(),
872 hitPairListPtr.begin());
874 hitPairListPtr.erase(newListEnd, hitPairListPtr.end());
895 for (SizeToSeedToHitMap::reverse_iterator seedMapItr = seedHitPairMap.rbegin();
896 seedMapItr != seedHitPairMap.rend();
898 for (
const auto& seedHitPair : seedMapItr->second) {
899 seedHitPairVec.emplace_back(seedHitPair);
926 if (eigenVal0 > 5. && eigenVal1 > 0.001) {
933 findHoughClusters(hitPairListPtr, pca, nLoops, rhoThetaAccumulatorBinMap, houghClusters);
941 std::set<const reco::ClusterHit3D*> masterHitPtrList;
942 std::set<const reco::ClusterHit3D*> peakBinPtrList;
944 size_t firstPeakCount(0);
947 for (
auto& houghCluster : houghClusters) {
948 BinIndex peakBin = houghCluster.front();
949 size_t peakCount = 0;
950 size_t totalHits = 0;
953 std::set<const reco::ClusterHit3D*> localHitPtrList;
956 for (
auto& binIndex : houghCluster) {
958 std::set<const reco::ClusterHit3D*> tempHitPtrList;
961 for (
auto& hitItr : rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues()) {
962 reco::HitPairListPtr::const_iterator hit3DItr = hitItr.getHitIterator();
964 tempHitPtrList.insert(*hit3DItr);
968 totalHits += tempHitPtrList.size();
971 std::set<const reco::ClusterHit3D*> tempHit3DSet;
973 std::set_difference(tempHitPtrList.begin(),
974 tempHitPtrList.end(),
975 masterHitPtrList.begin(),
976 masterHitPtrList.end(),
977 std::inserter(tempHit3DSet, tempHit3DSet.end()));
979 tempHitPtrList = tempHit3DSet;
981 size_t binCount = tempHitPtrList.size();
983 if (peakCount < binCount) {
984 peakCount = binCount;
986 peakBinPtrList = tempHitPtrList;
990 localHitPtrList.insert(tempHitPtrList.begin(), tempHitPtrList.end());
995 if (!firstPeakCount) firstPeakCount = peakCount;
998 if (peakCount < firstPeakCount / 10)
continue;
1006 hitPairListPtrList.back().resize(localHitPtrList.size());
1008 localHitPtrList.begin(), localHitPtrList.end(), hitPairListPtrList.back().begin());
1011 masterHitPtrList.insert(localHitPtrList.begin(), localHitPtrList.end());
1013 if (hitPairListPtr.size() - masterHitPtrList.size() <
m_minimum3DHits)
break;
1026 double& ChiDOF)
const
1048 if (hit2DSet.size() < 4)
return;
1050 const unsigned int nvars = 4;
1051 unsigned int npts = hit2DSet.size();
1053 TMatrixD
A(npts, nvars);
1056 unsigned short ninpl[3] = {0};
1057 unsigned short nok = 0;
1058 unsigned short iht(0), cstat, tpc, ipl;
1059 double x, cw, sw, off;
1062 for (
const auto&
hit : hit2DSet) {
1078 x =
hit->getXPosition() - XOrigin;
1084 w[iht] = wireID.
Wire - off;
1089 if (ninpl[ipl] == 2) ++nok;
1095 if (nok < 2)
return;
1099 TVectorD tVec = svd.Solve(w, ok);
1104 if (npts <= 4)
return;
1106 double ypr, zpr, diff;
1108 for (
const auto&
hit : hit2DSet) {
1117 x =
hit->getXPosition() - XOrigin;
1118 ypr = tVec[0] + tVec[2] *
x;
1119 zpr = tVec[1] + tVec[3] *
x;
1120 diff = ypr * cw + zpr * sw - (wireID.
Wire - off);
1121 ChiDOF += diff * diff;
1126 ChiDOF /= (float)(npts - 4);
1128 double norm = sqrt(1 + tVec[2] * tVec[2] + tVec[3] * tVec[3]);
1130 Dir[1] = tVec[2] /
norm;
1131 Dir[2] = tVec[3] /
norm;
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
void LineFit2DHits(std::set< const reco::ClusterHit2D * > &hitList, double XOrigin, TVector3 &Pos, TVector3 &Dir, double &ChiDOF) const
Define a comparator which will sort hits by arc length along a PCA axis.
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
void findHitGaps(reco::HitPairListPtr &inputHitList, reco::HitPairListPtr &outputList) const
Using Principal Components Axis, look for gaps in a list of 3D hits.
geo::Geometry const * m_geometry
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
std::vector< TVirtualPad * > m_Pads
View pads in current canvas.
process_name opflash particleana ie x
const Eigen::Vector3f getPosition() const
std::vector< AccumulatorValues > AccumulatorValuesVec
CryostatID_t Cryostat
Index of cryostat.
std::size_t size(FixedBins< T, C > const &) noexcept
HoughSeedFinderAlg(fhicl::ParameterSet const &pset)
Constructor.
WireID_t Wire
Index of the wire within its plane.
std::list< HitPairListPtr > HitPairListPtrList
bool operator()(const reco::ClusterHit3D *left, const reco::ClusterHit3D *right) const
void findHoughClusters(const reco::HitPairListPtr &inputHits, reco::PrincipalComponents &pca, int &nLoops, RhoThetaAccumulatorBinMap &rhoThetaMap, HoughClusterList &clusterList) const
unsigned int getStatusBits() const
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
float getDocaToAxis() const
process_name pandoraGausCryo1 vertexChargeCryo1 vertexStubCryo1 xmin
Define a comparator which will sort hits by the absolute value of arc length so hits are ordered clos...
OrderHitsAlongWire(int plane=0)
void expandHoughCluster(BinIndex &curBin, HoughCluster &neighborPts, HoughCluster &houghCluster, RhoThetaAccumulatorBinMap &rhoThetaAccumulatorBinMap, size_t threshold) const
HoughSeedFinderAlg::RhoThetaAccumulatorBinMap & m_accMap
void addAccumulatorValue(AccumulatorValues &value)
const EigenValues & getEigenValues() const
This is an algorithm for finding recob::Seed objects in 3D clusters.
void HoughRegionQuery(BinIndex &curBin, RhoThetaAccumulatorBinMap &rhoThetaAccumulatorBinMap, HoughCluster &neighborPts, size_t threshold) const
const Eigen::Vector3f & getAvePosition() const
const AccumulatorValuesVec & getAccumulatorValues() const
std::list< HoughCluster > HoughClusterList
std::list< const reco::ClusterHit3D * > HitPairListPtr
bool operator()(const HoughSeedFinderAlg::HoughCluster &left, const HoughSeedFinderAlg::HoughCluster &right)
PrincipalComponentsAlg m_pcaAlg
bool operator()(const reco::ClusterHit3D *left, const reco::ClusterHit3D *right)
PlaneID_t Plane
Index of the plane within its TPC.
bool buildSeed(reco::HitPairListPtr &seed3DHits, SeedHitPairListPair &seedHitPair) const
Given a list of candidate "seed" 3D hits, build the seed and get associated unique 2D hits...
bool operator()(const HoughSeedFinderAlg::RhoThetaAccumulatorBinMap::iterator &left, const HoughSeedFinderAlg::RhoThetaAccumulatorBinMap::iterator &right)
This is used to sort bins in Hough Space.
std::map< BinIndex, AccumulatorBin > RhoThetaAccumulatorBinMap
auto norm(Vector const &v)
Return norm of the specified vector.
reco::HitPairListPtr::const_iterator m_hit3DIterator
This will be used to take us back to our 3D hit.
bool findTrackHits(reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, reco::HitPairListPtrList &hitPairListPtrList) const
Given the list of hits this will return the sets of hits which belong on the same line...
const Eigen::Vector3f & getPosition() const
bool operator()(const std::pair< size_t, size_t > &left, const std::pair< size_t, size_t > &right)
const float getAveHitDoca() const
AccumulatorValuesVec m_accumulatorValuesVec
std::list< BinIndex > HoughCluster
std::vector< SeedHitPairListPair > SeedHitPairListPairVec
Eigen::Vector3f m_position
We really only need the x,y coordinates here but keep all three for now.
std::pair< recob::Seed, reco::HitPairListPtr > SeedHitPairListPair
SortHoughClusterList(HoughSeedFinderAlg::RhoThetaAccumulatorBinMap &accMap)
This is used to sort "Hough Clusters" by the maximum entries in a bin.
AccumulatorBin(AccumulatorValues &values)
std::pair< int, int > BinIndex
TPCID_t TPC
Index of the TPC within its cryostat.
AccumulatorValues()
A utility class to contain the values of a given "bin" in Hough Space.
AccumulatorBin()
A utility class used to accumulate the above values.
std::vector< std::unique_ptr< TCanvas > > m_Canvases
Graphical trace canvases.
const ClusterHit2DVec & getHits() const
AccumulatorValues(const Eigen::Vector3f &position, const reco::HitPairListPtr::const_iterator &itr)
bool Hit3DCompare(const reco::ClusterHit3D *left, const reco::ClusterHit3D *right)
reco::HitPairListPtr::const_iterator getHitIterator() const
art framework interface to geometry description
const EigenVectors & getEigenVectors() const
bool findTrackSeeds(reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, SeedHitPairListPairVec &seedHitPairVec) const override
Given the list of hits this will search for candidate Seed objects and return them.