LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
LArPcaHelper.cc
Go to the documentation of this file.
1 
12 
13 #include <Eigen/Dense>
14 
15 using namespace pandora;
16 
17 namespace lar_content
18 {
19 
20 template <typename T>
21 void 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 
33 void 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,
107  xiyi, yi2, yizi,
108  xizi, yizi, zi2;
109 
110  sig *= 1. / sumWeight;
111 
112  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigenMat(sig);
113 
114  if (eigenMat.info() != Eigen::ComputationInfo::Success)
115  {
116  std::cout << "LArPcaHelper::RunPca - decomposition failure, nThreeDHits = " << pointVector.size() << std::endl;
117  throw StatusCodeException(STATUS_CODE_INVALID_PARAMETER);
118  }
119 
120  typedef std::pair<float, size_t> EigenValColPair;
121  typedef std::vector<EigenValColPair> EigenValColVector;
122 
123  EigenValColVector eigenValColVector;
124  const auto &resultEigenMat(eigenMat.eigenvalues());
125  eigenValColVector.emplace_back(resultEigenMat(0), 0);
126  eigenValColVector.emplace_back(resultEigenMat(1), 1);
127  eigenValColVector.emplace_back(resultEigenMat(2), 2);
128 
129  std::sort(eigenValColVector.begin(), eigenValColVector.end(), [](const EigenValColPair &left, const EigenValColPair &right){return left.first > right.first;});
130 
131  // Get the eigen values
132  outputEigenValues = CartesianVector(eigenValColVector.at(0).first, eigenValColVector.at(1).first, eigenValColVector.at(2).first);
133 
134  // Get the principal axes
135  const Eigen::Matrix3f &eigenVecs(eigenMat.eigenvectors());
136 
137  for (const EigenValColPair &pair : eigenValColVector)
138  outputEigenVectors.emplace_back(eigenVecs(0, pair.second), eigenVecs(1, pair.second), eigenVecs(2, pair.second));
139 }
140 
141 //------------------------------------------------------------------------------------------------------------------------------------------
142 
143 template void LArPcaHelper::RunPca(const CartesianPointVector &, CartesianVector &, EigenValues &, EigenVectors &);
144 template void LArPcaHelper::RunPca(const CaloHitList &, CartesianVector &, EigenValues &, EigenVectors &);
145 
146 } // namespace lar_content
Float_t x
Definition: compare.C:6
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:112
pandora::CartesianVector EigenValues
Definition: LArPcaHelper.h:21
Float_t y
Definition: compare.C:6
Double_t z
Definition: plot.C:279
std::pair< const pandora::CartesianVector, double > WeightedPoint
Definition: LArPcaHelper.h:23
std::vector< WeightedPoint > WeightedPointVector
Definition: LArPcaHelper.h:24
Header file for the principal curve analysis helper class.
Header file for the object helper class.
Header file for the cluster helper class.
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
double weight
Definition: plottest35.C:25
std::vector< pandora::CartesianVector > EigenVectors
Definition: LArPcaHelper.h:22