Belle II Software development
KarimakisMethod.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/KarimakisMethod.h>
9
10#include <tracking/trackFindingCDC/fitting/EigenObservationMatrix.h>
11#include <tracking/trackFindingCDC/fitting/CDCObservations2D.h>
12
13#include <tracking/trackingUtilities/eventdata/trajectories/CDCTrajectory2D.h>
14
15#include <tracking/trackingUtilities/geometry/UncertainPerigeeCircle.h>
16#include <tracking/trackingUtilities/geometry/PerigeeParameters.h>
17
18#include <Math/Vector2D.h>
19
20#include <Eigen/Core>
21
22using namespace Belle2;
23using namespace TrackFindingCDC;
24using namespace TrackingUtilities;
25
30
32 CDCObservations2D& observations2D) const
33{
34 size_t nObservations = observations2D.size();
35 trajectory2D.clear();
36 if (not nObservations) return;
37
38 ROOT::Math::XYVector ref = observations2D.getCentralPoint();
39 observations2D.passiveMoveBy(ref);
40
41 UncertainPerigeeCircle perigeeCircle = fitInternal(observations2D);
42
43 double frontX = observations2D.getX(0);
44 double frontY = observations2D.getY(0);
45 ROOT::Math::XYVector frontPos(frontX, frontY);
46
47 double backX = observations2D.getX(nObservations - 1);
48 double backY = observations2D.getY(nObservations - 1);
49 ROOT::Math::XYVector backPos(backX, backY);
50
51 ROOT::Math::XYVector overPos(0, 0);
52 double totalPerps = (perigeeCircle->arcLengthBetween(frontPos, overPos) +
53 perigeeCircle->arcLengthBetween(overPos, backPos));
54
55 if (totalPerps < 0) {
56 perigeeCircle.reverse();
57 }
58
59 trajectory2D.setLocalOrigin(ref);
60 trajectory2D.setLocalCircle(perigeeCircle);
61}
62
63
64
65
66namespace {
68 constexpr size_t iW = 0;
69 constexpr size_t iX = 1;
70 constexpr size_t iY = 2;
71 constexpr size_t iR2 = 3;
72
74 UncertainPerigeeCircle fitKarimaki(const double /*sw*/,
75 const Eigen::Matrix< double, 4, 1 >& a,
76 const Eigen::Matrix< double, 4, 4 >& c,
77 bool lineConstrained = false)
78 {
79 double q1, q2 = 0.0;
80 if (lineConstrained) {
81 q1 = c(iX, iY);
82 q2 = c(iX, iX) - c(iY, iY);
83 } else {
84 q1 = c(iX, iY) * c(iR2, iR2) - c(iX, iR2) * c(iY, iR2);
85 q2 = (c(iX, iX) - c(iY, iY)) * c(iR2, iR2) - c(iX, iR2) * c(iX, iR2) + c(iY, iR2) * c(iY, iR2);
86 }
87
88 double phi = 0.5 * atan2(2. * q1, q2);
89
90 double sinphi = sin(phi);
91 double cosphi = cos(phi);
92
93 double curv, I = 0.0;
94 if (lineConstrained) {
95 curv = 0.0; //line
96 I = sinphi * a(iX) - cosphi * a(iY);
97
98 } else {
99 double kappa = (sinphi * c(iX, iR2) - cosphi * c(iY, iR2)) / c(iR2, iR2);
100 double delta = -kappa * a(iR2) + sinphi * a(iX) - cosphi * a(iY);
101 curv = 2. * kappa / sqrt(1. - 4. * delta * kappa);
102 I = 2. * delta / (1. + sqrt(1. - 4. * delta * kappa));
103
104 }
105
106 // Karimaki uses the opposite sign for phi in contrast to the convention of this framework !!!
107 phi += phi > 0 ? -M_PI : M_PI;
108 return UncertainPerigeeCircle(curv, phi, I);
109
110 }
111
112
113
114
115
117 double calcChi2Karimaki(const PerigeeCircle& parameters,
118 const double sw,
119 const Eigen::Matrix< double, 4, 4 >& c,
120 bool lineConstrained = false)
121 {
122 // Karimaki uses the opposite sign for phi in contrast to the convention of this framework !!!
123 const ROOT::Math::XYVector vecPhi = -parameters.tangential();
124
125 const double cosphi = vecPhi.x();
126 const double sinphi = vecPhi.y();
127
128 if (lineConstrained) {
129 double chi2 = sw * (sinphi * sinphi * c(iX, iX) - 2. * sinphi * cosphi * c(iX, iY) + cosphi * cosphi * c(iY, iY));
130 return chi2;
131 } else {
132 // Terminology Karimaki used in the paper
133 const double rho = parameters.curvature();
134 const double d = parameters.impact();
135
136 const double u = 1 + d * rho;
137 const double kappa = 0.5 * rho / u;
138
139 double chi2 = sw * u * u * (sinphi * sinphi * c(iX, iX) - 2. * sinphi * cosphi * c(iX, iY) + cosphi * cosphi * c(iY,
140 iY) - kappa * kappa * c(iR2, iR2));
141 return chi2;
142 }
143
144 }
145
146
147
148 PerigeePrecision calcPrecisionKarimaki(const PerigeeCircle& parameters,
149 const Eigen::Matrix< double, 4, 4 >& s,
150 bool lineConstrained = false)
151 {
152 PerigeePrecision perigeePrecision;
153
154 const double curv = parameters.curvature();
155 const double I = parameters.impact();
156
157 // Karimaki uses the opposite sign for phi in contrast to the convention of this framework !!!
158 const ROOT::Math::XYVector vecPhi = -parameters.tangential();
159
160 // Ternminology Karimaki using in the paper
161 const double cosphi = vecPhi.x();
162 const double sinphi = vecPhi.y();
163
164 const double ssphi = sinphi * sinphi;
165 const double scphi = sinphi * cosphi;
166 const double ccphi = cosphi * cosphi;
167
168 const double rho = curv;
169 const double d = I;
170
171 const double u = 1. + rho * d;
172
173 using namespace NPerigeeParameterIndices;
174 if (lineConstrained) {
175 perigeePrecision(c_Curv, c_Curv) = 0.;
176 perigeePrecision(c_Curv, c_Phi0) = 0.;
177 perigeePrecision(c_Curv, c_I) = 0.;
178 perigeePrecision(c_Phi0, c_Curv) = 0.;
179 perigeePrecision(c_I, c_Curv) = 0.;
180
181 perigeePrecision(c_Phi0, c_Phi0) = ccphi * s(iX, iX) + 2. * scphi * s(iX, iY) + ssphi * s(iY, iY);
182 perigeePrecision(c_Phi0, c_I) = -(cosphi * s(iX) + sinphi * s(iY));
183 perigeePrecision(c_I, c_Phi0) = perigeePrecision(c_Phi0, c_I);
184 perigeePrecision(c_I, c_I) = s(iW);
185
186 } else {
187 double sa = sinphi * s(iX) - cosphi * s(iY);
188 double sb = cosphi * s(iX) + sinphi * s(iY);
189 double sc = (ssphi - ccphi) * s(iX, iY) + scphi * (s(iX, iX) - s(iY, iY));
190
191 double sd = sinphi * s(iX, iR2) - cosphi * s(iY, iR2);
192
193 double saa = ssphi * s(iX, iX) - 2. * scphi * s(iX, iY) + ccphi * s(iY, iY);
194
195 // Not in the Karimaki paper, but factors a similar term.
196 double se = cosphi * s(iX, iR2) + sinphi * s(iY, iR2);
197 double sbb = ccphi * s(iX, iX) + 2. * scphi * s(iX, iY) + ssphi * s(iY, iY);
198
199 perigeePrecision(c_Curv, c_Curv) = 0.25 * s(iR2, iR2) - d * (sd - d * (saa + 0.5 * s(iR2) - d * (sa - 0.25 * d * s(iW))));
200 perigeePrecision(c_Curv, c_Phi0) = - u * (0.5 * se - d * (sc - 0.5 * d * sb));
201 perigeePrecision(c_Phi0, c_Curv) = perigeePrecision(c_Curv, c_Phi0);
202 perigeePrecision(c_Phi0, c_Phi0) = u * u * sbb;
203
204 perigeePrecision(c_Curv, c_I) = rho * (-0.5 * sd + d * saa) + 0.5 * u * s(iR2) - 0.5 * d * ((2 * u + rho * d) * sa - u * d * s(iW));
205 perigeePrecision(c_I, c_Curv) = perigeePrecision(c_Curv, c_I);
206 perigeePrecision(c_Phi0, c_I) = u * (rho * sc - u * sb);
207 perigeePrecision(c_I, c_Phi0) = perigeePrecision(c_Phi0, c_I);
208 perigeePrecision(c_I, c_I) = rho * (rho * saa - 2 * u * sa) + u * u * s(iW);
209 }
210 return perigeePrecision;
211 }
212}
213
214
215
217{
218 // Matrix of weighted sums
219 Eigen::Matrix< double, 4, 4> sNoL = getWXYRSumMatrix(observations2D);
220
221 // Matrix of averages
222 Eigen::Matrix<double, 4, 4> aNoL = sNoL / sNoL(iW);
223
224 // Measurement means
225 Eigen::Matrix<double, 4, 1> meansNoL = aNoL.row(iW);
226
227 // Covariance matrix
228 Eigen::Matrix<double, 4, 4> cNoL = aNoL - meansNoL * meansNoL.transpose();
229
230 // Determine NDF : Circle fit eats up to 3 degrees of freedom debpending on the constraints
231 size_t ndf = observations2D.size() - 2;
232
233 if (not isLineConstrained()) {
234 --ndf;
235 }
236
237 // Parameters to be fitted
238 UncertainPerigeeCircle resultCircle = fitKarimaki(sNoL(iW), meansNoL, cNoL, isLineConstrained());
239 double chi2 = calcChi2Karimaki(resultCircle, sNoL(iW), cNoL);
240
241 PerigeePrecision perigeePrecision = calcPrecisionKarimaki(resultCircle, sNoL, isLineConstrained());
242
243 // Use in pivotingin caset the matrix is not full rank as is for the constrained cases-
244 PerigeeCovariance perigeeCovariance = PerigeeUtil::covarianceFromPrecision(perigeePrecision);
245
246 resultCircle.setChi2(chi2);
247 resultCircle.setNDF(ndf);
248 resultCircle.setPerigeeCovariance(perigeeCovariance);
249 return resultCircle;
250}
Class serving as a storage of observed drift circles to present to the Riemann fitter.
double getX(int iObservation) const
Getter for the x value of the observation at the given index.
double getY(int iObservation) const
Getter for the y value of the observation at the given index.
void passiveMoveBy(const ROOT::Math::XYVector &origin)
Moves all observations passively such that the given vector becomes to origin of the new coordinate s...
std::size_t size() const
Returns the number of observations stored.
ROOT::Math::XYVector getCentralPoint() const
Extracts the observation center that is at the index in the middle.
KarimakisMethod()
Constructor setting the default constraints.
void update(TrackingUtilities::CDCTrajectory2D &trajectory2D, CDCObservations2D &observations2D) const
Executes the fit and updates the trajectory parameters. This may render the information in the observ...
bool isLineConstrained() const
Getter for the indicator that lines should be fitted by this fitter.
TrackingUtilities::UncertainPerigeeCircle fitInternal(CDCObservations2D &observations2D) const
Internal method doing the heavy work.
bool m_lineConstrained
Memory for the flag indicating that lines should be fitted.
Particle trajectory as it is seen in xy projection represented as a circle.
void setLocalCircle(const UncertainPerigeeCircle &localPerigeeCircle)
Setter for the generalized circle that describes the trajectory.
double setLocalOrigin(const ROOT::Math::XYVector &localOrigin)
Setter for the origin of the local coordinate system.
void clear()
Clears all information from this trajectory.
double arcLengthBetween(const ROOT::Math::XYVector &from, const ROOT::Math::XYVector &to) const
Calculates the arc length between two points of closest approach on the circle.
Adds an uncertainty matrix to the circle in perigee parameterisation.
void reverse()
Flips the orientation of the circle in place.
void setPerigeeCovariance(const PerigeeCovariance &perigeeCovariance)
Setter for the whole covariance matrix of the perigee parameters.
void setNDF(std::size_t ndf)
Setter for the number of degrees of freediom used in the circle fit.
void setChi2(const double chi2)
Setter for the chi square value of the circle fit.
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
Abstract base class for different kinds of events.