25 #include "TDecompSVD.h" 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)
85 : m_position(position), m_hit3DIterator(itr)
88 const Eigen::Vector3f&
getPosition()
const {
return m_position; }
111 m_accumulatorValuesVec.push_back(values);
144 size_t peakCountLeft(0);
145 size_t peakCountRight(0);
147 for (
const auto& binIndex : left)
148 peakCountLeft = std::max(peakCountLeft, m_accMap[binIndex].getAccumulatorValues().
size());
149 for (
const auto& binIndex : right)
150 peakCountRight = std::max(peakCountRight, m_accMap[binIndex].getAccumulatorValues().
size());
152 return peakCountLeft > peakCountRight;
166 size_t leftSize = left->second.getAccumulatorValues().size();
167 size_t rightSize = right->second.getAccumulatorValues().size();
169 return leftSize > rightSize;
176 size_t threshold)
const 183 for (
int rhoIdx = curBin.first - 1; rhoIdx <= curBin.first + 1; rhoIdx++) {
184 for (
int jdx = curBin.second - 1; jdx <= curBin.second + 1; jdx++) {
186 if (rhoIdx == curBin.first && jdx == curBin.second)
continue;
196 BinIndex binIndex(rhoIdx, thetaIdx);
199 if (mapItr != rhoThetaAccumulatorBinMap.end()) {
200 if (mapItr->second.getAccumulatorValues().size() >= threshold)
201 neighborPts.push_back(binIndex);
213 size_t threshold)
const 220 houghCluster.push_back(curBin);
222 for (
auto& binIndex : neighborPts) {
230 HoughRegionQuery(binIndex, rhoThetaAccumulatorBinMap, nextNeighborPts, threshold);
232 if (!nextNeighborPts.empty()) {
233 for (
auto& neighborIdx : nextNeighborPts) {
234 neighborPts.push_back(neighborIdx);
240 houghCluster.push_back(binIndex);
250 return *left < *
right;
266 int planeToCheck = (m_plane + 1) % 3;
268 return left->
getHits()[planeToCheck]->WireID().Wire <
269 right->
getHits()[planeToCheck]->WireID().Wire;
279 return left.second < right.second;
298 outputList = inputHitList;
310 std::map<size_t, reco::HitPairListPtr> gapHitListMap;
313 double arcLenLastHit = inputHitList.front()->getArclenToPoca();
316 for (
const auto& hit3D : inputHitList) {
318 double arcLen = hit3D->getArclenToPoca();
319 double deltaArcLen = arcLen - arcLenLastHit;
322 gapHitListMap[continuousHitList.size()] = continuousHitList;
323 continuousHitList.clear();
326 continuousHitList.emplace_back(hit3D);
328 arcLenLastHit = arcLen;
331 if (!continuousHitList.empty()) gapHitListMap[continuousHitList.size()] = continuousHitList;
334 std::map<size_t, reco::HitPairListPtr>::reverse_iterator longestListItr =
335 gapHitListMap.rbegin();
337 if (longestListItr != gapHitListMap.rend()) {
338 size_t nContinuousHits = longestListItr->first;
341 outputList.resize(nContinuousHits);
342 std::copy(longestList.begin(), longestList.end(), outputList.begin());
362 static int histCount(0);
363 const double maxTheta(M_PI);
364 const double thetaBinSize(maxTheta /
double(
m_thetaBins));
368 Eigen::Vector3f pcaCenter(
375 double maxRho = std::sqrt(eigenVal0 * eigenVal0 + eigenVal1 * eigenVal1) * 2. / 3.;
376 double rhoBinSize = maxRho / double(
m_rhoBins);
378 if (rhoBinSize < rhoBinSizeMin) rhoBinSize = rhoBinSizeMin;
384 size_t maxBinCount(0);
385 int nAccepted3DHits(0);
389 hit3DItr != hitPairListPtr.end();
399 Eigen::Vector3f hit3DPosition(
401 Eigen::Vector3f pcaToHitVec = hit3DPosition - pcaCenter;
402 Eigen::Vector3f pcaToHitPlaneVec(pcaToHitVec.dot(planeVec0), pcaToHitVec.dot(planeVec1), 0.);
403 double xPcaToHit = pcaToHitPlaneVec[0];
404 double yPcaToHit = pcaToHitPlaneVec[1];
411 for (
int thetaIdx = 0; thetaIdx <
m_thetaBins; thetaIdx++) {
413 double theta = thetaBinSize * double(thetaIdx);
416 double rho = xPcaToHit * std::cos(theta) + yPcaToHit * std::sin(theta);
419 int rhoIdx = std::round(rho / rhoBinSize);
422 BinIndex binIndex(rhoIdx, thetaIdx);
424 rhoThetaAccumulatorBinMap[binIndex].addAccumulatorValue(accValue);
426 if (rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues().
size() > maxBinCount)
427 maxBinCount = rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues().size();
433 std::ostringstream ostr;
434 ostr <<
"Hough Histogram " << histCount++;
435 m_Canvases.emplace_back(
new TCanvas(ostr.str().c_str(), ostr.str().c_str(), 1000, 1000));
437 std::ostringstream ostr2;
440 m_Canvases.back()->GetFrame()->SetFillColor(46);
449 TPad* p =
new TPad(ostr2.str().c_str(), ostr2.str().c_str(), zmin, xmin, zmax, xmax);
450 p->SetBit(kCanDelete);
451 p->Range(zmin, xmin, zmax, xmax);
452 p->SetFillStyle(4000);
456 TH2D* houghHist =
new TH2D(
"HoughHist",
465 for (
const auto& rhoThetaMap : rhoThetaAccumulatorBinMap) {
466 houghHist->Fill(rhoThetaMap.first.first,
467 rhoThetaMap.first.second + 0.5,
468 rhoThetaMap.second.getAccumulatorValues().size());
471 houghHist->SetBit(kCanDelete);
483 std::list<RhoThetaAccumulatorBinMap::iterator> binIndexList;
486 mapItr != rhoThetaAccumulatorBinMap.end();
488 binIndexList.push_back(mapItr);
492 for (
auto& mapItr : binIndexList) {
495 if (mapItr->second.isInCluster())
continue;
502 if (mapItr->second.getAccumulatorValues().size() < thresholdLo) {
503 mapItr->second.setNoise();
508 thresholdHi = std::max(
515 HoughRegionQuery(curBin, rhoThetaAccumulatorBinMap, neighborhood, thresholdHi);
522 curBin, neighborhood, houghCluster, rhoThetaAccumulatorBinMap, thresholdHi);
526 if (!houghClusters.empty()) houghClusters.sort(
SortHoughClusterList(rhoThetaAccumulatorBinMap));
540 if (!seedFullPca.
getSvdOK())
return false;
552 std::set<const reco::ClusterHit2D*> seedHitSet;
559 peakBinItr != seed3DHits.end();
566 seedHit3DList.clear();
570 seedHit3DList.push_back(hit3D);
573 seedHitSet.insert(
hit);
591 if (!seedPca.
getSvdOK())
return false;
598 double seedCenter[3] = {
604 double arcLen = seedHit3DList.front()->getArclenToPoca();
605 double seedStart[3] = {seedCenter[0] + arcLen * seedDir[0],
606 seedCenter[1] + arcLen * seedDir[1],
607 seedCenter[2] + arcLen * seedDir[2]};
613 if (seedHitSet.size() >= 10) {
618 LineFit2DHits(seedHitSet, seedStart[0], newSeedPos, newSeedDir, chiDOF);
623 seedDir[0] * newSeedDir[0] + seedDir[1] * newSeedDir[1] + seedDir[2] * newSeedDir[2];
625 if (cosAng < 0.) newSeedDir *= -1.;
627 seedStart[0] = newSeedPos[0];
628 seedStart[1] = newSeedPos[1];
629 seedStart[2] = newSeedPos[2];
630 seedDir[0] = newSeedDir[0];
631 seedDir[1] = newSeedDir[1];
632 seedDir[2] = newSeedDir[2];
640 if (seed3DHits.size() > 100) {
647 size_t numToKeep = seed3DHits.size() - 10;
651 std::advance(endItr, numToKeep);
653 seed3DHits.erase(endItr, seed3DHits.end());
670 typedef std::map<size_t, SeedHitPairListPairVec> SizeToSeedToHitMap;
672 SizeToSeedToHitMap seedHitPairMap;
684 while (!hitPairListPtr.empty()) {
689 if (eigenVal0 > 5. && eigenVal1 > 0.001) {
696 findHoughClusters(hitPairListPtr, pca, rhoThetaAccumulatorBinMap, houghClusters);
699 if (houghClusters.empty())
break;
707 std::set<const reco::ClusterHit3D*> masterHitPtrList;
708 std::set<const reco::ClusterHit3D*> peakBinPtrList;
710 size_t firstPeakCount(0);
713 for (
auto& houghCluster : houghClusters) {
714 BinIndex peakBin = houghCluster.front();
715 size_t peakCount = 0;
718 std::set<const reco::ClusterHit3D*> localHitPtrList;
721 for (
auto& binIndex : houghCluster) {
723 std::set<const reco::ClusterHit3D*> tempHitPtrList;
726 for (
auto& hitItr : rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues()) {
729 tempHitPtrList.insert(*hit3DItr);
733 std::set<const reco::ClusterHit3D*> tempHit3DSet;
735 std::set_difference(tempHitPtrList.begin(),
736 tempHitPtrList.end(),
737 masterHitPtrList.begin(),
738 masterHitPtrList.end(),
739 std::inserter(tempHit3DSet, tempHit3DSet.end()));
741 tempHitPtrList = tempHit3DSet;
743 size_t binCount = tempHitPtrList.size();
745 if (peakCount < binCount) {
746 peakCount = binCount;
748 peakBinPtrList = tempHitPtrList;
752 localHitPtrList.insert(tempHitPtrList.begin(), tempHitPtrList.end());
757 if (!firstPeakCount) firstPeakCount = peakCount;
760 if (peakCount < firstPeakCount / 10)
continue;
768 for (
const auto& hit3D : localHitPtrList)
769 allPeakBinHits.push_back(hit3D);
779 if (
buildSeed(peakBinHits, seedHitPair)) {
781 seedHitPairMap[peakBinHits.size()].push_back(seedHitPair);
784 if (seedHitPairMap.size() == 1) {
785 for (
const auto& hit3D : peakBinHits)
786 hit3D->setStatusBit(0x40000000);
797 masterHitPtrList.insert(peakBinHits.begin(), peakBinHits.end());
799 if (hitPairListPtr.size() - masterHitPtrList.size() <
m_minimum3DHits)
break;
803 if (masterHitPtrList.empty())
break;
809 hitPairListPtr.sort();
812 hitPairListPtr.end(),
813 masterHitPtrList.begin(),
814 masterHitPtrList.end(),
815 hitPairListPtr.begin());
817 hitPairListPtr.erase(newListEnd, hitPairListPtr.end());
838 for (SizeToSeedToHitMap::reverse_iterator seedMapItr = seedHitPairMap.rbegin();
839 seedMapItr != seedHitPairMap.rend();
841 for (
const auto& seedHitPair : seedMapItr->second) {
842 seedHitPairVec.emplace_back(seedHitPair);
866 if (eigenVal0 > 5. && eigenVal1 > 0.001) {
873 findHoughClusters(hitPairListPtr, pca, rhoThetaAccumulatorBinMap, houghClusters);
881 std::set<const reco::ClusterHit3D*> masterHitPtrList;
882 std::set<const reco::ClusterHit3D*> peakBinPtrList;
884 size_t firstPeakCount(0);
887 for (
auto& houghCluster : houghClusters) {
888 BinIndex peakBin = houghCluster.front();
889 size_t peakCount = 0;
892 std::set<const reco::ClusterHit3D*> localHitPtrList;
895 for (
auto& binIndex : houghCluster) {
897 std::set<const reco::ClusterHit3D*> tempHitPtrList;
900 for (
auto& hitItr : rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues()) {
903 tempHitPtrList.insert(*hit3DItr);
907 std::set<const reco::ClusterHit3D*> tempHit3DSet;
909 std::set_difference(tempHitPtrList.begin(),
910 tempHitPtrList.end(),
911 masterHitPtrList.begin(),
912 masterHitPtrList.end(),
913 std::inserter(tempHit3DSet, tempHit3DSet.end()));
915 tempHitPtrList = tempHit3DSet;
917 size_t binCount = tempHitPtrList.size();
919 if (peakCount < binCount) {
920 peakCount = binCount;
922 peakBinPtrList = tempHitPtrList;
926 localHitPtrList.insert(tempHitPtrList.begin(), tempHitPtrList.end());
931 if (!firstPeakCount) firstPeakCount = peakCount;
934 if (peakCount < firstPeakCount / 10)
continue;
942 hitPairListPtrList.back().resize(localHitPtrList.size());
944 localHitPtrList.begin(), localHitPtrList.end(), hitPairListPtrList.back().begin());
947 masterHitPtrList.insert(localHitPtrList.begin(), localHitPtrList.end());
949 if (hitPairListPtr.size() - masterHitPtrList.size() <
m_minimum3DHits)
break;
961 double& ChiDOF)
const 983 if (hit2DSet.size() < 4)
return;
985 const unsigned int nvars = 4;
986 unsigned int npts = hit2DSet.size();
988 TMatrixD A(npts, nvars);
991 unsigned short ninpl[3] = {0};
992 unsigned short nok = 0;
993 unsigned short iht(0);
996 for (
const auto&
hit : hit2DSet) {
998 unsigned int const ipl = wireID.
Plane;
1009 double const x =
hit->getXPosition() - XOrigin;
1015 w[iht] = wireID.
Wire - off;
1020 if (ninpl[ipl] == 2) ++nok;
1026 if (nok < 2)
return;
1030 TVectorD tVec = svd.Solve(w, ok);
1035 if (npts <= 4)
return;
1037 for (
const auto&
hit : hit2DSet) {
1043 double const x =
hit->getXPosition() - XOrigin;
1044 double const ypr = tVec[0] + tVec[2] *
x;
1045 double const zpr = tVec[1] + tVec[3] *
x;
1046 double const diff = ypr * cw + zpr * sw - (wireID.
Wire - off);
1047 ChiDOF += diff * diff;
1052 ChiDOF /= (float)(npts - 4);
1054 double norm = sqrt(1 + tVec[2] * tVec[2] + tVec[3] * tVec[3]);
1056 Dir[1] = tVec[2] /
norm;
1057 Dir[2] = tVec[3] /
norm;
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.
Length_t WireCoordinate(Point_t const &pos, PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
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
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
void findHoughClusters(const reco::HitPairListPtr &inputHits, reco::PrincipalComponents &pca, RhoThetaAccumulatorBinMap &rhoThetaMap, HoughClusterList &clusterList) const
std::vector< TVirtualPad * > m_Pads
View pads in current canvas.
const Eigen::Vector3f getPosition() const
std::vector< AccumulatorValues > AccumulatorValuesVec
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.
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
unsigned int getStatusBits() const
float getDocaToAxis() const
Define a comparator which will sort hits by the absolute value of arc length so hits are ordered clos...
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
OrderHitsAlongWire(int plane=0)
float getAveHitDoca() const
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
decltype(auto) values(Coll &&coll)
Range-for loop helper iterating across the values of the specified collection.
T get(std::string const &key) 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
Detector simulation of raw signals on wires.
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...
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
const Eigen::Vector3f & getPosition() const
decltype(auto) get(T &&obj)
ADL-aware version of std::to_string.
bool operator()(const std::pair< size_t, size_t > &left, const std::pair< size_t, size_t > &right)
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
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)
Length_t WirePitch(PlaneID const &planeid=plane_zero) const
Returns the distance between two consecutive wires.
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