26 #include "TDecompSVD.h" 47 , m_hiThresholdFrac(.05)
48 , m_loThresholdFrac(0.85)
51 , m_numSkippedHits(10)
52 , m_maxLoopsPerCluster(3)
54 , m_pcaAlg(pset.
get<
fhicl::ParameterSet>(
"PrincipalComponentsAlg"))
55 , m_displayHist(false)
86 : m_position(position), m_hit3DIterator(itr)
89 const Eigen::Vector3f&
getPosition()
const {
return m_position; }
112 m_accumulatorValuesVec.push_back(values);
145 size_t peakCountLeft(0);
146 size_t peakCountRight(0);
148 for (
const auto& binIndex : left)
149 peakCountLeft = std::max(peakCountLeft, m_accMap[binIndex].getAccumulatorValues().
size());
150 for (
const auto& binIndex : right)
151 peakCountRight = std::max(peakCountRight, m_accMap[binIndex].getAccumulatorValues().
size());
153 return peakCountLeft > peakCountRight;
167 size_t leftSize = left->second.getAccumulatorValues().size();
168 size_t rightSize = right->second.getAccumulatorValues().size();
170 return leftSize > rightSize;
177 size_t threshold)
const 184 for (
int rhoIdx = curBin.first - 1; rhoIdx <= curBin.first + 1; rhoIdx++) {
185 for (
int jdx = curBin.second - 1; jdx <= curBin.second + 1; jdx++) {
187 if (rhoIdx == curBin.first && jdx == curBin.second)
continue;
197 BinIndex binIndex(rhoIdx, thetaIdx);
200 if (mapItr != rhoThetaAccumulatorBinMap.end()) {
201 if (mapItr->second.getAccumulatorValues().size() >= threshold)
202 neighborPts.push_back(binIndex);
214 size_t threshold)
const 221 houghCluster.push_back(curBin);
223 for (
auto& binIndex : neighborPts) {
231 HoughRegionQuery(binIndex, rhoThetaAccumulatorBinMap, nextNeighborPts, threshold);
233 if (!nextNeighborPts.empty()) {
234 for (
auto& neighborIdx : nextNeighborPts) {
235 neighborPts.push_back(neighborIdx);
241 houghCluster.push_back(binIndex);
251 return *left < *
right;
267 int planeToCheck = (m_plane + 1) % 3;
269 return left->
getHits()[planeToCheck]->WireID().Wire <
270 right->
getHits()[planeToCheck]->WireID().Wire;
280 return left.second < right.second;
299 outputList = inputHitList;
311 std::map<size_t, reco::HitPairListPtr> gapHitListMap;
314 double arcLenLastHit = inputHitList.front()->getArclenToPoca();
317 for (
const auto& hit3D : inputHitList) {
319 double arcLen = hit3D->getArclenToPoca();
320 double deltaArcLen = arcLen - arcLenLastHit;
323 gapHitListMap[continuousHitList.size()] = continuousHitList;
324 continuousHitList.clear();
327 continuousHitList.emplace_back(hit3D);
329 arcLenLastHit = arcLen;
332 if (!continuousHitList.empty()) gapHitListMap[continuousHitList.size()] = continuousHitList;
335 std::map<size_t, reco::HitPairListPtr>::reverse_iterator longestListItr =
336 gapHitListMap.rbegin();
338 if (longestListItr != gapHitListMap.rend()) {
339 size_t nContinuousHits = longestListItr->first;
342 outputList.resize(nContinuousHits);
343 std::copy(longestList.begin(), longestList.end(), outputList.begin());
363 static int histCount(0);
364 const double maxTheta(M_PI);
365 const double thetaBinSize(maxTheta /
double(
m_thetaBins));
366 const double rhoBinSizeMin(
370 Eigen::Vector3f pcaCenter(
377 double maxRho = std::sqrt(eigenVal0 * eigenVal0 + eigenVal1 * eigenVal1) * 2. / 3.;
378 double rhoBinSize = maxRho / double(
m_rhoBins);
380 if (rhoBinSize < rhoBinSizeMin) rhoBinSize = rhoBinSizeMin;
386 size_t maxBinCount(0);
387 int nAccepted3DHits(0);
391 hit3DItr != hitPairListPtr.end();
401 Eigen::Vector3f hit3DPosition(
403 Eigen::Vector3f pcaToHitVec = hit3DPosition - pcaCenter;
404 Eigen::Vector3f pcaToHitPlaneVec(pcaToHitVec.dot(planeVec0), pcaToHitVec.dot(planeVec1), 0.);
405 double xPcaToHit = pcaToHitPlaneVec[0];
406 double yPcaToHit = pcaToHitPlaneVec[1];
413 for (
int thetaIdx = 0; thetaIdx <
m_thetaBins; thetaIdx++) {
415 double theta = thetaBinSize * double(thetaIdx);
418 double rho = xPcaToHit * std::cos(theta) + yPcaToHit * std::sin(theta);
421 int rhoIdx = std::round(rho / rhoBinSize);
424 BinIndex binIndex(rhoIdx, thetaIdx);
426 rhoThetaAccumulatorBinMap[binIndex].addAccumulatorValue(accValue);
428 if (rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues().
size() > maxBinCount)
429 maxBinCount = rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues().size();
435 std::ostringstream ostr;
436 ostr <<
"Hough Histogram " << histCount++;
437 m_Canvases.emplace_back(
new TCanvas(ostr.str().c_str(), ostr.str().c_str(), 1000, 1000));
439 std::ostringstream ostr2;
442 m_Canvases.back()->GetFrame()->SetFillColor(46);
451 TPad* p =
new TPad(ostr2.str().c_str(), ostr2.str().c_str(), zmin, xmin, zmax, xmax);
452 p->SetBit(kCanDelete);
453 p->Range(zmin, xmin, zmax, xmax);
454 p->SetFillStyle(4000);
458 TH2D* houghHist =
new TH2D(
"HoughHist",
467 for (
const auto& rhoThetaMap : rhoThetaAccumulatorBinMap) {
468 houghHist->Fill(rhoThetaMap.first.first,
469 rhoThetaMap.first.second + 0.5,
470 rhoThetaMap.second.getAccumulatorValues().size());
473 houghHist->SetBit(kCanDelete);
485 std::list<RhoThetaAccumulatorBinMap::iterator> binIndexList;
488 mapItr != rhoThetaAccumulatorBinMap.end();
490 binIndexList.push_back(mapItr);
494 for (
auto& mapItr : binIndexList) {
497 if (mapItr->second.isInCluster())
continue;
504 if (mapItr->second.getAccumulatorValues().size() < thresholdLo) {
505 mapItr->second.setNoise();
510 thresholdHi = std::max(
517 HoughRegionQuery(curBin, rhoThetaAccumulatorBinMap, neighborhood, thresholdHi);
524 curBin, neighborhood, houghCluster, rhoThetaAccumulatorBinMap, thresholdHi);
528 if (!houghClusters.empty()) houghClusters.sort(
SortHoughClusterList(rhoThetaAccumulatorBinMap));
542 if (!seedFullPca.
getSvdOK())
return false;
554 std::set<const reco::ClusterHit2D*> seedHitSet;
561 peakBinItr != seed3DHits.end();
568 seedHit3DList.clear();
572 seedHit3DList.push_back(hit3D);
575 seedHitSet.insert(
hit);
593 if (!seedPca.
getSvdOK())
return false;
600 double seedCenter[3] = {
606 double arcLen = seedHit3DList.front()->getArclenToPoca();
607 double seedStart[3] = {seedCenter[0] + arcLen * seedDir[0],
608 seedCenter[1] + arcLen * seedDir[1],
609 seedCenter[2] + arcLen * seedDir[2]};
615 if (seedHitSet.size() >= 10) {
620 LineFit2DHits(seedHitSet, seedStart[0], newSeedPos, newSeedDir, chiDOF);
625 seedDir[0] * newSeedDir[0] + seedDir[1] * newSeedDir[1] + seedDir[2] * newSeedDir[2];
627 if (cosAng < 0.) newSeedDir *= -1.;
629 seedStart[0] = newSeedPos[0];
630 seedStart[1] = newSeedPos[1];
631 seedStart[2] = newSeedPos[2];
632 seedDir[0] = newSeedDir[0];
633 seedDir[1] = newSeedDir[1];
634 seedDir[2] = newSeedDir[2];
642 if (seed3DHits.size() > 100) {
649 size_t numToKeep = seed3DHits.size() - 10;
653 std::advance(endItr, numToKeep);
655 seed3DHits.erase(endItr, seed3DHits.end());
672 typedef std::map<size_t, SeedHitPairListPairVec> SizeToSeedToHitMap;
674 SizeToSeedToHitMap seedHitPairMap;
686 while (!hitPairListPtr.empty()) {
691 if (eigenVal0 > 5. && eigenVal1 > 0.001) {
698 findHoughClusters(hitPairListPtr, pca, rhoThetaAccumulatorBinMap, houghClusters);
701 if (houghClusters.empty())
break;
709 std::set<const reco::ClusterHit3D*> masterHitPtrList;
710 std::set<const reco::ClusterHit3D*> peakBinPtrList;
712 size_t firstPeakCount(0);
715 for (
auto& houghCluster : houghClusters) {
716 BinIndex peakBin = houghCluster.front();
717 size_t peakCount = 0;
720 std::set<const reco::ClusterHit3D*> localHitPtrList;
723 for (
auto& binIndex : houghCluster) {
725 std::set<const reco::ClusterHit3D*> tempHitPtrList;
728 for (
auto& hitItr : rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues()) {
731 tempHitPtrList.insert(*hit3DItr);
735 std::set<const reco::ClusterHit3D*> tempHit3DSet;
737 std::set_difference(tempHitPtrList.begin(),
738 tempHitPtrList.end(),
739 masterHitPtrList.begin(),
740 masterHitPtrList.end(),
741 std::inserter(tempHit3DSet, tempHit3DSet.end()));
743 tempHitPtrList = tempHit3DSet;
745 size_t binCount = tempHitPtrList.size();
747 if (peakCount < binCount) {
748 peakCount = binCount;
750 peakBinPtrList = tempHitPtrList;
754 localHitPtrList.insert(tempHitPtrList.begin(), tempHitPtrList.end());
759 if (!firstPeakCount) firstPeakCount = peakCount;
762 if (peakCount < firstPeakCount / 10)
continue;
770 for (
const auto& hit3D : localHitPtrList)
771 allPeakBinHits.push_back(hit3D);
781 if (
buildSeed(peakBinHits, seedHitPair)) {
783 seedHitPairMap[peakBinHits.size()].push_back(seedHitPair);
786 if (seedHitPairMap.size() == 1) {
787 for (
const auto& hit3D : peakBinHits)
788 hit3D->setStatusBit(0x40000000);
799 masterHitPtrList.insert(peakBinHits.begin(), peakBinHits.end());
801 if (hitPairListPtr.size() - masterHitPtrList.size() <
m_minimum3DHits)
break;
805 if (masterHitPtrList.empty())
break;
811 hitPairListPtr.sort();
814 hitPairListPtr.end(),
815 masterHitPtrList.begin(),
816 masterHitPtrList.end(),
817 hitPairListPtr.begin());
819 hitPairListPtr.erase(newListEnd, hitPairListPtr.end());
840 for (SizeToSeedToHitMap::reverse_iterator seedMapItr = seedHitPairMap.rbegin();
841 seedMapItr != seedHitPairMap.rend();
843 for (
const auto& seedHitPair : seedMapItr->second) {
844 seedHitPairVec.emplace_back(seedHitPair);
868 if (eigenVal0 > 5. && eigenVal1 > 0.001) {
875 findHoughClusters(hitPairListPtr, pca, rhoThetaAccumulatorBinMap, houghClusters);
883 std::set<const reco::ClusterHit3D*> masterHitPtrList;
884 std::set<const reco::ClusterHit3D*> peakBinPtrList;
886 size_t firstPeakCount(0);
889 for (
auto& houghCluster : houghClusters) {
890 BinIndex peakBin = houghCluster.front();
891 size_t peakCount = 0;
894 std::set<const reco::ClusterHit3D*> localHitPtrList;
897 for (
auto& binIndex : houghCluster) {
899 std::set<const reco::ClusterHit3D*> tempHitPtrList;
902 for (
auto& hitItr : rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues()) {
905 tempHitPtrList.insert(*hit3DItr);
909 std::set<const reco::ClusterHit3D*> tempHit3DSet;
911 std::set_difference(tempHitPtrList.begin(),
912 tempHitPtrList.end(),
913 masterHitPtrList.begin(),
914 masterHitPtrList.end(),
915 std::inserter(tempHit3DSet, tempHit3DSet.end()));
917 tempHitPtrList = tempHit3DSet;
919 size_t binCount = tempHitPtrList.size();
921 if (peakCount < binCount) {
922 peakCount = binCount;
924 peakBinPtrList = tempHitPtrList;
928 localHitPtrList.insert(tempHitPtrList.begin(), tempHitPtrList.end());
933 if (!firstPeakCount) firstPeakCount = peakCount;
936 if (peakCount < firstPeakCount / 10)
continue;
944 hitPairListPtrList.back().resize(localHitPtrList.size());
946 localHitPtrList.begin(), localHitPtrList.end(), hitPairListPtrList.back().begin());
949 masterHitPtrList.insert(localHitPtrList.begin(), localHitPtrList.end());
951 if (hitPairListPtr.size() - masterHitPtrList.size() <
m_minimum3DHits)
break;
963 double& ChiDOF)
const 985 if (hit2DSet.size() < 4)
return;
987 const unsigned int nvars = 4;
988 unsigned int npts = hit2DSet.size();
990 TMatrixD A(npts, nvars);
993 unsigned short ninpl[3] = {0};
994 unsigned short nok = 0;
995 unsigned short iht(0);
998 for (
const auto&
hit : hit2DSet) {
1001 unsigned int const ipl = wireID.
Plane;
1004 double const off = plane.WireCoordinate(
geo::Point_t{});
1007 double const cw = plane.WireCoordinate(
geo::Point_t{0., 1., 0.}) - off;
1010 double const sw = plane.WireCoordinate(
geo::Point_t{0., 0., 1.}) - off;
1012 double const x =
hit->getXPosition() - XOrigin;
1018 w[iht] = wireID.
Wire - off;
1023 if (ninpl[ipl] == 2) ++nok;
1029 if (nok < 2)
return;
1033 TVectorD tVec = svd.Solve(w, ok);
1038 if (npts <= 4)
return;
1040 for (
const auto&
hit : hit2DSet) {
1044 double const cw = plane.WireCoordinate(
geo::Point_t{0., 1., 0.}) - off;
1045 double const sw = plane.WireCoordinate(
geo::Point_t{0., 0., 1.}) - off;
1046 double const x =
hit->getXPosition() - XOrigin;
1047 double const ypr = tVec[0] + tVec[2] *
x;
1048 double const zpr = tVec[1] + tVec[3] *
x;
1049 double const diff = ypr * cw + zpr * sw - (wireID.
Wire - off);
1050 ChiDOF += diff * diff;
1054 float werr2 = plane.
WirePitch() * plane.WirePitch();
1056 ChiDOF /= (float)(npts - 4);
1058 double norm = sqrt(1 + tVec[2] * tVec[2] + tVec[3] * tVec[3]);
1060 Dir[1] = tVec[2] /
norm;
1061 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.
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.
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.
double WireCoordinate(Point_t const &point) const
Returns the coordinate of the point on the plane, in wire units.
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.
cout<< "Opened file "<< fin<< " ixs= "<< ixs<< endl;if(ixs==0) hhh=(TH1F *) fff-> Get("h1")
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)
Encapsulate the construction of a single detector plane .
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
PlaneGeo const & Plane(TPCID const &tpcid, View_t view) const
Returns the specified wire.
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
double WirePitch() const
Return the wire pitch (in centimeters). It is assumed constant.
const EigenVectors & getEigenVectors() const
geo::WireReadoutGeom const * m_wireReadoutGeom