EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FullBilloirVertexFitter.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FullBilloirVertexFitter.ipp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
14 
15 namespace {
16 
20 template <typename input_track_t>
21 struct BilloirTrack {
23 
24  BilloirTrack(const input_track_t* params, Acts::LinearizedTrack lTrack)
25  : originalTrack(params), linTrack(std::move(lTrack)) {}
26 
27  BilloirTrack(const BilloirTrack& arg) = default;
28 
29  const input_track_t* originalTrack;
30  Acts::LinearizedTrack linTrack;
31  double chi2;
32  Jacobian DiMat; // position jacobian
33  Acts::ActsMatrixD<Acts::eBoundSize, 3> EiMat; // momentum jacobian
34  Acts::ActsSymMatrixD<3> CiMat; // = EtWmat * Emat (see below)
35  Acts::ActsMatrixD<4, 3> BiMat; // = DiMat^T * Wi * EiMat
36  Acts::ActsSymMatrixD<3> CiInv; // = (EiMat^T * Wi * EiMat)^-1
37  Acts::Vector3D UiVec; // = EiMat^T * Wi * dqi
38  Acts::ActsMatrixD<4, 3> BCiMat; // = BiMat * Ci^-1
39  Acts::BoundVector deltaQ;
40 };
41 
45 struct BilloirVertex {
46  // Amat = sum{DiMat^T * Wi * DiMat}
47  Acts::SymMatrix4D Amat = Acts::SymMatrix4D::Zero();
48  // Tvec = sum{DiMat^T * Wi * dqi}
49  Acts::Vector4D Tvec = Acts::Vector4D::Zero();
50  // BCBmat = sum{BiMat * Ci^-1 * BiMat^T}
51  Acts::SymMatrix4D BCBmat = Acts::SymMatrix4D::Zero();
52  // BCUvec = sum{BiMat * Ci^-1 * UiVec}
53  Acts::Vector4D BCUvec = Acts::Vector4D::Zero();
54 };
55 
56 } // end anonymous namespace
57 
58 template <typename input_track_t, typename linearizer_t>
61  const std::vector<const input_track_t*>& paramVector,
62  const linearizer_t& linearizer,
63  const VertexingOptions<input_track_t>& vertexingOptions,
64  State& state) const {
65  double chi2 = std::numeric_limits<double>::max();
66  double newChi2 = 0;
67  unsigned int nTracks = paramVector.size();
68 
69  if (nTracks == 0) {
70  return Vertex<input_track_t>(Vector3D(0., 0., 0.));
71  }
72 
73  // Set number of degrees of freedom
74  // ndf = (5-3) * nTracks - 3;
75  int ndf = 2 * nTracks - 3;
76  if (nTracks < 2) {
77  ndf = 1;
78  }
79 
80  // Determine if we do contraint fit or not by checking if an
81  // invertible non-zero constraint vertex covariance is given
82  bool isConstraintFit = false;
83  if (vertexingOptions.vertexConstraint.covariance().determinant() != 0) {
84  isConstraintFit = true;
85  ndf += 3;
86  }
87 
88  std::vector<BilloirTrack<input_track_t>> billoirTracks;
89 
90  std::vector<Vector3D> trackMomenta;
91 
92  Vector4D linPoint(vertexingOptions.vertexConstraint.fullPosition());
93 
94  Vertex<input_track_t> fittedVertex;
95 
96  for (int nIter = 0; nIter < m_cfg.maxIterations; ++nIter) {
97  billoirTracks.clear();
98 
99  newChi2 = 0;
100 
101  BilloirVertex billoirVertex;
102  int iTrack = 0;
103  // iterate over all tracks
104  for (const input_track_t* trackContainer : paramVector) {
105  const auto& trackParams = extractParameters(*trackContainer);
106  if (nIter == 0) {
107  double phi = trackParams.parameters()[BoundIndices::eBoundPhi];
108  double theta = trackParams.parameters()[BoundIndices::eBoundTheta];
109  double qop = trackParams.parameters()[BoundIndices::eBoundQOverP];
110  trackMomenta.push_back(Vector3D(phi, theta, qop));
111  }
112 
113  auto result = linearizer.linearizeTrack(
114  trackParams, linPoint, vertexingOptions.geoContext,
115  vertexingOptions.magFieldContext, state.linearizerState);
116  if (result.ok()) {
117  const auto& linTrack = *result;
118  const auto& parametersAtPCA = linTrack.parametersAtPCA;
119  double d0 = parametersAtPCA[BoundIndices::eBoundLoc0];
120  double z0 = parametersAtPCA[BoundIndices::eBoundLoc1];
121  double phi = parametersAtPCA[BoundIndices::eBoundPhi];
122  double theta = parametersAtPCA[BoundIndices::eBoundTheta];
123  double qOverP = parametersAtPCA[BoundIndices::eBoundQOverP];
124 
125  // calculate f(V_0,p_0) f_d0 = f_z0 = 0
126  double fPhi = trackMomenta[iTrack][0];
127  double fTheta = trackMomenta[iTrack][1];
128  double fQOvP = trackMomenta[iTrack][2];
129  BilloirTrack<input_track_t> currentBilloirTrack(trackContainer,
130  linTrack);
131 
132  currentBilloirTrack.deltaQ << d0, z0, phi - fPhi, theta - fTheta,
133  qOverP - fQOvP, 0;
134 
135  // position jacobian (D matrix)
137  Dmat = linTrack.positionJacobian;
138 
139  // momentum jacobian (E matrix)
141  Emat = linTrack.momentumJacobian;
142  // cache some matrix multiplications
145  BoundSymMatrix Wi = linTrack.weightAtPCA;
146 
147  DtWmat = Dmat.transpose() * Wi;
148  EtWmat = Emat.transpose() * Wi;
149 
150  // compute billoir tracks
151  currentBilloirTrack.DiMat = Dmat;
152  currentBilloirTrack.EiMat = Emat;
153  currentBilloirTrack.CiMat = EtWmat * Emat;
154  currentBilloirTrack.BiMat = DtWmat * Emat; // DiMat^T * Wi * EiMat
155  currentBilloirTrack.UiVec =
156  EtWmat * currentBilloirTrack.deltaQ; // EiMat^T * Wi * dqi
157  currentBilloirTrack.CiInv =
158  (EtWmat * Emat).inverse(); // (EiMat^T * Wi * EiMat)^-1
159 
160  // sum up over all tracks
161  billoirVertex.Tvec +=
162  DtWmat * currentBilloirTrack.deltaQ; // sum{DiMat^T * Wi * dqi}
163  billoirVertex.Amat += DtWmat * Dmat; // sum{DiMat^T * Wi * DiMat}
164 
165  // remember those results for all tracks
166  currentBilloirTrack.BCiMat =
167  currentBilloirTrack.BiMat *
168  currentBilloirTrack.CiInv; // BCi = BiMat * Ci^-1
169 
170  // and some summed results
171  billoirVertex.BCUvec +=
172  currentBilloirTrack.BCiMat *
173  currentBilloirTrack.UiVec; // sum{BiMat * Ci^-1 * UiVec}
174  billoirVertex.BCBmat +=
175  currentBilloirTrack.BCiMat *
176  currentBilloirTrack.BiMat
177  .transpose(); // sum{BiMat * Ci^-1 * BiMat^T}
178 
179  billoirTracks.push_back(currentBilloirTrack);
180  ++iTrack;
181  } else {
182  return result.error();
183  }
184  } // end loop tracks
185 
186  // calculate delta (billoirFrameOrigin-position), might be changed by the
187  // beam-const
188  // Vdel = Tvec-sum{BiMat*Ci^-1*UiVec}
189  Vector4D Vdel = billoirVertex.Tvec - billoirVertex.BCUvec;
190  SymMatrix4D VwgtMat =
191  billoirVertex.Amat -
192  billoirVertex.BCBmat; // VwgtMat = Amat-sum{BiMat*Ci^-1*BiMat^T}
193  if (isConstraintFit) {
194  // this will be 0 for first iteration but != 0 from second on
195  Vector4D posInBilloirFrame =
196  vertexingOptions.vertexConstraint.fullPosition() - linPoint;
197 
198  Vdel += vertexingOptions.vertexConstraint.fullCovariance().inverse() *
199  posInBilloirFrame;
200  VwgtMat += vertexingOptions.vertexConstraint.fullCovariance().inverse();
201  }
202 
203  // cov(deltaV) = VwgtMat^-1
204  SymMatrix4D covDeltaVmat = VwgtMat.inverse();
205  // deltaV = cov_(deltaV) * Vdel;
206  Vector4D deltaV = covDeltaVmat * Vdel;
207  //--------------------------------------------------------------------------------------
208  // start momentum related calculations
209 
210  std::vector<std::optional<BoundSymMatrix>> covDeltaPmat(nTracks);
211 
212  iTrack = 0;
213  for (auto& bTrack : billoirTracks) {
214  Vector3D deltaP =
215  (bTrack.CiInv) * (bTrack.UiVec - bTrack.BiMat.transpose() * deltaV);
216 
217  // update track momenta
218  trackMomenta[iTrack] += deltaP;
219 
220  // correct for 2PI / PI periodicity
221  auto correctedPhiTheta = detail::ensureThetaBounds(
222  trackMomenta[iTrack][0], trackMomenta[iTrack][1]);
223 
224  trackMomenta[iTrack][0] = correctedPhiTheta.first;
225  trackMomenta[iTrack][1] = correctedPhiTheta.second;
226 
227  // calculate 5x5 covdelta_P matrix
228  // d(d0,z0,phi,theta,qOverP, t)/d(x,y,z,phi,theta,qOverP,
229  // t)-transformation matrix
231  transMat.setZero();
232  transMat(0, 0) = bTrack.DiMat(0, 0);
233  transMat(0, 1) = bTrack.DiMat(0, 1);
234  transMat(1, 0) = bTrack.DiMat(1, 0);
235  transMat(1, 1) = bTrack.DiMat(1, 1);
236  transMat(1, 2) = 1.;
237  transMat(2, 3) = 1.;
238  transMat(3, 4) = 1.;
239  transMat(4, 5) = 1.;
240  transMat(5, 6) = 1.;
241 
242  // some intermediate calculations to get 5x5 matrix
243  // cov(V,V), 4x4 matrix
244  SymMatrix4D VVmat = covDeltaVmat;
245 
246  // cov(V,P)
247  ActsMatrixD<4, 3> VPmat = bTrack.BiMat;
248 
249  // cov(P,P), 3x3 matrix
250  ActsSymMatrixD<3> PPmat;
251  PPmat = bTrack.CiInv +
252  bTrack.BCiMat.transpose() * covDeltaVmat * bTrack.BCiMat;
253 
254  ActsSymMatrixD<7> covMat;
255  covMat.setZero();
256  covMat.block<4, 4>(0, 0) = VVmat;
257  covMat.block<4, 3>(0, 4) = VPmat;
258  covMat.block<3, 4>(4, 0) = VPmat.transpose();
259 
260  covMat.block<3, 3>(4, 4) = PPmat;
261 
262  // covdelta_P calculation
263  covDeltaPmat[iTrack] = transMat * covMat * transMat.transpose();
264  // Calculate chi2 per track.
265  bTrack.chi2 =
266  ((bTrack.deltaQ - bTrack.DiMat * deltaV - bTrack.EiMat * deltaP)
267  .transpose())
268  .dot(bTrack.linTrack.weightAtPCA *
269  (bTrack.deltaQ - bTrack.DiMat * deltaV -
270  bTrack.EiMat * deltaP));
271  newChi2 += bTrack.chi2;
272 
273  ++iTrack;
274  }
275 
276  if (isConstraintFit) {
277  // last term will also be 0 again but only in the first iteration
278  // = calc. vtx in billoir frame - ( isConstraintFit pos. in billoir
279  // frame )
280 
281  Vector4D deltaTrk =
282  deltaV -
283  (vertexingOptions.vertexConstraint.fullPosition() - linPoint);
284 
285  newChi2 +=
286  (deltaTrk.transpose())
287  .dot(
288  vertexingOptions.vertexConstraint.fullCovariance().inverse() *
289  deltaTrk);
290  }
291 
292  if (!std::isnormal(newChi2)) {
293  return VertexingError::NumericFailure;
294  }
295 
296  // assign new linearization point (= new vertex position in global frame)
297  linPoint += deltaV;
298  if (newChi2 < chi2) {
299  chi2 = newChi2;
300 
301  Vector4D vertexPos(linPoint);
302 
303  fittedVertex.setFullPosition(vertexPos);
304  fittedVertex.setFullCovariance(covDeltaVmat);
305  fittedVertex.setFitQuality(chi2, ndf);
306 
307  std::vector<TrackAtVertex<input_track_t>> tracksAtVertex;
308 
309  std::shared_ptr<PerigeeSurface> perigee =
310  Surface::makeShared<PerigeeSurface>(
311  VectorHelpers::position(vertexPos));
312 
313  iTrack = 0;
314  for (auto& bTrack : billoirTracks) {
315  // new refitted trackparameters
316  BoundVector paramVec = BoundVector::Zero();
317  paramVec[eBoundPhi] = trackMomenta[iTrack](0);
318  paramVec[eBoundTheta] = trackMomenta[iTrack](1);
319  paramVec[eBoundQOverP] = trackMomenta[iTrack](2);
320  BoundTrackParameters refittedParams(perigee, paramVec,
321  covDeltaPmat[iTrack]);
322  TrackAtVertex<input_track_t> trackVx(bTrack.chi2, refittedParams,
323  bTrack.originalTrack);
324  tracksAtVertex.push_back(std::move(trackVx));
325  ++iTrack;
326  }
327  fittedVertex.setTracksAtVertex(tracksAtVertex);
328  }
329  } // end loop iterations
330  return fittedVertex;
331 }