8#include <tracking/trackFindingCDC/fitting/FacetFitter.h>
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>
21#include <Math/Vector2D.h>
22#include <Math/Functor.h>
23#include <Math/BrentMinimizer1D.h>
26using namespace TrackFindingCDC;
27using namespace TrackingUtilities;
32 ROOT::Math::XYVector getCenterForwardDirection(
const Matrix<double, N, 3>& xyl)
35 ROOT::Math::XYVector coordinate(xyl(N - 1, 0) - xyl(0, 0), xyl(N - 1, 1) - xyl(0, 1));
36 return VectorUtil::unit(coordinate);
40 ROOT::Math::XYVector getTangentialForwardDirection(
const Matrix<double, N, 3>& xyl)
43 ROOT::Math::XYVector fromPos(xyl(0, 0), xyl(0, 1));
44 double fromL = xyl(0, 2);
46 ROOT::Math::XYVector toPos(xyl(N - 1, 0), xyl(N - 1, 1));
47 double toL = xyl(N - 1, 2);
50 ROOT::Math::XYVector coordinate = tangentLine.
tangential();
51 return VectorUtil::unit(coordinate);
55 void rotate(ROOT::Math::XYVector coordinate, Matrix<double, N, 3>& xyl)
58 rot(0, 0) = coordinate.x();
59 rot(0, 1) = -coordinate.y();
60 rot(1, 0) = coordinate.y();
61 rot(1, 1) = coordinate.x();
66 void unrotate(ROOT::Math::XYVector coordinate, ROOT::Math::XYVector& vec)
70 vec = VectorUtil::passiveRotatedBy(vec, ROOT::Math::XYVector(coordinate.X(), -coordinate.Y()));
73 Eigen::Vector2d fitPhiVecZeroSteps(
const Eigen::Matrix<double, 3, 3>& xylCov,
double& chi2)
75 chi2 = xylCov(1, 1) + 2 * xylCov(1, 2) + xylCov(2, 2);
76 return Eigen::Vector2d(1, 0);
79 Eigen::Vector2d fitPhiVecOneStep(
const Eigen::Matrix<double, 3, 3>& xylCov,
double& chi2)
81 const double phi = (xylCov(0, 1) + xylCov(0, 2)) / xylCov(0, 0);
82 chi2 = xylCov(1, 1) + 2 * xylCov(1, 2) + xylCov(2, 2) - phi * (xylCov(0, 1) + xylCov(0, 2));
83 return Eigen::Vector2d(std::cos(phi), std::sin(phi));
86 Eigen::Vector2d fitPhiVecBrent(
const Eigen::Matrix<double, 3, 3>& xylCov,
int nIter,
double& chi2)
88 const Eigen::Matrix< double, 2, 2> A = xylCov.topLeftCorner<2, 2>();
89 const Eigen::Matrix< double, 2, 1> b = xylCov.topRightCorner<2, 1>();
90 const double c = xylCov(2, 2);
92 auto calcReducedChi2 = [&A, &b](
double phi) ->
double {
93 Eigen::Matrix<double, 2, 1> normal(std::sin(phi), -std::cos(phi));
94 return ((normal.transpose() * A - 2 * b.transpose()) * normal)[0];
97 ROOT::Math::Functor1D functor(calcReducedChi2);
98 ROOT::Math::BrentMinimizer1D bm;
99 bm.SetFunction(functor, -M_PI / 2, M_PI / 2);
102 chi2 = bm.FValMinimum() + c;
103 const double phi = bm.XMinimum();
104 return Eigen::Vector2d(std::cos(phi), std::sin(phi));
113 struct LineFitPrecursor {
115 ROOT::Math::XYVector coordinate;
118 Eigen::Array<double, 1, 3> averages;
121 Eigen::Matrix<double, 3, 3> covariances;
124 Eigen::Vector2d phiVec;
134 LineFitPrecursor fitPrecursor(Matrix<double, N, 3> xylIn,
135 Matrix<double, N, 1> wIn,
138 LineFitPrecursor precursor;
141 ROOT::Math::XYVector coordinate = getTangentialForwardDirection(xylIn);
144 if (VectorUtil::hasNAN(coordinate)) {
145 coordinate = getCenterForwardDirection(xylIn);
148 rotate(coordinate, xylIn);
150 auto xyl = mapToEigen(xylIn);
151 auto w = mapToEigen(wIn).array();
153 Eigen::Array< double, 1, 3> averages = (xyl.array().colwise() * w).colwise().sum() / w.sum();
154 Eigen::Matrix< double, N, 3> deltas = xyl.array().rowwise() - averages;
155 Eigen::Matrix< double, N, 3> weightedDeltas = deltas.array().colwise() * w;
156 Eigen::Matrix< double, 3, 3> covariances = deltas.transpose() * weightedDeltas / w.sum();
158 Eigen::Vector2d phiVec;
161 phiVec = fitPhiVecZeroSteps(covariances, chi2);
162 }
else if (nSteps == 1) {
163 phiVec = fitPhiVecOneStep(covariances, chi2);
165 phiVec = fitPhiVecBrent(covariances, nSteps, chi2);
169 precursor.coordinate = coordinate;
170 precursor.averages = averages;
171 precursor.covariances = covariances;
172 precursor.phiVec = phiVec;
173 precursor.chi2 = chi2;
174 precursor.sumW = w.sum();
181 const ROOT::Math::XYVector& coordinate = precursor.coordinate;
182 const Eigen::Array<double, 1, 3>& averages = precursor.averages;
183 const Eigen::Matrix<double, 3, 3>& covariances = precursor.covariances;
184 const Eigen::Vector2d& phiVec = precursor.phiVec;
185 const double chi2 = precursor.chi2;
187 double meanArcLength = averages.topLeftCorner<1, 2>().matrix() * phiVec;
188 double varArcLength = phiVec.transpose() * covariances.topLeftCorner<2, 2>() * phiVec;
189 double p = precursor.sumW;
192 LinePrecision linePrecision;
193 linePrecision(c_Phi0, c_Phi0) = p * (varArcLength + meanArcLength * meanArcLength);
194 linePrecision(c_Phi0, c_I) = p * meanArcLength;
195 linePrecision(c_I, c_Phi0) = p * meanArcLength;
196 linePrecision(c_I, c_I) = p;
197 LineCovariance lineCovariance = LineUtil::covarianceFromFullPrecision(linePrecision);
199 ROOT::Math::XYVector tangential(phiVec(0), phiVec(1));
200 ROOT::Math::XYVector n12 = VectorUtil::Orthogonal(tangential, ERotation::c_Clockwise);
201 double n0 = averages(2) - averages(0) * n12.x() - averages(1) * n12.y();
202 ROOT::Math::XYVector support = -n12 * n0;
205 unrotate(coordinate, support);
206 unrotate(coordinate, tangential);
214 Matrix<double, N, 1> wIn,
217 LineFitPrecursor precursor = fitPrecursor(std::move(xylIn), std::move(wIn), nSteps);
219 return lineFromPrecursor(precursor, ndf);
226 ROOT::Math::XYVector fillFacetObservations(
const CDCFacet& facet,
228 Matrix<double, 3, 3>& xyl,
230 Matrix<double, 3, 1>& w)
240 xyl(0, 0) = startWirePos2D.x() - support.x();
241 xyl(0, 1) = startWirePos2D.y() - support.y();
243 w(0) = 1.0 / startDriftLengthVar;
247 xyl(1, 0) = middleWirePos2D.x() - support.x();
248 xyl(1, 1) = middleWirePos2D.y() - support.y();
250 w(1) = 1.0 / middleDriftLengthVar;
254 xyl(2, 0) = endWirePos2D.x() - support.x();
255 xyl(2, 1) = endWirePos2D.y() - support.y();
257 w(2) = 1.0 / endDriftLengthVar;
271 const ROOT::Math::XYVector support = fillFacetObservations(facet, xyl, w);
273 LineFitPrecursor precursor = fitPrecursor(std::move(xyl), std::move(w), nSteps);
279 if (std::isinf(maxChi2) or precursor.chi2 <= maxChi2) {
285 return precursor.chi2;
291 ROOT::Math::XYVector fillFacetPairObservations(
const CDCFacet& fromFacet,
294 Matrix<double, 6, 3>& xyl,
296 Matrix<double, 6, 1>& w)
307 xyl(0, 0) = startWirePos2D.x() - support.x();
308 xyl(0, 1) = startWirePos2D.y() - support.y();
310 w(0) = 1.0 / startDriftLengthVar;
314 xyl(1, 0) = middleWirePos2D.x() - support.x();
315 xyl(1, 1) = middleWirePos2D.y() - support.y();
317 w(1) = 1.0 / middleDriftLengthVar;
321 xyl(2, 0) = endWirePos2D.x() - support.x();
322 xyl(2, 1) = endWirePos2D.y() - support.y();
324 w(2) = 1.0 / endDriftLengthVar;
334 xyl(3, 0) = startWirePos2D.x() - support.x();
335 xyl(3, 1) = startWirePos2D.y() - support.y();
337 w(3) = 1.0 / startDriftLengthVar;
341 xyl(4, 0) = middleWirePos2D.x() - support.x();
342 xyl(4, 1) = middleWirePos2D.y() - support.y();
344 w(4) = 1.0 / middleDriftLengthVar;
348 xyl(5, 0) = endWirePos2D.x() - support.x();
349 xyl(5, 1) = endWirePos2D.y() - support.y();
351 w(5) = 1.0 / endDriftLengthVar;
368 const ROOT::Math::XYVector support = fillFacetPairObservations(fromFacet, toFacet, xyl, w);
384 fillFacetPairObservations(fromFacet, toFacet, xyl, w);
387 constexpr const int nSteps = 0;
388 return fitPrecursor(std::move(xyl), std::move(w), nSteps).chi2;
393 TrackingUtilities::Matrix<double, 3, 1> w,
396 return ::fit(std::move(xyl), std::move(w), nSteps);
static double fitChi2(const TrackingUtilities::CDCFacet &fromFacet, const TrackingUtilities::CDCFacet &toFacet)
Calculate only the chi2 of a line fitted to the hits of the two facets.
static double fit(const TrackingUtilities::CDCFacet &facet, int nSteps=100, double maxChi2=std::numeric_limits< double >::infinity())
Fits a proper line to the facet and returns the chi2.
Class representing a triple of neighboring oriented wire with additional trajectory information.
void setFitLine(const UncertainParameterLine2D &fitLine) const
Setter for the contained line fit information.
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.
static PlainMatrix< T, M, N > Zero()
Construct a matrix initialized with zeros.
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.