Belle II Software  release-08-01-10
StandaloneCosmicsCollector.h
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #pragma once
9 
10 #include <vector>
11 #include <utility>
12 #include <Eigen/Dense>
13 #include <Eigen/Geometry>
14 
15 #include <framework/datastore/StoreArray.h>
16 
17 #include <tracking/spacePointCreation/SpacePoint.h>
18 
19 namespace Belle2 {
34 
35  public:
38 
41 
42 
51  void setSortingMode(unsigned short index)
52  {
53  if ((index < 1) or (index > 3)) {
54  B2FATAL("Invalid sorting mode chosen! You used " << m_sortingMode
55  << ". Must be one of 1 (by radius), 2 (by x) or 3 (by y).");
56  }
57  m_sortingMode = index;
58  }
59 
66  void addSpacePoints(std::vector<StoreArray<SpacePoint>> SPs)
67  {
68  m_spacePoints.clear();
69  m_direction.clear();
70  m_start.clear();
71  m_reducedChi2 = 10;
72  for (auto& spArray : SPs) {
73  for (auto& sp : spArray) {
74  addSpacePoint(&sp);
75  }
76  }
77  }
78 
79 
92  bool doFit(double qualityCut, int maxRejected, int minSPs)
93  {
94  bool fitting = true;
95  int rejected = 0;
96 
97  // cppcheck-suppress knownConditionTrueFalse
98  while (m_reducedChi2 > qualityCut && fitting) {
99  fitting = doLineFit(minSPs);
100  if (not fitting) {return false;}
101  if (m_reducedChi2 > qualityCut) {
102  B2DEBUG(20, "Refitting without sp with index " << m_largestChi2.second
103  << " and chi2 contribution " << m_largestChi2.first << "...");
104  m_spacePoints.erase(m_spacePoints.begin() + m_largestChi2.second);
105  rejected++;
106  }
107  if (rejected > maxRejected) { B2DEBUG(20, "Rejected " << rejected << "!"); return false; }
108  }
109  return fitting;
110  }
111 
112 
122  std::pair<std::vector<double>, std::vector<double>> getResult()
123  {
124  return std::pair<std::vector<double>, std::vector<double>> (m_start, m_direction);
125  }
126 
127 
134  std::vector<const SpacePoint*> getSPTC()
135  {
136  return m_spacePoints;
137  }
138 
139 
145  double getReducedChi2()
146  {
147  return m_reducedChi2;
148  }
149 
150 
151  private:
152 
158  void addSpacePoint(const SpacePoint* SP)
159  {
160  auto forwardIt = std::lower_bound(m_spacePoints.begin(), m_spacePoints.end(), SP,
161  [this](const SpacePoint * lhs, const SpacePoint * rhs)
162  -> bool { return this->compareRads(lhs, rhs); });
163  m_spacePoints.insert(forwardIt, SP);
164  }
165 
166 
179  bool doLineFit(int minSPs)
180  {
181  int nHits = m_spacePoints.size();
182  B2DEBUG(20, "Trying fit with " << nHits << " hits...");
183  // Aborting fit and returning false if the minimal number of SpacePoints required is not met.
184  if (nHits < minSPs) { B2DEBUG(20, "Only " << nHits << " hits!"); return false; };
185 
186  Eigen::Matrix<double, 3, 1> average = Eigen::Matrix<double, 3, 1>::Zero(3, 1);
187  Eigen::Matrix<double, Eigen::Dynamic, 3> data = Eigen::Matrix<double, Eigen::Dynamic, 3>::Zero(nHits, 3);
188  Eigen::Matrix<double, Eigen::Dynamic, 3> P = Eigen::Matrix<double, Eigen::Dynamic, 3>::Zero(nHits, 3);
189 
190  for (const auto& sp : m_spacePoints) {
191  average(0) += sp->getPosition().X();
192  average(1) += sp->getPosition().Y();
193  average(2) += sp->getPosition().Z();
194  }
195  average *= 1. / nHits;
196 
197  int index = 0;
198  for (const auto& sp : m_spacePoints) {
199  data(index, 0) = sp->getPosition().X();
200  data(index, 1) = sp->getPosition().Y();
201  data(index, 2) = sp->getPosition().Z();
202 
203  P(index, 0) = sp->getPosition().X() - average(0);
204  P(index, 1) = sp->getPosition().Y() - average(1);
205  P(index, 2) = sp->getPosition().Z() - average(2);
206  index++;
207  }
208 
209  //Principal component analysis
210  Eigen::Matrix<double, 3, 3> product = P.transpose() * P;
211 
212  Eigen::EigenSolver<Eigen::Matrix<double, 3, 3>> eigencollection(product);
213  Eigen::Matrix<double, 3, 1> eigenvalues = eigencollection.eigenvalues().real();
214  Eigen::Matrix<std::complex<double>, 3, 3> eigenvectors = eigencollection.eigenvectors();
215  Eigen::Matrix<double, 3, 1>::Index maxRow, maxCol;
216  eigenvalues.maxCoeff(&maxRow, &maxCol);
217 
218  Eigen::Matrix<double, 3, 1> e = eigenvectors.col(maxRow).real();
219 
220  // Setting starting point to the data point with larges radius
221  Eigen::Matrix<double, 3, 1> start = data.row(nHits - 1).transpose();
222  Eigen::Matrix<double, 3, 1> second = data.row(nHits - 2).transpose();
223  m_start = {start(0), start(1), start(2)};
224  // Setting direction vector towards the inside of the detector
225  m_direction = {e(0), e(1), e(2)};
226  Eigen::Hyperplane<double, 3> plane(e.normalized(), start);
227  Eigen::ParametrizedLine<double, 3> line(second, e.normalized());
228  double factor = line.intersectionParameter(plane);
229  if (factor > 0) {
230  m_direction = { -e(0), -e(1), -e(2)};
231  }
232 
233  // Resorting SpacePoints based on the obtained line fit result.
234  resortHits();
235 
236  // Calculating reduced chi2 value of the line fit using the distances of the SpacePoints to the obtained line and
237  // keeping the m_spacePoints index and the chi2 contribution of the SpacePoint with the largest contribution.
238  m_reducedChi2 = 0;
239  m_largestChi2 = std::pair<double, int>(0., 0);
240  int largestChi2_index = 0;
241  for (const auto& sp : m_spacePoints) {
242  Eigen::Matrix<double, 3, 1> origin(sp->getPosition().X(), sp->getPosition().Y(), sp->getPosition().Z());
243  plane = Eigen::Hyperplane<double, 3>(e.normalized(), origin);
244 
245  Eigen::Matrix<double, 3, 1> point = line.intersectionPoint(plane);
246 
247  double delta_chi2 = (point - origin).transpose() * (point - origin);
248  m_reducedChi2 += delta_chi2;
249 
250  if (delta_chi2 > m_largestChi2.first) {
251  m_largestChi2.first = delta_chi2;
252  m_largestChi2.second = largestChi2_index;
253  }
254  largestChi2_index++;
255  }
256 
257  m_reducedChi2 *= 1. / nHits;
258  B2DEBUG(20, "Reduced chi2 result is " << m_reducedChi2 << "...");
259  return true;
260  }
261 
262 
270  bool compareRads(const SpacePoint* a, const SpacePoint* b)
271  {
272  if (m_sortingMode == 1) {
273  double radA = a->getPosition().X() * a->getPosition().X() + a->getPosition().Y() * a->getPosition().Y();
274  double radB = b->getPosition().X() * b->getPosition().X() + b->getPosition().Y() * b->getPosition().Y();
275  return radA < radB;
276  } else if (m_sortingMode == 2) {
277  double xA = a->getPosition().X();
278  double xB = b->getPosition().X();
279  return xA < xB;
280  } else if (m_sortingMode == 3) {
281  double yA = a->getPosition().Y();
282  double yB = b->getPosition().Y();
283  return yA < yB;
284  } else {
285  B2FATAL("Invalid sorting mode chosen! You used " << m_sortingMode
286  << ". Must be one of 1 (by radius), 2 (by x) or 3 (by y).");
287  }
288  }
289 
290 
297  void resortHits()
298  {
299  std::vector<const SpacePoint*> sortedSPs;
300  for (auto& SP : m_spacePoints) {
301  auto forwardIt = std::lower_bound(sortedSPs.begin(), sortedSPs.end(), SP,
302  [this](const SpacePoint * lhs, const SpacePoint * rhs) -> bool {
303  return this->comparePars(lhs, rhs);
304  });
305  sortedSPs.insert(forwardIt, SP);
306  }
307  m_spacePoints = sortedSPs;
308  }
309 
310 
318  bool comparePars(const SpacePoint* a, const SpacePoint* b)
319  {
320  Eigen::Matrix<double, 3, 1> posA(a->getPosition().X(), a->getPosition().Y(), a->getPosition().Z());
321  Eigen::Matrix<double, 3, 1> posB(b->getPosition().X(), b->getPosition().Y(), b->getPosition().Z());
322 
323  Eigen::Matrix<double, 3, 1> direction(m_direction[0], m_direction[1], m_direction[2]);
324  Eigen::Matrix<double, 3, 1> origin(m_start[0], m_start[1], m_start[2]);
325 
326  Eigen::ParametrizedLine<double, 3> line(origin, direction.normalized());
327  Eigen::Hyperplane<double, 3> planeA(direction.normalized(), posA);
328  Eigen::Hyperplane<double, 3> planeB(direction.normalized(), posB);
329 
330  double parA = line.intersectionParameter(planeA);
331  double parB = line.intersectionParameter(planeB);
332  return parA < parB;
333  }
334 
335 
337  std::vector<const SpacePoint*> m_spacePoints;
338 
344  unsigned short m_sortingMode = 1;
345 
350  double m_reducedChi2 = 10;
351 
358  std::pair<double, int> m_largestChi2 = std::pair<double, int>(0., 0);
359 
361  std::vector<double> m_start {0., 0., 0.};
362 
364  std::vector<double> m_direction {0., 0., 0.};
365  };
367 }
368 
SpacePoint typically is build from 1 PXDCluster or 1-2 SVDClusters.
Definition: SpacePoint.h:42
Track finding algorithm class for linear tracks produced by cosmics in the VXD without magnetic field...
void resortHits()
Function to resort the member vector of SpacePoints m_spacePoints based on the members m_start and m_...
unsigned short m_sortingMode
Storing identifier for sorting algorithm to be used for the function addSpacePoint.
void addSpacePoints(std::vector< StoreArray< SpacePoint >> SPs)
Function to initialize the track finder anew for an event with its set of SpacePoints provided via th...
~StandaloneCosmicsCollector()=default
Destructor.
std::vector< const SpacePoint * > getSPTC()
Getter for the sorted list of SpacePoints used for the final fit which met the given requirements.
StandaloneCosmicsCollector()=default
Constructor.
std::vector< double > m_direction
Direction of the line obtained by the last performed line fit.
std::pair< double, int > m_largestChi2
Pair containing the index of the vector m_spacePoints for the SpacePoint with the largest contributio...
std::vector< double > m_start
Start point obtained by the last performed line fit.
void addSpacePoint(const SpacePoint *SP)
Adding single SpacePoint to the sorted member vector m_spacePoints, beginning with the SpacePoint wit...
bool comparePars(const SpacePoint *a, const SpacePoint *b)
Comparison function to compare two SpacePoints based on the distance between the start point of the f...
bool doFit(double qualityCut, int maxRejected, int minSPs)
Function to perform the actual line fit based on the StoreArray of SpacePoints provided.
std::vector< const SpacePoint * > m_spacePoints
Member vector of SpacePoints holding the SpacePoints considered for the track candidate.
double m_reducedChi2
Member variable containing the reduced chi squared value of the current line fit.
bool compareRads(const SpacePoint *a, const SpacePoint *b)
Compare function used by addSpacePoint to sort the member vector of SpacePoints m_spacePoints by the ...
bool doLineFit(int minSPs)
Function performing the actual line fit via a principal component analysis methode yielding a directi...
void setSortingMode(unsigned short index)
Set sorting mode used in addSpacePoints.
std::pair< std::vector< double >, std::vector< double > > getResult()
Getter for the position and momentum seed resulting from the linear fit.
double getReducedChi2()
Getter for the final reduced chi squared value obtained for the set of SpacePoints used for the last ...
Abstract base class for different kinds of events.