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/Vector2D.h>
16#include <tracking/trackingUtilities/numerics/EigenView.h>
22#include <Math/Functor.h>
23#include <Math/BrentMinimizer1D.h>
26using namespace TrackFindingCDC;
27using namespace TrackingUtilities;
32 Vector2D getCenterForwardDirection(
const Matrix<double, N, 3>& xyl)
35 Vector2D coordinate(xyl(N - 1, 0) - xyl(0, 0), xyl(N - 1, 1) - xyl(0, 1));
36 return coordinate.unit();
40 Vector2D getTangentialForwardDirection(
const Matrix<double, N, 3>& xyl)
43 Vector2D fromPos(xyl(0, 0), xyl(0, 1));
44 double fromL = xyl(0, 2);
46 Vector2D toPos(xyl(N - 1, 0), xyl(N - 1, 1));
47 double toL = xyl(N - 1, 2);
51 return coordinate.
unit();
55 void rotate(
Vector2D 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();
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 {
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 Vector2D coordinate = getTangentialForwardDirection(xylIn);
144 if (coordinate.
hasNAN()) {
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 Vector2D& 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 Vector2D tangential(phiVec(0), phiVec(1));
201 double n0 = averages(2) - averages(0) * n12.
x() - averages(1) * n12.
y();
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);
227 Matrix<double, 3, 3>& xyl,
228 Matrix<double, 3, 1>& w)
238 xyl(0, 0) = startWirePos2D.
x() - support.
x();
239 xyl(0, 1) = startWirePos2D.
y() - support.
y();
241 w(0) = 1.0 / startDriftLengthVar;
245 xyl(1, 0) = middleWirePos2D.
x() - support.
x();
246 xyl(1, 1) = middleWirePos2D.
y() - support.
y();
248 w(1) = 1.0 / middleDriftLengthVar;
252 xyl(2, 0) = endWirePos2D.
x() - support.
x();
253 xyl(2, 1) = endWirePos2D.
y() - support.
y();
255 w(2) = 1.0 / endDriftLengthVar;
269 const Vector2D support = fillFacetObservations(facet, xyl, w);
271 LineFitPrecursor precursor = fitPrecursor(std::move(xyl), std::move(w), nSteps);
277 if (std::isinf(maxChi2) or precursor.chi2 <= maxChi2) {
283 return precursor.chi2;
291 Matrix<double, 6, 3>& xyl,
292 Matrix<double, 6, 1>& w)
303 xyl(0, 0) = startWirePos2D.
x() - support.
x();
304 xyl(0, 1) = startWirePos2D.
y() - support.
y();
306 w(0) = 1.0 / startDriftLengthVar;
310 xyl(1, 0) = middleWirePos2D.
x() - support.
x();
311 xyl(1, 1) = middleWirePos2D.
y() - support.
y();
313 w(1) = 1.0 / middleDriftLengthVar;
317 xyl(2, 0) = endWirePos2D.
x() - support.
x();
318 xyl(2, 1) = endWirePos2D.
y() - support.
y();
320 w(2) = 1.0 / endDriftLengthVar;
330 xyl(3, 0) = startWirePos2D.
x() - support.
x();
331 xyl(3, 1) = startWirePos2D.
y() - support.
y();
333 w(3) = 1.0 / startDriftLengthVar;
337 xyl(4, 0) = middleWirePos2D.
x() - support.
x();
338 xyl(4, 1) = middleWirePos2D.
y() - support.
y();
340 w(4) = 1.0 / middleDriftLengthVar;
344 xyl(5, 0) = endWirePos2D.
x() - support.
x();
345 xyl(5, 1) = endWirePos2D.
y() - support.
y();
347 w(5) = 1.0 / endDriftLengthVar;
364 const Vector2D support = fillFacetPairObservations(fromFacet, toFacet, xyl, w);
380 fillFacetPairObservations(fromFacet, toFacet, xyl, w);
383 constexpr const int nSteps = 0;
384 return fitPrecursor(std::move(xyl), std::move(w), nSteps).chi2;
389 TrackingUtilities::Matrix<double, 3, 1> w,
392 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.
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.
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 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...
Vector2D flippedSecond() const
Makes a copy of the vector with the second coordinate flipped (no difference between active and passi...
static Vector2D average(const Vector2D &one, const Vector2D &two)
Constructs the average of two vectors.
double x() const
Getter for the x coordinate.
Vector2D orthogonal() const
Orthogonal vector to the counterclockwise direction.
bool hasNAN() const
Checks if one of the coordinates is NAN.
double y() const
Getter for the y coordinate.
Vector2D unit() const
Returns a unit vector colaligned with this.
Vector2D passiveRotatedBy(const Vector2D &phiVec) const
Returns a transformed vector version rotated by the given vector.
Namespace to hide the contained enum constants.
Abstract base class for different kinds of events.