Belle II Software development
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
19namespace 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
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
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
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.
~StandaloneCosmicsCollector()=default
Destructor.
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
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.
std::vector< const SpacePoint * > getSPTC()
Getter for the sorted list of SpacePoints used for the final fit which met the given requirements.
bool compareRads(const SpacePoint *a, const SpacePoint *b)
Compare function used by addSpacePoint to sort the member vector of SpacePoints m_spacePoints by the ...
std::pair< std::vector< double >, std::vector< double > > getResult()
Getter for the position and momentum seed resulting from the linear fit.
bool doLineFit(int minSPs)
Function performing the actual line fit via a principal component analysis method yielding a directio...
void setSortingMode(unsigned short index)
Set sorting mode used in addSpacePoints.
double getReducedChi2()
Getter for the final reduced chi squared value obtained for the set of SpacePoints used for the last ...
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
Abstract base class for different kinds of events.