23 #include "TDecompSVD.h" 44 , m_hiThresholdFrac(.05)
45 , m_loThresholdFrac(0.85)
48 , m_numSkippedHits(10)
49 , m_maxLoopsPerCluster(3)
51 , m_pcaAlg(pset.
get<
fhicl::ParameterSet>(
"PrincipalComponentsAlg"))
52 , m_displayHist(false)
71 class AccumulatorValues {
83 : m_position(position), m_hit3DIterator(itr)
86 const Eigen::Vector3f&
94 return m_hit3DIterator;
117 m_accumulatorValuesVec.push_back(values);
139 m_accumulatorValuesVec.push_back(value);
161 return m_accumulatorValuesVec;
183 size_t peakCountLeft(0);
184 size_t peakCountRight(0);
186 for (
const auto& binIndex : left)
187 peakCountLeft =
std::max(peakCountLeft, m_accMap[binIndex].getAccumulatorValues().
size());
188 for (
const auto& binIndex : right)
189 peakCountRight =
std::max(peakCountRight, m_accMap[binIndex].getAccumulatorValues().
size());
191 return peakCountLeft > peakCountRight;
206 size_t leftSize = left->second.getAccumulatorValues().size();
207 size_t rightSize = right->second.getAccumulatorValues().size();
209 return leftSize > rightSize;
217 size_t threshold)
const 224 for (
int rhoIdx = curBin.first - 1; rhoIdx <= curBin.first + 1; rhoIdx++) {
225 for (
int jdx = curBin.second - 1; jdx <= curBin.second + 1; jdx++) {
227 if (rhoIdx == curBin.first && jdx == curBin.second)
continue;
237 BinIndex binIndex(rhoIdx, thetaIdx);
240 if (mapItr != rhoThetaAccumulatorBinMap.end()) {
241 if (mapItr->second.getAccumulatorValues().size() >= threshold)
242 neighborPts.push_back(binIndex);
255 size_t threshold)
const 262 houghCluster.push_back(curBin);
264 for (
auto& binIndex : neighborPts) {
272 HoughRegionQuery(binIndex, rhoThetaAccumulatorBinMap, nextNeighborPts, threshold);
274 if (!nextNeighborPts.empty()) {
275 for (
auto& neighborIdx : nextNeighborPts) {
276 neighborPts.push_back(neighborIdx);
282 houghCluster.push_back(binIndex);
293 return *left < *
right;
311 int planeToCheck = (m_plane + 1) % 3;
313 return left->
getHits()[planeToCheck]->WireID().Wire <
314 right->
getHits()[planeToCheck]->WireID().Wire;
323 operator()(
const std::pair<size_t, size_t>& left,
const std::pair<size_t, size_t>& right)
325 return left.second < right.second;
345 outputList = inputHitList;
357 std::map<size_t, reco::HitPairListPtr> gapHitListMap;
360 double arcLenLastHit = inputHitList.front()->getArclenToPoca();
363 for (
const auto& hit3D : inputHitList) {
365 double arcLen = hit3D->getArclenToPoca();
366 double deltaArcLen = arcLen - arcLenLastHit;
369 gapHitListMap[continuousHitList.size()] = continuousHitList;
370 continuousHitList.clear();
373 continuousHitList.emplace_back(hit3D);
375 arcLenLastHit = arcLen;
378 if (!continuousHitList.empty()) gapHitListMap[continuousHitList.size()] = continuousHitList;
381 std::map<size_t, reco::HitPairListPtr>::reverse_iterator longestListItr =
382 gapHitListMap.rbegin();
384 if (longestListItr != gapHitListMap.rend()) {
385 size_t nContinuousHits = longestListItr->first;
388 outputList.resize(nContinuousHits);
389 std::copy(longestList.begin(), longestList.end(), outputList.begin());
411 static int histCount(0);
412 const double maxTheta(
M_PI);
413 const double thetaBinSize(maxTheta /
double(
m_thetaBins));
417 Eigen::Vector3f pcaCenter(
424 double maxRho = std::sqrt(eigenVal0 * eigenVal0 + eigenVal1 * eigenVal1) * 2. / 3.;
425 double rhoBinSize = maxRho / double(
m_rhoBins);
427 if (rhoBinSize < rhoBinSizeMin) rhoBinSize = rhoBinSizeMin;
433 size_t maxBinCount(0);
434 int nAccepted3DHits(0);
438 hit3DItr != hitPairListPtr.end();
448 Eigen::Vector3f hit3DPosition(
450 Eigen::Vector3f pcaToHitVec = hit3DPosition - pcaCenter;
451 Eigen::Vector3f pcaToHitPlaneVec(pcaToHitVec.dot(planeVec0), pcaToHitVec.dot(planeVec1), 0.);
452 double xPcaToHit = pcaToHitPlaneVec[0];
453 double yPcaToHit = pcaToHitPlaneVec[1];
460 for (
int thetaIdx = 0; thetaIdx <
m_thetaBins; thetaIdx++) {
462 double theta = thetaBinSize * double(thetaIdx);
465 double rho = xPcaToHit * std::cos(theta) + yPcaToHit * std::sin(theta);
468 int rhoIdx = std::round(rho / rhoBinSize);
471 BinIndex binIndex(rhoIdx, thetaIdx);
473 rhoThetaAccumulatorBinMap[binIndex].addAccumulatorValue(accValue);
475 if (rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues().
size() > maxBinCount)
476 maxBinCount = rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues().size();
482 std::ostringstream ostr;
483 ostr <<
"Hough Histogram " << histCount++;
484 m_Canvases.emplace_back(
new TCanvas(ostr.str().c_str(), ostr.str().c_str(), 1000, 1000));
486 std::ostringstream ostr2;
489 m_Canvases.back()->GetFrame()->SetFillColor(46);
498 TPad*
p =
new TPad(ostr2.str().c_str(), ostr2.str().c_str(), zmin, xmin, zmax, xmax);
499 p->SetBit(kCanDelete);
500 p->Range(zmin, xmin, zmax, xmax);
501 p->SetFillStyle(4000);
505 TH2D* houghHist =
new TH2D(
"HoughHist",
514 for (
const auto& rhoThetaMap : rhoThetaAccumulatorBinMap) {
515 houghHist->Fill(rhoThetaMap.first.first,
516 rhoThetaMap.first.second + 0.5,
517 rhoThetaMap.second.getAccumulatorValues().size());
520 houghHist->SetBit(kCanDelete);
532 std::list<RhoThetaAccumulatorBinMap::iterator> binIndexList;
535 mapItr != rhoThetaAccumulatorBinMap.end();
537 binIndexList.push_back(mapItr);
539 binIndexList.sort(SortBinIndexList());
541 for (
auto& mapItr : binIndexList) {
544 if (mapItr->second.isInCluster())
continue;
551 if (mapItr->second.getAccumulatorValues().size() < thresholdLo) {
552 mapItr->second.setNoise();
564 HoughRegionQuery(curBin, rhoThetaAccumulatorBinMap, neighborhood, thresholdHi);
571 curBin, neighborhood, houghCluster, rhoThetaAccumulatorBinMap, thresholdHi);
575 if (!houghClusters.empty()) houghClusters.sort(SortHoughClusterList(rhoThetaAccumulatorBinMap));
590 if (!seedFullPca.
getSvdOK())
return false;
602 std::set<const reco::ClusterHit2D*> seedHitSet;
609 peakBinItr != seed3DHits.end();
616 seedHit3DList.clear();
620 seedHit3DList.push_back(hit3D);
623 seedHitSet.insert(
hit);
641 if (!seedPca.
getSvdOK())
return false;
648 double seedCenter[3] = {
654 double arcLen = seedHit3DList.front()->getArclenToPoca();
655 double seedStart[3] = {seedCenter[0] + arcLen * seedDir[0],
656 seedCenter[1] + arcLen * seedDir[1],
657 seedCenter[2] + arcLen * seedDir[2]};
663 if (seedHitSet.size() >= 10) {
668 LineFit2DHits(seedHitSet, seedStart[0], newSeedPos, newSeedDir, chiDOF);
673 seedDir[0] * newSeedDir[0] + seedDir[1] * newSeedDir[1] + seedDir[2] * newSeedDir[2];
675 if (cosAng < 0.) newSeedDir *= -1.;
677 seedStart[0] = newSeedPos[0];
678 seedStart[1] = newSeedPos[1];
679 seedStart[2] = newSeedPos[2];
680 seedDir[0] = newSeedDir[0];
681 seedDir[1] = newSeedDir[1];
682 seedDir[2] = newSeedDir[2];
690 if (seed3DHits.size() > 100) {
697 size_t numToKeep = seed3DHits.size() - 10;
701 std::advance(endItr, numToKeep);
703 seed3DHits.erase(endItr, seed3DHits.end());
721 typedef std::map<size_t, SeedHitPairListPairVec> SizeToSeedToHitMap;
723 SizeToSeedToHitMap seedHitPairMap;
735 while (!hitPairListPtr.empty()) {
740 if (eigenVal0 > 5. && eigenVal1 > 0.001) {
747 findHoughClusters(hitPairListPtr, pca, nLoops, rhoThetaAccumulatorBinMap, houghClusters);
750 if (houghClusters.empty())
break;
758 std::set<const reco::ClusterHit3D*> masterHitPtrList;
759 std::set<const reco::ClusterHit3D*> peakBinPtrList;
761 size_t firstPeakCount(0);
764 for (
auto& houghCluster : houghClusters) {
765 BinIndex peakBin = houghCluster.front();
766 size_t peakCount = 0;
767 size_t totalHits = 0;
770 std::set<const reco::ClusterHit3D*> localHitPtrList;
773 for (
auto& binIndex : houghCluster) {
775 std::set<const reco::ClusterHit3D*> tempHitPtrList;
778 for (
auto& hitItr : rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues()) {
781 tempHitPtrList.insert(*hit3DItr);
785 totalHits += tempHitPtrList.size();
788 std::set<const reco::ClusterHit3D*> tempHit3DSet;
790 std::set_difference(tempHitPtrList.begin(),
791 tempHitPtrList.end(),
792 masterHitPtrList.begin(),
793 masterHitPtrList.end(),
794 std::inserter(tempHit3DSet, tempHit3DSet.end()));
796 tempHitPtrList = tempHit3DSet;
798 size_t binCount = tempHitPtrList.size();
800 if (peakCount < binCount) {
801 peakCount = binCount;
803 peakBinPtrList = tempHitPtrList;
807 localHitPtrList.insert(tempHitPtrList.begin(), tempHitPtrList.end());
812 if (!firstPeakCount) firstPeakCount = peakCount;
815 if (peakCount < firstPeakCount / 10)
continue;
823 for (
const auto& hit3D : localHitPtrList)
824 allPeakBinHits.push_back(hit3D);
834 if (
buildSeed(peakBinHits, seedHitPair)) {
836 seedHitPairMap[peakBinHits.size()].push_back(seedHitPair);
839 if (seedHitPairMap.size() == 1) {
840 for (
const auto& hit3D : peakBinHits)
841 hit3D->setStatusBit(0x40000000);
852 masterHitPtrList.insert(peakBinHits.begin(), peakBinHits.end());
854 if (hitPairListPtr.size() - masterHitPtrList.size() <
m_minimum3DHits)
break;
858 if (masterHitPtrList.empty())
break;
864 hitPairListPtr.sort();
867 hitPairListPtr.end(),
868 masterHitPtrList.begin(),
869 masterHitPtrList.end(),
870 hitPairListPtr.begin());
872 hitPairListPtr.erase(newListEnd, hitPairListPtr.end());
893 for (SizeToSeedToHitMap::reverse_iterator seedMapItr = seedHitPairMap.rbegin();
894 seedMapItr != seedHitPairMap.rend();
896 for (
const auto& seedHitPair : seedMapItr->second) {
897 seedHitPairVec.emplace_back(seedHitPair);
924 if (eigenVal0 > 5. && eigenVal1 > 0.001) {
931 findHoughClusters(hitPairListPtr, pca, nLoops, rhoThetaAccumulatorBinMap, houghClusters);
939 std::set<const reco::ClusterHit3D*> masterHitPtrList;
940 std::set<const reco::ClusterHit3D*> peakBinPtrList;
942 size_t firstPeakCount(0);
945 for (
auto& houghCluster : houghClusters) {
946 BinIndex peakBin = houghCluster.front();
947 size_t peakCount = 0;
948 size_t totalHits = 0;
951 std::set<const reco::ClusterHit3D*> localHitPtrList;
954 for (
auto& binIndex : houghCluster) {
956 std::set<const reco::ClusterHit3D*> tempHitPtrList;
959 for (
auto& hitItr : rhoThetaAccumulatorBinMap[binIndex].getAccumulatorValues()) {
962 tempHitPtrList.insert(*hit3DItr);
966 totalHits += tempHitPtrList.size();
969 std::set<const reco::ClusterHit3D*> tempHit3DSet;
971 std::set_difference(tempHitPtrList.begin(),
972 tempHitPtrList.end(),
973 masterHitPtrList.begin(),
974 masterHitPtrList.end(),
975 std::inserter(tempHit3DSet, tempHit3DSet.end()));
977 tempHitPtrList = tempHit3DSet;
979 size_t binCount = tempHitPtrList.size();
981 if (peakCount < binCount) {
982 peakCount = binCount;
984 peakBinPtrList = tempHitPtrList;
988 localHitPtrList.insert(tempHitPtrList.begin(), tempHitPtrList.end());
993 if (!firstPeakCount) firstPeakCount = peakCount;
996 if (peakCount < firstPeakCount / 10)
continue;
1004 hitPairListPtrList.back().resize(localHitPtrList.size());
1006 localHitPtrList.begin(), localHitPtrList.end(), hitPairListPtrList.back().begin());
1009 masterHitPtrList.insert(localHitPtrList.begin(), localHitPtrList.end());
1011 if (hitPairListPtr.size() - masterHitPtrList.size() <
m_minimum3DHits)
break;
1024 double& ChiDOF)
const 1046 if (hit2DSet.size() < 4)
return;
1048 const unsigned int nvars = 4;
1049 unsigned int npts = hit2DSet.size();
1051 TMatrixD
A(npts, nvars);
1054 unsigned short ninpl[3] = {0};
1055 unsigned short nok = 0;
1056 unsigned short iht(0), cstat, tpc, ipl;
1057 double x, cw, sw, off;
1060 for (
const auto&
hit : hit2DSet) {
1076 x =
hit->getXPosition() - XOrigin;
1082 w[iht] = wireID.
Wire - off;
1087 if (ninpl[ipl] == 2) ++nok;
1093 if (nok < 2)
return;
1097 TVectorD tVec = svd.Solve(w, ok);
1102 if (npts <= 4)
return;
1104 double ypr, zpr, diff;
1106 for (
const auto&
hit : hit2DSet) {
1115 x =
hit->getXPosition() - XOrigin;
1116 ypr = tVec[0] + tVec[2] *
x;
1117 zpr = tVec[1] + tVec[3] *
x;
1118 diff = ypr * cw + zpr * sw - (wireID.
Wire - off);
1119 ChiDOF += diff * diff;
1124 ChiDOF /= (
float)(npts - 4);
1126 double norm = sqrt(1 + tVec[2] * tVec[2] + tVec[3] * tVec[3]);
1128 Dir[1] = tVec[2] /
norm;
1129 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.
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
const Eigen::Vector3f getPosition() const
CryostatID_t Cryostat
Index of cryostat.
std::vector< AccumulatorValues > AccumulatorValuesVec
HoughSeedFinderAlg(fhicl::ParameterSet const &pset)
Constructor.
WireID_t Wire
Index of the wire within its plane.
std::list< HitPairListPtr > HitPairListPtrList
std::vector< TVirtualPad * > m_Pads
View pads in current canvas.
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.
std::pair< recob::Seed, reco::HitPairListPtr > SeedHitPairListPair
float getDocaToAxis() const
art framework interface to geometry description
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)
std::vector< std::unique_ptr< TCanvas > > m_Canvases
Graphical trace canvases.
void expandHoughCluster(BinIndex &curBin, HoughCluster &neighborPts, HoughCluster &houghCluster, RhoThetaAccumulatorBinMap &rhoThetaAccumulatorBinMap, size_t threshold) const
void addAccumulatorValue(AccumulatorValues &value)
const EigenValues & getEigenValues() const
void HoughRegionQuery(BinIndex &curBin, RhoThetaAccumulatorBinMap &rhoThetaAccumulatorBinMap, HoughCluster &neighborPts, size_t threshold) const
T get(std::string const &key) const
const Eigen::Vector3f & getAvePosition() const
std::list< HoughCluster > HoughClusterList
const AccumulatorValuesVec & getAccumulatorValues() const
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)
static int max(int a, int b)
PlaneID_t Plane
Index of the plane within its TPC.
geo::Geometry * m_geometry
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.
Detector simulation of raw signals on wires.
virtual 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
std::list< BinIndex > HoughCluster
Eigen::Vector3f m_position
We really only need the x,y coordinates here but keep all three for now.
virtual bool findTrackSeeds(reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, SeedHitPairListPairVec &seedHitPairVec) const
Given the list of hits this will search for candidate Seed objects and return them.
SortHoughClusterList(HoughSeedFinderAlg::RhoThetaAccumulatorBinMap &accMap)
This is used to sort "Hough Clusters" by the maximum entries in a bin.
std::vector< SeedHitPairListPair > SeedHitPairListPairVec
AccumulatorBin(AccumulatorValues &values)
std::pair< int, int > BinIndex
auto const & get(AssnsNode< L, R, D > const &r)
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.
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
const EigenVectors & getEigenVectors() const