28 #include <Eigen/Dense> 52 m_detector = lar::providerFrom<detinfo::DetectorPropertiesService>();
56 const Eigen::Vector3f& axisDir,
58 Eigen::Vector3f& poca,
70 double wirePos[3] = {0.,0.,0.};
81 Eigen::Vector3f wVec(axisPos(0)-wirePos[0], axisPos(1)-wirePos[1], axisPos(2)-wirePos[2]);
84 float a(axisDir.dot(axisDir));
85 float b(axisDir.dot(wireDir));
86 float c(wireDir.dot(wireDir));
87 float d(axisDir.dot(wVec));
88 float e(wireDir.dot(wVec));
95 arcLenAxis = (b*
e - c*
d) / den;
96 arcLenWire = (a*
e - b*
d) / den;
100 mf::LogDebug(
"Cluster3D") <<
"** Parallel lines, need a solution here" << std::endl;
106 poca = Eigen::Vector3f(wirePos[0] + arcLenWire * wireDir(0),
107 wirePos[1] + arcLenWire * wireDir(1),
108 wirePos[2] + arcLenWire * wireDir(2));
109 Eigen::Vector3f axisPocaPos(axisPos[0] + arcLenAxis * axisDir(0),
110 axisPos[1] + arcLenAxis * axisDir(1),
111 axisPos[2] + arcLenAxis * axisDir(2));
113 float deltaX(poca(0) - axisPocaPos(0));
114 float deltaY(poca(1) - axisPocaPos(1));
115 float deltaZ(poca(2) - axisPocaPos(2));
116 float doca2(deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ);
186 int maxIterations(3);
190 maxRange = sclFctr * 0.5*(maxRange+aveDoca);
193 int totalRejects(numRejHits);
194 int maxRejects(0.4*hitPairVector.size());
197 while(maxIterations-- && numRejHits > 0 && totalRejects < maxRejects)
231 float meanPos[] = {0.,0.,0.};
232 float meanWeightSum(0.);
236 float minimumDeltaPeakSig(0.00001);
242 std::vector<float> hitChiSquareVec;
244 hitChiSquareVec.resize(hitPairVector.size());
246 std::transform(hitPairVector.begin(),hitPairVector.end(),hitChiSquareVec.begin(),[](
const auto&
hit){
return hit->getHitChiSquare();});
247 std::sort(hitChiSquareVec.begin(),hitChiSquareVec.end());
249 size_t numToKeep = 0.8 * hitChiSquareVec.size();
251 hitChiSquareVec.resize(numToKeep);
253 float aveValue = std::accumulate(hitChiSquareVec.begin(),hitChiSquareVec.end(),float(0.)) /
float(hitChiSquareVec.size());
254 float rms = std::sqrt(std::inner_product(hitChiSquareVec.begin(),hitChiSquareVec.end(), hitChiSquareVec.begin(), 0.,std::plus<>(),[aveValue](
const auto&
left,
const auto&
right){
return (
left - aveValue) * (
right - aveValue);}) /
float(hitChiSquareVec.size()));
256 minimumDeltaPeakSig =
std::max(minimumDeltaPeakSig, aveValue - rms);
260 for (
const auto&
hit : hitPairVector)
267 meanPos[0] +=
hit->getPosition()[0] *
weight;
268 meanPos[1] +=
hit->getPosition()[1] *
weight;
269 meanPos[2] +=
hit->getPosition()[2] *
weight;
275 meanPos[0] /= meanWeightSum;
276 meanPos[1] /= meanWeightSum;
277 meanPos[2] /= meanWeightSum;
289 for (
const auto&
hit : hitPairVector)
294 float x = (
hit->getPosition()[0] - meanPos[0]) * weight;
295 float y = (
hit->getPosition()[1] - meanPos[1]) * weight;
296 float z = (
hit->getPosition()[2] - meanPos[2]) * weight;
298 weightSum += weight*
weight;
311 sig << xi2, xiyi, xizi,
317 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigenMat(sig);
319 if (eigenMat.info() == Eigen::ComputationInfo::Success)
321 using eigenValColPair = std::pair<float,size_t>;
322 std::vector<eigenValColPair> eigenValColVec;
324 eigenValColVec.push_back(eigenValColPair(eigenMat.eigenvalues()(0),0));
325 eigenValColVec.push_back(eigenValColPair(eigenMat.eigenvalues()(1),1));
326 eigenValColVec.push_back(eigenValColPair(eigenMat.eigenvalues()(2),2));
328 std::sort(eigenValColVec.begin(),eigenValColVec.end(),[](
const eigenValColPair&
left,
const eigenValColPair&
right){
return left.first >
right.first;});
332 float recobEigenVals[] = {eigenValColVec[0].first, eigenValColVec[1].first, eigenValColVec[2].first};
336 Eigen::Matrix3f eigenVecs(eigenMat.eigenvectors());
338 for(
const auto& pair : eigenValColVec)
340 std::vector<float> tempVec = {eigenVecs(0,pair.second),eigenVecs(1,pair.second),eigenVecs(2,pair.second)};
341 recobEigenVecs.push_back(tempVec);
349 mf::LogDebug(
"Cluster3D") <<
"PCA decompose failure, numPairs = " << numPairsInt << std::endl;
370 float aveHitDoca(0.);
371 Eigen::Vector3f avePosUpdate(0.,0.,0.);
382 std::vector<Eigen::Vector3f> hitPosVec;
385 for (
const auto& hit3D : hitPairVector)
388 for (
const auto&
hit : hit3D->getHits())
397 double wirePosArr[3] = {0.,0.,0.};
400 Eigen::Vector3f wireCenter(wirePosArr[0], wirePosArr[1], wirePosArr[2]);
404 float hitPeak(
hit->getHit().PeakTime());
409 Eigen::Vector3f xAxis(1.,0.,0.);
410 Eigen::Vector3f planeNormal = xAxis.cross(wireDirVec);
412 float docaInPlane(wirePos[0] - avePosition[0]);
413 float arcLenToPlane(0.);
414 float cosAxisToPlaneNormal = axisDirVec.dot(planeNormal);
416 Eigen::Vector3f axisPlaneIntersection = wirePos;
417 Eigen::Vector3f hitPosTVec = wirePos;
419 if (fabs(cosAxisToPlaneNormal) > 0.)
421 Eigen::Vector3f deltaPos = wirePos - avePosition;
423 arcLenToPlane = deltaPos.dot(planeNormal) / cosAxisToPlaneNormal;
424 axisPlaneIntersection = avePosition + arcLenToPlane * axisDirVec;
425 docaInPlane = wirePos[0] - axisPlaneIntersection[0];
427 Eigen::Vector3f axisToInter = axisPlaneIntersection - wirePos;
428 float arcLenToDoca = axisToInter.dot(wireDirVec);
430 hitPosTVec += arcLenToDoca * wireDirVec;
434 Eigen::Vector3f wVec = avePosition - wirePos;
437 float a(axisDirVec.dot(axisDirVec));
438 float b(axisDirVec.dot(wireDirVec));
439 float c(wireDirVec.dot(wireDirVec));
440 float d(axisDirVec.dot(wVec));
441 float e(wireDirVec.dot(wVec));
443 float den(a*c - b*b);
450 arcLen1 = (b*
e - c*
d) / den;
451 arcLen2 = (a*
e - b*
d) / den;
455 mf::LogDebug(
"Cluster3D") <<
"** Parallel lines, need a solution here" << std::endl;
466 Eigen::Vector3f hitPos = wirePos + arcLen2 * wireDirVec;
467 Eigen::Vector3f axisPos = avePosition + arcLen1 * axisDirVec;
468 float deltaX = hitPos(0) - axisPos(0);
469 float deltaY = hitPos(1) - axisPos(1);
470 float deltaZ = hitPos(2) - axisPos(2);
471 float doca2 = deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ;
472 float doca = sqrt(doca2);
476 aveHitDoca += fabs(docaInPlane);
491 hit->setDocaToAxis(fabs(docaInPlane));
492 hit->setArcLenToPoca(arcLenToPlane);
496 if (
hit->getStatusBits() & 0x80)
503 avePosUpdate += hitPosTVec;
505 hitPosVec.push_back(hitPosTVec);
512 avePosUpdate[0] /= float(nHits);
513 avePosUpdate[1] /= float(nHits);
514 avePosUpdate[2] /= float(nHits);
517 aveHitDoca /= float(nHits);
521 avePosition = avePosUpdate;
525 for(
auto& hitPos : hitPosVec)
528 float x = hitPos[0] - avePosition[0];
529 float y = hitPos[1] - avePosition[1];
530 float z = hitPos[2] - avePosition[2];
545 sig << xi2, xiyi, xizi,
549 sig *= 1./(nHits - 1);
551 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigenMat(sig);
553 if (eigenMat.info() == Eigen::ComputationInfo::Success)
555 using eigenValColPair = std::pair<float,size_t>;
556 std::vector<eigenValColPair> eigenValColVec;
558 eigenValColVec.push_back(eigenValColPair(eigenMat.eigenvalues()(0),0));
559 eigenValColVec.push_back(eigenValColPair(eigenMat.eigenvalues()(1),1));
560 eigenValColVec.push_back(eigenValColPair(eigenMat.eigenvalues()(2),2));
562 std::sort(eigenValColVec.begin(),eigenValColVec.end(),[](
const eigenValColPair&
left,
const eigenValColPair&
right){
return left.first >
right.first;});
566 float recobEigenVals[] = {eigenValColVec[0].first, eigenValColVec[1].first, eigenValColVec[2].first};
570 Eigen::Matrix3f eigenVecs(eigenMat.eigenvectors());
572 for(
const auto& pair : eigenValColVec)
574 std::vector<float> tempVec = {eigenVecs(0,pair.second),eigenVecs(1,pair.second),eigenVecs(2,pair.second)};
575 recobEigenVecs.push_back(tempVec);
579 float avePosToSave[] = {float(avePosition[0]),float(avePosition[1]),float(avePosition[2])};
586 mf::LogDebug(
"Cluster3D") <<
"PCA decompose failure, numPairs = " << nHits << std::endl;
608 for (
const auto* clusterHit3D : hitPairVector)
611 clusterHit3D->clearStatusBits(0x80);
615 Eigen::Vector3f clusPos(clusterHit3D->getPosition()[0],clusterHit3D->getPosition()[1],clusterHit3D->getPosition()[2]);
618 Eigen::Vector3f clusToHitVec = clusPos - avePosition;
621 float arclenToPoca = clusToHitVec.dot(axisDirVec);
624 Eigen::Vector3f docaPos = avePosition + arclenToPoca * axisDirVec;
627 Eigen::Vector3f docaPosToClusPos = clusPos - docaPos;
628 float docaToAxis = docaPosToClusPos.norm();
630 aveDoca3D += docaToAxis;
633 clusterHit3D->setDocaToAxis(docaToAxis);
634 clusterHit3D->setArclenToPoca(arclenToPoca);
638 aveDoca3D /= float(hitPairVector.size());
660 float aveHitDoca(0.);
663 for (
const auto*
hit : hit2DListPtr)
673 double wirePosArr[3] = {0.,0.,0.};
676 Eigen::Vector3f wireCenter(wirePosArr[0], wirePosArr[1], wirePosArr[2]);
680 Eigen::Vector3f wirePos(
hit->getXPosition(), wireCenter[1], wireCenter[2]);
683 Eigen::Vector3f xAxis(1.,0.,0.);
684 Eigen::Vector3f planeNormal = xAxis.cross(wireDirVec);
686 float arcLenToPlane(0.);
687 float docaInPlane(wirePos[0] - avePosition[0]);
688 float cosAxisToPlaneNormal = axisDirVec.dot(planeNormal);
690 Eigen::Vector3f axisPlaneIntersection = wirePos;
693 if (fabs(cosAxisToPlaneNormal) > 0.)
695 Eigen::Vector3f deltaPos = wirePos - avePosition;
697 arcLenToPlane =
std::min(
float(deltaPos.dot(planeNormal) / cosAxisToPlaneNormal), maxArcLen);
698 axisPlaneIntersection = avePosition + arcLenToPlane * axisDirVec;
700 Eigen::Vector3f axisToInter = axisPlaneIntersection - wirePos;
701 float arcLenToDoca = axisToInter.dot(wireDirVec);
704 if (fabs(arcLenToDoca) > wire_geom.
HalfL()) arcLenToDoca = wire_geom.
HalfL();
709 Eigen::Vector3f docaVec = axisPlaneIntersection - (wirePos + arcLenToDoca * wireDirVec);
710 docaInPlane = docaVec.norm();
713 aveHitDoca += fabs(docaInPlane);
716 hit->setDocaToAxis(fabs(docaInPlane));
717 hit->setArcLenToPoca(arcLenToPlane);
721 aveHitDoca /= float(hit2DListPtr.size());
730 float maxDocaAllowed)
const 740 for (
const auto& hit3D : hitPairVector)
743 for (
const auto&
hit : hit3D->getHits())
746 hit->clearStatusBits(0x80);
748 if (
hit->getDocaToAxis() > maxDocaAllowed)
750 hit->setStatusBit(0x80);
761 float maxDocaAllowed)
const 775 for (
const auto* clusterHit3D : hitPairVector)
778 clusterHit3D->clearStatusBits(0x80);
782 Eigen::Vector3f clusPos(clusterHit3D->getPosition()[0],clusterHit3D->getPosition()[1],clusterHit3D->getPosition()[2]);
785 Eigen::Vector3f clusToHitVec = clusPos - avePosition;
788 float arclenToPoca = clusToHitVec.dot(axisDirVec);
791 Eigen::Vector3f docaPos = avePosition + arclenToPoca * axisDirVec;
794 Eigen::Vector3f docaPosToClusPos = clusPos - docaPos;
795 float docaToAxis = docaPosToClusPos.norm();
798 clusterHit3D->setDocaToAxis(docaToAxis);
799 clusterHit3D->setArclenToPoca(arclenToPoca);
802 if (clusterHit3D->getDocaToAxis() > maxDocaAllowed)
804 clusterHit3D->setStatusBit(0x80);
float m_parallel
means lines are parallel
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
void setAveHitDoca(double doca) const
void PCAAnalysis_2D(const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, bool updateAvePos=false) const
std::list< const reco::ClusterHit2D * > Hit2DListPtr
export some data structure definitions
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
int PCAAnalysis_reject3DOutliers(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca, float aveHitDoca) const
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
PrincipalComponentsAlg(fhicl::ParameterSet const &pset)
Constructor.
bool operator()(const reco::ClusterHit3D *left, const reco::ClusterHit3D *right)
geo::Geometry * m_geometry
geo::WireID WireID() const
Initial tdc tick for hit.
void reconfigure(fhicl::ParameterSet const &pset)
a handler for the case where the algorithm control parameters are to be reset
int PCAAnalysis_reject2DOutliers(const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, float aveHitDoca) const
Declaration of signal hit object.
CryostatID_t Cryostat
Index of cryostat.
const float * getAvePosition() const
float getDocaToAxis() const
T get(std::string const &key) const
const recob::Hit & getHit() const
std::list< const reco::ClusterHit3D * > HitPairListPtr
std::vector< std::vector< float > > EigenVectors
PlaneID_t Plane
Index of the plane within its TPC.
void getHit2DPocaToAxis(const Eigen::Vector3f &axisPos, const Eigen::Vector3f &axisDir, const reco::ClusterHit2D *hit2D, Eigen::Vector3f &poca, float &arcLenAxis, float &arcLenWire, float &doca)
This is used to get the poca, doca and arclen along cluster axis to 2D hit.
Vector Direction() const
Returns the wire direction as a norm-one vector.
Detector simulation of raw signals on wires.
This header file defines the interface to a principal components analysis designed to be used within ...
Encapsulate the geometry of a wire.
double HalfL() const
Returns half the length of the wire [cm].
virtual double ConvertTicksToX(double ticks, int p, int t, int c) const =0
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
float PeakTime() const
Time of the signal peak, in tick units.
Utility object to perform functions of association.
bool operator()(const reco::ClusterHit3D *left, const reco::ClusterHit3D *right)
const float * getEigenValues() const
Encapsulate the construction of a single detector plane.
const float getAveHitDoca() const
virtual ~PrincipalComponentsAlg()
Destructor.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
float getArclenToPoca() const
bool operator()(const reco::ClusterHit3D *left, const reco::ClusterHit3D *right)
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
TPCID_t TPC
Index of the TPC within its cryostat.
void PCAAnalysis_calc2DDocas(const reco::Hit2DListPtr &hit2DVector, const reco::PrincipalComponents &pca) const
const detinfo::DetectorProperties * m_detector
art framework interface to geometry description
const EigenVectors & getEigenVectors() const
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
Returns the specified wire.
void PCAAnalysis(const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, float doca3DScl=3.) const
Run the Principal Components Analysis.