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/VectorUtil.h>
15#include <tracking/trackingUtilities/numerics/EigenView.h>
16
17#include <Eigen/Core>
18
19#include <Math/Vector2D.h>
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 ROOT::Math::XYVector getCenterForwardDirection(const Matrix<double, N, 3>& xyl)
31 {
33 ROOT::Math::XYVector coordinate(xyl(N - 1, 0) - xyl(0, 0), xyl(N - 1, 1) - xyl(0, 1));
34 return VectorUtil::unit(coordinate);
35 }
36
37 template<int N>
38 ROOT::Math::XYVector getTangentialForwardDirection(const Matrix<double, N, 3>& xyl)
39 {
41 ROOT::Math::XYVector fromPos(xyl(0, 0), xyl(0, 1));
42 double fromL = xyl(0, 2);
43
44 ROOT::Math::XYVector 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 ROOT::Math::XYVector coordinate = tangentLine.tangential();
49 return VectorUtil::unit(coordinate);
50 }
51
52 template<int N>
53 void rotate(ROOT::Math::XYVector 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(ROOT::Math::XYVector coordinate, ROOT::Math::XYVector& 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 = VectorUtil::passiveRotatedBy(vec, ROOT::Math::XYVector(coordinate.X(), -coordinate.Y()));
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 ROOT::Math::XYVector 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 (VectorUtil::hasNAN(coordinate)) {
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 ROOT::Math::XYVector tangential(phiVec(0), phiVec(1));
152 ROOT::Math::XYVector n12 = VectorUtil::Orthogonal(tangential, ERotation::c_Clockwise);
153 double n0 = averages(2) - averages(0) * n12.x() - averages(1) * n12.y();
154 ROOT::Math::XYVector 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 ROOT::Math::XYVector support = middleRLWireHit.getWireHit().getRefPos2D();
180
181 const double startDriftLengthVar = startRLWireHit.getRefDriftLengthVariance();
182 const ROOT::Math::XYVector 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 ROOT::Math::XYVector 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 ROOT::Math::XYVector 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 ROOT::Math::XYVector support = VectorUtil::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 ROOT::Math::XYVector 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 ROOT::Math::XYVector 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 ROOT::Math::XYVector 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 ROOT::Math::XYVector 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 ROOT::Math::XYVector 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 ROOT::Math::XYVector 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(TrackingUtilities::Matrix<double, 3, 3> xyl,
282 TrackingUtilities::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:33
void setFitLine(const UncertainParameterLine2D &fitLine) const
Setter for the contained line fit information.
Definition CDCFacet.h:68
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.
const ROOT::Math::XYVector & tangential() const
Gives the tangential vector of the line.
static ParameterLine2D touchingCircles(const ROOT::Math::XYVector &fromCenter, double fromSignedRadius, const ROOT::Math::XYVector &toCenter, double toSignedRadius)
Constructs a line touching two circles in one point each.
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 ROOT::Math::XYVector &by)
Moves the coordinate system by the vector by.
Namespace to hide the contained enum constants.
Abstract base class for different kinds of events.