Pandora
Pandora source code navigator
Loading...
Searching...
No Matches
LArPcaHelper.cc
Go to the documentation of this file.
1
12
13#include <Eigen/Dense>
14
15using namespace pandora;
16
17namespace lar_content
18{
19
20template <typename T>
21void LArPcaHelper::RunPca(const T &t, CartesianVector &centroid, EigenValues &outputEigenValues, EigenVectors &outputEigenVectors)
22{
23 WeightedPointVector weightedPointVector;
24
25 for (const auto &point : t)
26 weightedPointVector.push_back(std::make_pair(LArObjectHelper::TypeAdaptor::GetPosition(point), 1.));
27
28 return LArPcaHelper::RunPca(weightedPointVector, centroid, outputEigenValues, outputEigenVectors);
29}
30
31//------------------------------------------------------------------------------------------------------------------------------------------
32
33void LArPcaHelper::RunPca(const WeightedPointVector &pointVector, CartesianVector &centroid, EigenValues &outputEigenValues, EigenVectors &outputEigenVectors)
34{
35 // The steps are:
36 // 1) do a mean normalization of the input vec points
37 // 2) compute the covariance matrix
38 // 3) run the SVD
39 // 4) extract the eigen vectors and values
40
41 // Run through the point vector and get the mean position of all points
42 if (pointVector.empty())
43 {
44 std::cout << "LArPcaHelper::RunPca - no three dimensional hits provided" << std::endl;
45 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
46 }
47
48 double meanPosition[3] = {0., 0., 0.};
49 double sumWeight(0.);
50
51 for (const WeightedPoint &weightedPoint : pointVector)
52 {
53 const CartesianVector &point(weightedPoint.first);
54 const double weight(weightedPoint.second);
55
56 if (weight < 0.)
57 {
58 std::cout << "LArPcaHelper::RunPca - negative weight found" << std::endl;
59 throw StatusCodeException(STATUS_CODE_NOT_ALLOWED);
60 }
61
62 meanPosition[0] += static_cast<double>(point.GetX()) * weight;
63 meanPosition[1] += static_cast<double>(point.GetY()) * weight;
64 meanPosition[2] += static_cast<double>(point.GetZ()) * weight;
65 sumWeight += weight;
66 }
67
68 if (std::fabs(sumWeight) < std::numeric_limits<double>::epsilon())
69 {
70 std::cout << "LArPcaHelper::RunPca - sum of weights is zero" << std::endl;
71 throw StatusCodeException(STATUS_CODE_NOT_FOUND);
72 }
73
74 meanPosition[0] /= sumWeight;
75 meanPosition[1] /= sumWeight;
76 meanPosition[2] /= sumWeight;
77 centroid = CartesianVector(meanPosition[0], meanPosition[1], meanPosition[2]);
78
79 // Define elements of our covariance matrix
80 double xi2(0.);
81 double xiyi(0.);
82 double xizi(0.);
83 double yi2(0.);
84 double yizi(0.);
85 double zi2(0.);
86
87 for (const WeightedPoint &weightedPoint : pointVector)
88 {
89 const CartesianVector &point(weightedPoint.first);
90 const double weight(weightedPoint.second);
91 const double x(static_cast<double>((point.GetX()) - meanPosition[0]));
92 const double y(static_cast<double>((point.GetY()) - meanPosition[1]));
93 const double z(static_cast<double>((point.GetZ()) - meanPosition[2]));
94
95 xi2 += x * x * weight;
96 xiyi += x * y * weight;
97 xizi += x * z * weight;
98 yi2 += y * y * weight;
99 yizi += y * z * weight;
100 zi2 += z * z * weight;
101 }
102
103 // Using Eigen package
104 Eigen::Matrix3f sig;
105
106 sig << xi2, xiyi, xizi, xiyi, yi2, yizi, xizi, yizi, zi2;
107
108 sig *= 1. / sumWeight;
109
110 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigenMat(sig);
111
112 if (eigenMat.info() != Eigen::ComputationInfo::Success)
113 {
114 std::cout << "LArPcaHelper::RunPca - decomposition failure, nThreeDHits = " << pointVector.size() << std::endl;
115 throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
116 }
117
118 typedef std::pair<float, size_t> EigenValColPair;
119 typedef std::vector<EigenValColPair> EigenValColVector;
120
121 EigenValColVector eigenValColVector;
122 const auto &resultEigenMat(eigenMat.eigenvalues());
123 eigenValColVector.emplace_back(resultEigenMat(0), 0);
124 eigenValColVector.emplace_back(resultEigenMat(1), 1);
125 eigenValColVector.emplace_back(resultEigenMat(2), 2);
126
127 std::sort(eigenValColVector.begin(), eigenValColVector.end(),
128 [](const EigenValColPair &left, const EigenValColPair &right) { return left.first > right.first; });
129
130 // Get the eigen values
131 outputEigenValues = CartesianVector(eigenValColVector.at(0).first, eigenValColVector.at(1).first, eigenValColVector.at(2).first);
132
133 // Get the principal axes
134 const Eigen::Matrix3f &eigenVecs(eigenMat.eigenvectors());
135
136 for (const EigenValColPair &pair : eigenValColVector)
137 outputEigenVectors.emplace_back(eigenVecs(0, pair.second), eigenVecs(1, pair.second), eigenVecs(2, pair.second));
138}
139
140//------------------------------------------------------------------------------------------------------------------------------------------
141
142template void LArPcaHelper::RunPca(const CartesianPointVector &, CartesianVector &, EigenValues &, EigenVectors &);
143template void LArPcaHelper::RunPca(const CaloHitList &, CartesianVector &, EigenValues &, EigenVectors &);
144
145} // namespace lar_content
Header file for the cluster helper class.
Header file for the object helper class.
Header file for the principal curve analysis helper class.
static pandora::CartesianVector GetPosition(const T &t)
Get the associated position.
std::vector< WeightedPoint > WeightedPointVector
std::vector< pandora::CartesianVector > EigenVectors
std::pair< const pandora::CartesianVector, double > WeightedPoint
static void RunPca(const T &t, pandora::CartesianVector &centroid, EigenValues &outputEigenValues, EigenVectors &outputEigenVectors)
Run principal component analysis using input calo hits (TPC_VIEW_U,V,W or TPC_3D; all treated as 3D p...
CartesianVector class.
float GetX() const
Get the cartesian x coordinate.
float GetZ() const
Get the cartesian z coordinate.
float GetY() const
Get the cartesian y coordinate.
StatusCodeException class.
std::vector< CartesianVector > CartesianPointVector
MANAGED_CONTAINER< const CaloHit * > CaloHitList