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