Belle II Software development
FacetFitter.cc
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#include <tracking/trackFindingCDC/fitting/FacetFitter.h>
9
10#include <tracking/trackingUtilities/eventdata/hits/CDCFacet.h>
11#include <tracking/trackingUtilities/eventdata/hits/CDCWireHit.h>
12#include <tracking/trackingUtilities/geometry/UncertainParameterLine2D.h>
13#include <tracking/trackingUtilities/geometry/ParameterLine2D.h>
14#include <tracking/trackingUtilities/geometry/Vector2D.h>
15
16#include <tracking/trackingUtilities/numerics/EigenView.h>
17
18#include <Eigen/Core>
19
20#include <Math/Functor.h>
21#include <Math/BrentMinimizer1D.h>
22
23using namespace Belle2;
24using namespace TrackFindingCDC;
25using namespace TrackingUtilities;
26
27namespace {
28
29 template<int N>
30 Vector2D getCenterForwardDirection(const Matrix<double, N, 3>& xyl)
31 {
33 Vector2D coordinate(xyl(N - 1, 0) - xyl(0, 0), xyl(N - 1, 1) - xyl(0, 1));
34 return coordinate.unit();
35 }
36
37 template<int N>
38 Vector2D getTangentialForwardDirection(const Matrix<double, N, 3>& xyl)
39 {
41 Vector2D fromPos(xyl(0, 0), xyl(0, 1));
42 double fromL = xyl(0, 2);
43
44 Vector2D toPos(xyl(N - 1, 0), xyl(N - 1, 1));
45 double toL = xyl(N - 1, 2);
46
47 ParameterLine2D tangentLine = ParameterLine2D::touchingCircles(fromPos, fromL, toPos, toL);
48 Vector2D coordinate = tangentLine.tangential();
49 return coordinate.unit();
50 }
51
52 template<int N>
53 void rotate(Vector2D coordinate, Matrix<double, N, 3>& xyl)
54 {
55 Matrix<double, 3, 3> rot = Matrix<double, 3, 3>::Identity();
56 rot(0, 0) = coordinate.x();
57 rot(0, 1) = -coordinate.y();
58 rot(1, 0) = coordinate.y();
59 rot(1, 1) = coordinate.x();
60 rot(2, 2) = 1; // Drift length remains the same.
61 xyl = xyl * rot;
62 }
63
64 void unrotate(Vector2D coordinate, Vector2D& vec)
65 {
66 // Inverse rotation is accomblished by taking the angle to the opposite
67 // which is equivalent to flipping the second coordinate.
68 vec = vec.passiveRotatedBy(coordinate.flippedSecond());
69 }
70
71 Eigen::Vector2d fitPhiVecZeroSteps(const Eigen::Matrix<double, 3, 3>& xylCov, double& chi2)
72 {
73 chi2 = xylCov(1, 1) + 2 * xylCov(1, 2) + xylCov(2, 2);
74 return Eigen::Vector2d(1, 0);
75 }
76
77 Eigen::Vector2d fitPhiVecOneStep(const Eigen::Matrix<double, 3, 3>& xylCov, double& chi2)
78 {
79 const double phi = (xylCov(0, 1) + xylCov(0, 2)) / xylCov(0, 0);
80 chi2 = xylCov(1, 1) + 2 * xylCov(1, 2) + xylCov(2, 2) - phi * (xylCov(0, 1) + xylCov(0, 2));
81 return Eigen::Vector2d(std::cos(phi), std::sin(phi));
82 }
83
84 Eigen::Vector2d fitPhiVecBrent(const Eigen::Matrix<double, 3, 3>& xylCov, int nIter, double& chi2)
85 {
86 const Eigen::Matrix< double, 2, 2> A = xylCov.topLeftCorner<2, 2>();
87 const Eigen::Matrix< double, 2, 1> b = xylCov.topRightCorner<2, 1>();
88 const double c = xylCov(2, 2);
89
90 auto calcReducedChi2 = [&A, &b](double phi) -> double {
91 Eigen::Matrix<double, 2, 1> normal(std::sin(phi), -std::cos(phi));
92 return ((normal.transpose() * A - 2 * b.transpose()) * normal)[0];
93 };
94
95 ROOT::Math::Functor1D functor(calcReducedChi2);
96 ROOT::Math::BrentMinimizer1D bm;
97 bm.SetFunction(functor, -M_PI / 2, M_PI / 2);
98 bm.Minimize(nIter); // #iterations, abs. error, rel. error
99
100 chi2 = bm.FValMinimum() + c;
101 const double phi = bm.XMinimum();
102 return Eigen::Vector2d(std::cos(phi), std::sin(phi));
103 }
104
105 template<int N>
106 UncertainParameterLine2D fit(Matrix<double, N, 3> xylIn,
107 Matrix<double, N, 1> wIn,
108 int nSteps)
109 {
111 Vector2D coordinate = getTangentialForwardDirection(xylIn);
112 // Sometimes the calculation of the tangent fails due to misestimated dirft lengths
113 // Make best effort the continue the calculation
114 if (coordinate.hasNAN()) {
115 coordinate = getCenterForwardDirection(xylIn);
116 }
117
118 rotate(coordinate, xylIn);
119
120 auto xyl = mapToEigen(xylIn);
121 auto w = mapToEigen(wIn).array();
122
123 Eigen::Array< double, 1, 3> averages = (xyl.array().colwise() * w).colwise().sum() / w.sum();
124 Eigen::Matrix< double, N, 3> deltas = xyl.array().rowwise() - averages;
125 Eigen::Matrix< double, N, 3> weightedDeltas = deltas.array().colwise() * w;
126 Eigen::Matrix< double, 3, 3> covariances = deltas.transpose() * weightedDeltas / w.sum();
127
128 Eigen::Vector2d phiVec;
129 double chi2 = 0.0;
130 if (nSteps == 0) {
131 phiVec = fitPhiVecZeroSteps(covariances, chi2);
132 } else if (nSteps == 1) {
133 phiVec = fitPhiVecOneStep(covariances, chi2);
134 } else {
135 phiVec = fitPhiVecBrent(covariances, nSteps, chi2);
136 }
137 chi2 *= w.sum();
138
139 double meanArcLength = averages.topLeftCorner<1, 2>().matrix() * phiVec;
140 double varArcLength = phiVec.transpose() * covariances.topLeftCorner<2, 2>() * phiVec;
141 double p = w.sum();
142
143 using namespace NLineParameterIndices;
144 LinePrecision linePrecision;
145 linePrecision(c_Phi0, c_Phi0) = p * (varArcLength + meanArcLength * meanArcLength);
146 linePrecision(c_Phi0, c_I) = p * meanArcLength;
147 linePrecision(c_I, c_Phi0) = p * meanArcLength;
148 linePrecision(c_I, c_I) = p;
149 LineCovariance lineCovariance = LineUtil::covarianceFromFullPrecision(linePrecision);
150
151 Vector2D tangential(phiVec(0), phiVec(1));
152 Vector2D n12 = tangential.orthogonal(ERotation::c_Clockwise);
153 double n0 = averages(2) - averages(0) * n12.x() - averages(1) * n12.y();
154 Vector2D support = -n12 * n0;
155
156 // Transform the normal vector back into the original coordinate system.
157 unrotate(coordinate, support);
158 unrotate(coordinate, tangential);
159
160 ParameterLine2D parameterLine2D(support, tangential);
161 int ndf = N - 2;
162 return UncertainParameterLine2D(parameterLine2D, lineCovariance, chi2, ndf);
163 }
164
165}
166
167double FacetFitter::fit(const CDCFacet& facet, int nSteps)
168{
169 // Measurement matrix
170 Matrix<double, 3, 3> xyl = Matrix<double, 3, 3>::Zero();
171
172 // Weight matrix
173 Matrix<double, 3, 1> w = Matrix<double, 3, 1>::Zero();
174
175 const CDCRLWireHit& startRLWireHit = facet.getStartRLWireHit();
176 const CDCRLWireHit& middleRLWireHit = facet.getMiddleRLWireHit();
177 const CDCRLWireHit& endRLWireHit = facet.getEndRLWireHit();
178
179 const Vector2D support = middleRLWireHit.getWireHit().getRefPos2D();
180
181 const double startDriftLengthVar = startRLWireHit.getRefDriftLengthVariance();
182 const Vector2D startWirePos2D = startRLWireHit.getWireHit().getRefPos2D();
183 xyl(0, 0) = startWirePos2D.x() - support.x();
184 xyl(0, 1) = startWirePos2D.y() - support.y();
185 xyl(0, 2) = startRLWireHit.getSignedRefDriftLength();
186 w(0) = 1.0 / startDriftLengthVar;
187
188 const double middleDriftLengthVar = middleRLWireHit.getRefDriftLengthVariance();
189 const Vector2D middleWirePos2D = middleRLWireHit.getWireHit().getRefPos2D();
190 xyl(1, 0) = middleWirePos2D.x() - support.x();
191 xyl(1, 1) = middleWirePos2D.y() - support.y();
192 xyl(1, 2) = middleRLWireHit.getSignedRefDriftLength();
193 w(1) = 1.0 / middleDriftLengthVar;
194
195 const double endDriftLengthVar = endRLWireHit.getRefDriftLengthVariance();
196 const Vector2D endWirePos2D = endRLWireHit.getWireHit().getRefPos2D();
197 xyl(2, 0) = endWirePos2D.x() - support.x();
198 xyl(2, 1) = endWirePos2D.y() - support.y();
199 xyl(2, 2) = endRLWireHit.getSignedRefDriftLength();
200 w(2) = 1.0 / endDriftLengthVar;
201
202 UncertainParameterLine2D fitLine{ ::fit(std::move(xyl), std::move(w), nSteps) };
203 fitLine.passiveMoveBy(-support);
204 facet.setFitLine(fitLine);
205 return fitLine.chi2();
206}
207
208
210 const CDCFacet& toFacet,
211 int nSteps)
212{
213 // Observations matrix
214 Matrix<double, 6, 3> xyl = Matrix<double, 6, 3>::Zero();
215
216 // Weight matrix
217 Matrix<double, 6, 1> w = Matrix<double, 6, 1>::Zero();
218
219 const Vector2D support = Vector2D::average(fromFacet.getMiddleWireHit().getRefPos2D(),
220 toFacet.getMiddleWireHit().getRefPos2D());
221 {
222 const CDCRLWireHit& startRLWireHit = fromFacet.getStartRLWireHit();
223 const CDCRLWireHit& middleRLWireHit = fromFacet.getMiddleRLWireHit();
224 const CDCRLWireHit& endRLWireHit = fromFacet.getEndRLWireHit();
225
226 const double startDriftLengthVar = startRLWireHit.getRefDriftLengthVariance();
227 const Vector2D startWirePos2D = startRLWireHit.getWireHit().getRefPos2D();
228 xyl(0, 0) = startWirePos2D.x() - support.x();
229 xyl(0, 1) = startWirePos2D.y() - support.y();
230 xyl(0, 2) = startRLWireHit.getSignedRefDriftLength();
231 w(0) = 1.0 / startDriftLengthVar;
232
233 const double middleDriftLengthVar = middleRLWireHit.getRefDriftLengthVariance();
234 const Vector2D middleWirePos2D = middleRLWireHit.getWireHit().getRefPos2D();
235 xyl(1, 0) = middleWirePos2D.x() - support.x();
236 xyl(1, 1) = middleWirePos2D.y() - support.y();
237 xyl(1, 2) = middleRLWireHit.getSignedRefDriftLength();
238 w(1) = 1.0 / middleDriftLengthVar;
239
240 const double endDriftLengthVar = endRLWireHit.getRefDriftLengthVariance();
241 const Vector2D endWirePos2D = endRLWireHit.getWireHit().getRefPos2D();
242 xyl(2, 0) = endWirePos2D.x() - support.x();
243 xyl(2, 1) = endWirePos2D.y() - support.y();
244 xyl(2, 2) = endRLWireHit.getSignedRefDriftLength();
245 w(2) = 1.0 / endDriftLengthVar;
246 }
247
248 {
249 const CDCRLWireHit& startRLWireHit = toFacet.getStartRLWireHit();
250 const CDCRLWireHit& middleRLWireHit = toFacet.getMiddleRLWireHit();
251 const CDCRLWireHit& endRLWireHit = toFacet.getEndRLWireHit();
252
253 const double startDriftLengthVar = startRLWireHit.getRefDriftLengthVariance();
254 const Vector2D startWirePos2D = startRLWireHit.getWireHit().getRefPos2D();
255 xyl(3, 0) = startWirePos2D.x() - support.x();
256 xyl(3, 1) = startWirePos2D.y() - support.y();
257 xyl(3, 2) = startRLWireHit.getSignedRefDriftLength();
258 w(3) = 1.0 / startDriftLengthVar;
259
260 const double middleDriftLengthVar = middleRLWireHit.getRefDriftLengthVariance();
261 const Vector2D middleWirePos2D = middleRLWireHit.getWireHit().getRefPos2D();
262 xyl(4, 0) = middleWirePos2D.x() - support.x();
263 xyl(4, 1) = middleWirePos2D.y() - support.y();
264 xyl(4, 2) = middleRLWireHit.getSignedRefDriftLength();
265 w(4) = 1.0 / middleDriftLengthVar;
266
267 const double endDriftLengthVar = endRLWireHit.getRefDriftLengthVariance();
268 const Vector2D endWirePos2D = endRLWireHit.getWireHit().getRefPos2D();
269 xyl(5, 0) = endWirePos2D.x() - support.x();
270 xyl(5, 1) = endWirePos2D.y() - support.y();
271 xyl(5, 2) = endRLWireHit.getSignedRefDriftLength();
272 w(5) = 1.0 / endDriftLengthVar;
273 }
274
275 UncertainParameterLine2D fitLine{ ::fit(std::move(xyl), std::move(w), nSteps) };
276 fitLine.passiveMoveBy(-support);
277 return fitLine;
278}
279
280
281UncertainParameterLine2D FacetFitter::fit(Matrix<double, 3, 3> xyl,
282 Matrix<double, 3, 1> w,
283 int nSteps)
284{
285 return ::fit(std::move(xyl), std::move(w), nSteps);
286}
static double fit(const TrackingUtilities::CDCFacet &facet, int nSteps=100)
Fits a proper line to facet and returns the chi2.
Class representing a triple of neighboring oriented wire with additional trajectory information.
Definition CDCFacet.h:32
void setFitLine(const UncertainParameterLine2D &fitLine) const
Setter for the contained line fit information.
Definition CDCFacet.h:67
const CDCWireHit & getMiddleWireHit() const
Getter for the hit wire of the second oriented wire hit.
CDCRLWireHit & getStartRLWireHit()
Getter for the first oriented wire hit.
CDCRLWireHit & getEndRLWireHit()
Getter for the third oriented wire hit.
CDCRLWireHit & getMiddleRLWireHit()
Getter for the second oriented wire hit.
Class representing an oriented hit wire including a hypotheses whether the causing track passes left ...
const CDCWireHit & getWireHit() const
Getter for the wire hit associated with the oriented hit.
double getRefDriftLengthVariance() const
Getter for the variance of the drift length at the reference position of the wire.
double getSignedRefDriftLength() const
Getter for the drift length at the reference position of the wire.
const ROOT::Math::XYVector & getRefPos2D() const
The two dimensional reference position (z=0) of the underlying wire.
A line with a support point and tangential vector.
static ParameterLine2D touchingCircles(const Vector2D &fromCenter, double fromSignedRadius, const Vector2D &toCenter, double toSignedRadius)
Constructs a line touching two circles in one point each.
const Vector2D & tangential() const
Gives the tangential vector of the line.
static PlainMatrix< T, M, N > Identity()
Construct an identity matrix.
Definition PlainMatrix.h:74
static PlainMatrix< T, M, N > Zero()
Construct a matrix initialized with zeros.
Definition PlainMatrix.h:67
A parameter line including including an line covariance matrix which is interpreted as located in the...
void passiveMoveBy(const Vector2D &by)
Moves the coordinate system by the vector by.
A two dimensional vector which is equipped with functions for correct handling of orientation relate...
Definition Vector2D.h:36
Vector2D flippedSecond() const
Makes a copy of the vector with the second coordinate flipped (no difference between active and passi...
Definition Vector2D.h:396
static Vector2D average(const Vector2D &one, const Vector2D &two)
Constructs the average of two vectors.
Definition Vector2D.h:104
double x() const
Getter for the x coordinate.
Definition Vector2D.h:626
Vector2D orthogonal() const
Orthogonal vector to the counterclockwise direction.
Definition Vector2D.h:320
bool hasNAN() const
Checks if one of the coordinates is NAN.
Definition Vector2D.h:169
double y() const
Getter for the y coordinate.
Definition Vector2D.h:641
Vector2D unit() const
Returns a unit vector colaligned with this.
Definition Vector2D.h:352
Vector2D passiveRotatedBy(const Vector2D &phiVec) const
Returns a transformed vector version rotated by the given vector.
Definition Vector2D.h:620
Namespace to hide the contained enum constants.
Abstract base class for different kinds of events.