9 #include "art/Framework/Services/Registry/ServiceHandle.h"
10 #include "art/Utilities/ToolMacros.h"
11 #include "art_root_io/TFileDirectory.h"
12 #include "art_root_io/TFileService.h"
13 #include "cetlib/cpu_timer.h"
14 #include "fhiclcpp/ParameterSet.h"
15 #include "messagefacility/MessageLogger/MessageLogger.h"
32 namespace lar_cluster3d {
49 void configure(fhicl::ParameterSet
const &pset)
override;
78 float closestApproach(
const Eigen::Vector3f&,
const Eigen::Vector3f&,
const Eigen::Vector3f&,
const Eigen::Vector3f&, Eigen::Vector3f&, Eigen::Vector3f&, Eigen::Vector3f&)
const;
127 fPCAAlg(pset.
get<fhicl::ParameterSet>(
"PrincipalComponentsAlg"))
150 if (fOutputHistograms)
154 art::ServiceHandle<art::TFileService>
tfs;
157 art::TFileDirectory
dir = tfs->mkdir(
"MergeClusters");
162 std::vector<float> maxValsVec = {20., 50., 250.};
164 for(
size_t idx : {0, 1, 2})
166 fFirstEigenValueHists[idx] = dir.make<TH1F>(Form(
"FEigen1st%1zu",idx),
"Eigen Val", 200, 0., maxValsVec[idx]);
167 fNextEigenValueHists[idx] = dir.make<TH1F>(Form(
"FEigen2nd%1zu",idx),
"Eigen Val", 200, 0., maxValsVec[idx]);
170 fNumMergedClusters = dir.make<TH1F>(
"NumMergedClus",
"Number Merged", 200, 0., 1000.);
172 f1stTo2ndPosLenHist = dir.make<TH1F>(
"1stTo2ndPosLen",
"Distance between Clusters", 250, 0., 1000.);
174 fRMaxFirstHist = dir.make<TH1F>(
"rMaxFirst",
"Radius of First Cluster", 200, 0., 100.);
175 fCosMaxFirstHist = dir.make<TH1F>(
"CosMaxFirst",
"Cos Angle First Cyl/Axis", 200, 0., 1. );
176 fCosFirstAxisHist = dir.make<TH1F>(
"CosFirstAxis",
"Cos Angle First Next/Axis", 200, 0., 1. );
179 fRMaxNextHist = dir.make<TH1F>(
"rMaxNext",
"Radius of Next Cluster", 200, 0., 100.);
180 fCosMaxNextHist = dir.make<TH1F>(
"CosMaxNext",
"Cos Angle Next Cyl/Axis", 200, 0., 1. );
181 fCosNextAxisHist = dir.make<TH1F>(
"CosNextAxis",
"Cos Angle Next Next/Axis", 200, 0., 1. );
184 fGapBetweenClusHist = dir.make<TH1F>(
"ClusterGap",
"Gap Between Clusters", 400, -200., 200.);
185 fGapRatToLenHist = dir.make<TH1F>(
"GapRatToLen",
"Ratio Gap to Distance", 100, -8., 2.);
186 fProjEndPointLenHist = dir.make<TH1F>(
"ProjEndPointLen",
"Projected End Point Len", 200, -100., 100.);
187 fProjEndPointRatHist = dir.make<TH1F>(
"ProjEndPointRat",
"Projected End Point Ratio", 100, 0., 1.);
189 fAxesDocaHist = dir.make<TH1F>(
"AxesDocaHist",
"DOCA", 200, 0., 25.);
190 f1stDocaArcLRatHist = dir.make<TH1F>(
"ALenPOCA1Hist",
"Arc Len to POCA 1", 400, -50., 50.);
191 f2ndDocaArcLRatHist = dir.make<TH1F>(
"ALenPOCA2Hist",
"Arc Len to POCA 2", 400, -50., 50.);
194 fGapRatHist = dir.make<TH1F>(
"GapRat",
"Ratio Gap to Next Eigen", 400, -20., 20.);
215 cet::cpu_timer theClockBuildClusters;
221 clusterParametersList.sort([](
auto&
left,
auto&
right){
return left.getFullPCA().getEigenValues()[2] >
right.getFullPCA().getEigenValues()[2];});
226 size_t lastClusterListCount = clusterParametersList.size() + 1;
227 reco::ClusterParametersList::iterator lastFirstClusterItr = clusterParametersList.begin();
229 int numMergedClusters(0);
230 int nOutsideLoops(0);
232 while(clusterParametersList.size() != lastClusterListCount)
235 lastClusterListCount = clusterParametersList.size();
238 reco::ClusterParametersList::iterator firstClusterItr = lastFirstClusterItr++;
241 while(firstClusterItr != clusterParametersList.end())
244 reco::ClusterParametersList::iterator nextClusterItr = firstClusterItr;
261 while(++nextClusterItr != clusterParametersList.end())
272 nextClusterItr = clusterParametersList.erase(nextClusterItr);
276 reco::ClusterParametersList::iterator biggestItr = firstClusterItr;
279 while(biggestItr-- != clusterParametersList.begin())
283 if ((*biggestItr).getFullPCA().getEigenValues()[2] > (*firstClusterItr).getFullPCA().getEigenValues()[2])
287 if (++biggestItr != firstClusterItr) clusterParametersList.splice(biggestItr, clusterParametersList, firstClusterItr);
294 nextClusterItr = firstClusterItr;
307 std::cout <<
"==> # merged: " << numMergedClusters <<
", in " << nOutsideLoops <<
" outside loops " << std::endl;
314 theClockBuildClusters.stop();
319 mf::LogDebug(
"Cluster3D") <<
">>>>> Merge clusters done, found " << clusterParametersList.size() <<
" clusters" << std::endl;
327 bool consistent(
false);
342 Eigen::Vector3f firstPosToNextPosVec = nextCenter - firstCenter;
343 Eigen::Vector3f firstPosToNextPosUnit = firstPosToNextPosVec.normalized();
344 float firstPosToNextPosLen = firstPosToNextPosVec.norm();
352 float arcLenToNextDoca = firstPosToNextPosVec.dot(firstAxis2);
356 if (arcLenToNextDoca < 0.)
358 firstAxis0 = -firstAxis0;
359 firstAxis1 = -firstAxis1;
360 firstAxis2 = -firstAxis2;
361 arcLenToNextDoca = -arcLenToNextDoca;
371 Eigen::Vector2f firstProj01Unit = Eigen::Vector2f(firstPosToNextPosUnit.dot(firstAxis0),firstPosToNextPosUnit.dot(firstAxis1)).normalized();
372 float firstEigen0Proj = firstEigenVals[0] * firstProj01Unit[0];
373 float firstEigen1Proj = firstEigenVals[1] * firstProj01Unit[1];
374 float rMaxFirst = std::sqrt(firstEigen0Proj * firstEigen0Proj + firstEigen1Proj * firstEigen1Proj);
375 float cosMaxFirst = firstEigenVals[2] / std::sqrt(firstEigenVals[2] * firstEigenVals[2] + rMaxFirst * rMaxFirst);
376 float cosFirstAxis = firstAxis2.dot(firstPosToNextPosUnit);
379 float firstEigenVal2 = firstEigenVals[2];
380 float firstToNextProjEigen = firstEigenVal2;
383 if (cosFirstAxis < cosMaxFirst)
386 float sinFirstAxis = std::sqrt(1. - cosFirstAxis * cosFirstAxis);
389 firstToNextProjEigen = rMaxFirst / sinFirstAxis;
391 else firstToNextProjEigen /= cosFirstAxis;
394 float firstPosToNextPosScaleFactor = 8.;
407 if (firstPosToNextPosLen < firstPosToNextPosScaleFactor * firstToNextProjEigen)
415 float cosFirstNextAxis = firstAxis2.dot(nextAxis2);
419 if (cosFirstNextAxis < 0.)
421 nextAxis0 = -nextAxis0;
422 nextAxis1 = -nextAxis1;
423 nextAxis2 = -nextAxis2;
424 cosFirstNextAxis = -cosFirstNextAxis;
433 Eigen::Vector2f nextProj01Unit = Eigen::Vector2f(firstPosToNextPosUnit.dot(nextAxis0),firstPosToNextPosUnit.dot(nextAxis1)).normalized();
434 float nextEigen0Proj = nextEigenVals[0] * nextProj01Unit[0];
435 float nextEigen1Proj = nextEigenVals[1] * nextProj01Unit[1];
436 float rMaxNext = std::sqrt(nextEigen0Proj * nextEigen0Proj + nextEigen1Proj * nextEigen1Proj);
437 float cosMaxNext = nextEigenVals[2] / std::sqrt(nextEigenVals[2] * nextEigenVals[2] + rMaxNext * rMaxNext);
438 float cosNextAxis =
std::abs(nextAxis2.dot(firstPosToNextPosUnit));
441 float nextToFirstProjEigen = nextEigenVals[2];
444 if (cosNextAxis < cosMaxNext)
447 float sinNextAxis = std::sqrt(1. - cosNextAxis * cosNextAxis);
450 nextToFirstProjEigen = rMaxNext / sinNextAxis;
452 else nextToFirstProjEigen /= cosNextAxis;
456 float nextToFirstScaleFactor = 8. * cosFirstNextAxis;
460 float gapFirstToNext = firstPosToNextPosLen - firstToNextProjEigen - nextToFirstProjEigen;
463 Eigen::Vector3f firstEndPoint = firstCenter + firstEigenVals[2] * firstAxis2;
464 Eigen::Vector3f nextTailPoint = nextCenter - nextEigenVals[2] * nextAxis2;
465 Eigen::Vector3f endToTailVec = nextTailPoint - firstEndPoint;
468 float endPointProjection = endToTailVec.dot(firstPosToNextPosUnit);
469 float endToTailLen = endToTailVec.norm();
487 if (gapFirstToNext < nextToFirstScaleFactor * nextToFirstProjEigen || (
std::abs(endPointProjection) < nextToFirstProjEigen && endToTailLen < nextEigenVals[2]))
491 Eigen::Vector3f firstPoca;
492 Eigen::Vector3f nextPoca;
493 Eigen::Vector3f firstToNextUnit;
496 float lineDoca =
closestApproach(firstCenter, firstAxis2, nextCenter, nextAxis2, firstPoca, nextPoca, firstToNextUnit);
499 Eigen::Vector3f firstPOCAProjUnit = Eigen::Vector3f(firstToNextUnit.dot(firstAxis0),firstToNextUnit.dot(firstAxis1),firstToNextUnit.dot(firstAxis1)).normalized();
500 float firstPOCAVecProjEigen = std::sqrt(std::pow(firstEigenVals[0] * firstPOCAProjUnit[0],2)
501 + std::pow(firstEigenVals[1] * firstPOCAProjUnit[1],2)
502 + std::pow(firstEigenVals[2] * firstPOCAProjUnit[2],2));
505 Eigen::Vector3f nextPOCAProjUnit = Eigen::Vector3f(firstToNextUnit.dot(firstAxis0),firstToNextUnit.dot(firstAxis1),firstToNextUnit.dot(firstAxis1)).normalized();
506 float nextPOCAVecProjEigen = std::sqrt(std::pow(nextEigenVals[0] * nextPOCAProjUnit[0],2)
507 + std::pow(nextEigenVals[1] * nextPOCAProjUnit[1],2)
508 + std::pow(nextEigenVals[2] * nextPOCAProjUnit[2],2));
513 float arcLenToFirstPoca = (firstPoca - firstCenter).
dot(firstAxis2);
514 float arcLenToNextPoca = (nextPoca - nextCenter ).
dot(nextAxis2);
522 float rMaxScaleFactor = 1.2;
524 if (lineDoca < rMaxScaleFactor * (firstPOCAVecProjEigen + nextPOCAVecProjEigen))
550 hitPairListPtr.push_back(
hit);
552 for(
const auto* hit2D :
hit->getHits())
566 for(
const auto& pair : nextEdgeMap) firstEdgeMap[pair.first] = pair.second;
581 const Eigen::Vector3f& P1,
const Eigen::Vector3f& u1,
582 Eigen::Vector3f& poca0,
583 Eigen::Vector3f& poca1,
584 Eigen::Vector3f& firstNextUnit)
const
587 Eigen::Vector3f w0 = P0 - P1;
593 float den(a * c - b * b);
596 if (
std::abs(den) > 10. * std::numeric_limits<float>::epsilon())
598 float arcLen0 = (b *
e - c * d) / den;
599 float arcLen1 = (a *
e - b * d) / den;
601 poca0 = P0 + arcLen0 * u0;
602 poca1 = P1 + arcLen1 * u1;
607 float arcLenToNextPoint = w0.dot(u0);
609 poca0 = P0 + arcLenToNextPoint * u0;
613 firstNextUnit = poca1 - poca0;
615 float docaDist = firstNextUnit.norm();
617 firstNextUnit = firstNextUnit.normalized();
625 float closest(std::numeric_limits<float>::max());
627 for(
const auto& hit3D : hitList)
629 Eigen::Vector3f refToHitVec = hit3D->getPosition() - refPoint;
630 float arcLenToHit = refToHitVec.dot(refVector);
632 if (arcLenToHit < closest)
634 nearestHit3D = hit3D;
635 closest = arcLenToHit;
645 float furthest(-std::numeric_limits<float>::max());
647 for(
const auto& hit3D : hitList)
649 Eigen::Vector3f refToHitVec = hit3D->getPosition() - refPoint;
650 float arcLenToHit = refToHitVec.dot(refVector);
652 if (arcLenToHit > furthest)
654 nearestHit3D = hit3D;
655 furthest = arcLenToHit;
std::vector< TH1F * > fNextEigenValueHists
Next Cluster eigen value.
std::vector< TH1F * > fFirstEigenValueHists
First Cluster eigen value.
void configure(fhicl::ParameterSet const &pset) override
Interface for configuring the particular algorithm tool.
constexpr auto dot(Vector const &a, Vector const &b)
Return cross product of two vectors.
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
float closestApproach(const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, Eigen::Vector3f &, Eigen::Vector3f &, Eigen::Vector3f &) const
~ClusterMergeAlg()
Destructor.
TH1F * fCosMaxFirstHist
Cos angle beteeen cylinder axis and edge.
void initializeHistograms(art::TFileDirectory &) override
Interface for initializing histograms if they are desired Note that the idea is to put hisgtograms in...
PrincipalComponentsAlg fPCAAlg
reco::PrincipalComponents & getSkeletonPCA()
float fTimeToProcess
Keep track of how long it took to run this algorithm.
TH1F * f2ndDocaArcLRatHist
arc length to POCA for DOCA second cluster
bool fOutputHistograms
Take the time to create and fill some histograms for diagnostics.
reco::Hit3DToEdgeMap & getHit3DToEdgeMap()
reco::HitPairListPtr & getHitPairListPtr()
TH1F * fRMaxFirstHist
radius of "cylinder" first cluster
TH1F * fGapRatHist
Ratio of gap and next proj eigen.
IClusterModAlg interface class definiton.
TH1F * fCosFirstAxisHist
Cos angle between vector between centers and first axis.
void ModifyClusters(reco::ClusterParametersList &) const override
Scan an input collection of clusters and modify those according to the specific implementing algorith...
TH1F * fProjEndPointRatHist
Ratio of projection to vector length.
float fMinEigenToProcess
Don't look anymore at clusters below this size.
const EigenValues & getEigenValues() const
bool mergeClusters(reco::ClusterParameters &, reco::ClusterParameters &) const
reco::PrincipalComponents & getFullPCA()
TH1F * fCosNextAxisHist
Cos angle between vector between centers and next axis.
const reco::ClusterHit3D * findFurthestHit3D(const Eigen::Vector3f &, const Eigen::Vector3f &, const reco::HitPairListPtr &) const
TH1F * f2ndTo1stProjEigenHist
arc length along vector between centers from next center to cylinder
TH1F * f1stTo2ndPosLenRatHist
Ratio of distance between centers and first proj eigen.
const Eigen::Vector3f & getAvePosition() const
ClusterMergeAlg(const fhicl::ParameterSet &)
Constructor.
TH1F * fRMaxNextHist
radius of "cylinder" next cluster
std::list< const reco::ClusterHit3D * > HitPairListPtr
void UpdateParameters(const reco::ClusterHit2D *hit)
bool fEnableMonitoring
Data members to follow.
TH1F * f1stTo2ndProjEigenHist
arc length along vector between centers from first center to cylinder
const reco::ClusterHit3D * findClosestHit3D(const Eigen::Vector3f &, const Eigen::Vector3f &, const reco::HitPairListPtr &) const
TH1F * fNumMergedClusters
How many clusters were merged?
TH1F * fProjEndPointLenHist
Projection of vector between the endpoints.
This header file defines the interface to a principal components analysis designed to be used within ...
bool linearClusters(reco::ClusterParameters &, reco::ClusterParameters &) const
float fMinTransEigenVal
Set a mininum allowed value for the transverse eigen values.
float getTimeToExecute() const override
If monitoring, recover the time to execute a particular function.
This provides an art tool interface definition for 3D Cluster algorithms.
TH1F * fAxesDocaHist
Closest distance between two primary axes.
TH1F * fGapRatToLenHist
Ratio of gap to distance between centers.
TH1F * fCosMaxNextHist
Cos angle beteeen cylinder axis and edge.
art::ServiceHandle< art::TFileService > tfs
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
process_name physics producers generator hPHist_pi physics producers generator P0
TH1F * fGapBetweenClusHist
Gap between clusters.
TH1F * f1stDocaArcLRatHist
arc length to POCA for DOCA first cluster
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
BEGIN_PROLOG could also be cout
TH1F * f1stTo2ndPosLenHist
Distance between cluster centers.
std::list< ClusterParameters > ClusterParametersList
const EigenVectors & getEigenVectors() const