EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ImpactPointEstimator.ipp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ImpactPointEstimator.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 template <typename input_track_t, typename propagator_t,
16  typename propagator_options_t>
20  const BoundTrackParameters& trkParams,
21  const Vector3D& vtxPos, State& state) const {
23  Vector3D momDir;
24 
25  auto res =
26  getDistanceAndMomentum(gctx, trkParams, vtxPos, deltaR, momDir, state);
27 
28  if (!res.ok()) {
29  return res.error();
30  }
31 
32  // Return distance
33  return deltaR.norm();
34 }
35 
36 template <typename input_track_t, typename propagator_t,
37  typename propagator_options_t>
41  const Acts::MagneticFieldContext& mctx,
42  const BoundTrackParameters& trkParams,
43  const Vector3D& vtxPos, State& state) const {
45  Vector3D momDir;
46 
47  auto res =
48  getDistanceAndMomentum(gctx, trkParams, vtxPos, deltaR, momDir, state);
49 
50  if (!res.ok()) {
51  return res.error();
52  }
53 
54  // Normalize deltaR
55  deltaR.normalize();
56 
57  // corrected deltaR for small deviations from orthogonality
58  Vector3D corrDeltaR = deltaR - (deltaR.dot(momDir)) * momDir;
59 
60  // get perpendicular direction vector
61  Vector3D perpDir = momDir.cross(corrDeltaR);
62 
63  Transform3D thePlane;
64  // rotation matrix
65  thePlane.matrix().block(0, 0, 3, 1) = corrDeltaR;
66  thePlane.matrix().block(0, 1, 3, 1) = perpDir;
67  thePlane.matrix().block(0, 2, 3, 1) = momDir;
68  // translation
69  thePlane.matrix().block(0, 3, 3, 1) = vtxPos;
70 
71  std::shared_ptr<PlaneSurface> planeSurface =
72  Surface::makeShared<PlaneSurface>(thePlane);
73 
74  // Create propagator options
75  auto logger = getDefaultLogger("IPEstProp", Logging::INFO);
76  propagator_options_t pOptions(gctx, mctx, LoggerWrapper{*logger});
77  pOptions.direction = backward;
78 
79  // Do the propagation to linPointPos
80  auto result = m_cfg.propagator->propagate(trkParams, *planeSurface, pOptions);
81  if (result.ok()) {
82  return std::move((*result).endParameters);
83  } else {
84  return result.error();
85  }
86 }
87 
88 template <typename input_track_t, typename propagator_t,
89  typename propagator_options_t>
93  const BoundTrackParameters* trkParams,
94  const Vector3D& vertexPos) const {
95  if (trkParams == nullptr) {
96  return VertexingError::EmptyInput;
97  }
98 
99  // surface rotation
100  RotationMatrix3D myRotation =
101  trkParams->referenceSurface().transform(gctx).rotation();
102  // Surface translation
103  Vector3D myTranslation =
104  trkParams->referenceSurface().transform(gctx).translation();
105 
106  // x and y direction of plane
107  Vector3D xDirPlane = myRotation.col(0);
108  Vector3D yDirPlane = myRotation.col(1);
109 
110  // transform vertex position in local plane reference frame
111  Vector3D vertexLocPlane = vertexPos - myTranslation;
112 
113  // local x/y vertex position
114  Vector2D vertexLocXY{vertexLocPlane.dot(xDirPlane),
115  vertexLocPlane.dot(yDirPlane)};
116 
117  // track covariance
118  auto cov = trkParams->covariance();
119  SymMatrix2D myWeightXY = cov->block<2, 2>(0, 0).inverse();
120 
121  // 2-dim residual
122  Vector2D myXYpos =
123  Vector2D(trkParams->parameters()[eX], trkParams->parameters()[eY]) -
124  vertexLocXY;
125 
126  // return chi2
127  return myXYpos.dot(myWeightXY * myXYpos);
128 }
129 
130 template <typename input_track_t, typename propagator_t,
131  typename propagator_options_t>
133  input_track_t, propagator_t,
134  propagator_options_t>::performNewtonApproximation(const Vector3D& trkPos,
135  const Vector3D& vtxPos,
136  double phi, double theta,
137  double r) const {
138  double sinNewPhi = -std::sin(phi);
139  double cosNewPhi = std::cos(phi);
140 
141  int nIter = 0;
142  bool hasConverged = false;
143 
144  double cotTheta = 1. / std::tan(theta);
145 
146  // start iteration until convergence or max iteration reached
147  while (!hasConverged && nIter < m_cfg.maxIterations) {
148  double x0 = trkPos.x();
149  double y0 = trkPos.y();
150  double z0 = trkPos.z();
151 
152  double xc = vtxPos.x();
153  double yc = vtxPos.y();
154  double zc = vtxPos.z();
155 
156  double derivative = (x0 - xc) * (-r * cosNewPhi) +
157  (y0 - yc) * r * sinNewPhi +
158  (z0 - zc - r * phi * cotTheta) * (-r * cotTheta);
159  double secDerivative = r * (-(x0 - xc) * sinNewPhi - (y0 - yc) * cosNewPhi +
160  r * cotTheta * cotTheta);
161 
162  if (secDerivative < 0.) {
163  return VertexingError::NumericFailure;
164  }
165 
166  double deltaPhi = -derivative / secDerivative;
167 
168  phi += deltaPhi;
169  sinNewPhi = -std::sin(phi);
170  cosNewPhi = std::cos(phi);
171 
172  nIter += 1;
173 
174  if (std::abs(deltaPhi) < m_cfg.precision) {
175  hasConverged = true;
176  }
177  } // end while loop
178 
179  if (!hasConverged) {
180  // max iterations reached but did not converge
181  return VertexingError::NotConverged;
182  }
183  return phi;
184 }
185 
186 template <typename input_track_t, typename propagator_t,
187  typename propagator_options_t>
191  const BoundTrackParameters& trkParams,
192  const Vector3D& vtxPos, Vector3D& deltaR,
193  Vector3D& momDir, State& state) const {
194  Vector3D trkSurfaceCenter = trkParams.referenceSurface().center(gctx);
195 
196  double d0 = trkParams.parameters()[BoundIndices::eBoundLoc0];
197  double z0 = trkParams.parameters()[BoundIndices::eBoundLoc1];
198  double phi = trkParams.parameters()[BoundIndices::eBoundPhi];
199  double theta = trkParams.parameters()[BoundIndices::eBoundTheta];
200  double qOvP = trkParams.parameters()[BoundIndices::eBoundQOverP];
201 
202  double sinTheta = std::sin(theta);
203 
204  double cotTheta = 1. / std::tan(theta);
205 
206  // get B-field z-component at current position
207  double bZ = m_cfg.bField.getField(trkSurfaceCenter, state.fieldCache)[eZ];
208 
209  // The radius
210  double r;
211  // Curvature is infinite w/o b field
212  if (bZ == 0. || std::abs(qOvP) < m_cfg.minQoP) {
213  r = m_cfg.maxRho;
214  } else {
215  // signed(!) r
216  r = sinTheta * (1. / qOvP) / bZ;
217  }
218 
219  Vector3D vec0 = trkSurfaceCenter + Vector3D(-(d0 - r) * std::sin(phi),
220  (d0 - r) * std::cos(phi),
221  z0 + r * phi * cotTheta);
222 
223  // Perform newton approximation method
224  // this will change the value of phi
225  auto res = performNewtonApproximation(vec0, vtxPos, phi, theta, r);
226  if (!res.ok()) {
227  return res.error();
228  }
229  // Set new phi value
230  phi = *res;
231 
232  double cosPhi = std::cos(phi);
233  double sinPhi = std::sin(phi);
234 
235  // Set momentum direction
236  momDir = Vector3D(sinTheta * cosPhi, sinPhi * sinTheta, std::cos(theta));
237 
238  // point of closest approach in 3D
239  Vector3D pointCA3d = vec0 + r * Vector3D(-sinPhi, cosPhi, -cotTheta * phi);
240 
241  // Set deltaR
242  deltaR = pointCA3d - vtxPos;
243 
244  return {};
245 }
246 
247 template <typename input_track_t, typename propagator_t,
248  typename propagator_options_t>
252  const Vertex<input_track_t>& vtx,
253  const GeometryContext& gctx,
254  const Acts::MagneticFieldContext& mctx) const {
255  // estimating the d0 and its significance by propagating the trajectory state
256  // towards
257  // the vertex position. By this time the vertex should NOT contain this
258  // trajectory anymore
259  const std::shared_ptr<PerigeeSurface> perigeeSurface =
260  Surface::makeShared<PerigeeSurface>(vtx.position());
261 
262  // Create propagator options
263  auto logger = getDefaultLogger("IPEstProp", Logging::INFO);
264  propagator_options_t pOptions(gctx, mctx, LoggerWrapper{*logger});
265  pOptions.direction = backward;
266 
267  // Do the propagation to linPoint
268  auto result = m_cfg.propagator->propagate(track, *perigeeSurface, pOptions);
269 
270  if (!result.ok()) {
271  return result.error();
272  }
273 
274  const auto& propRes = *result;
275  const auto& params = propRes.endParameters->parameters();
276  const double d0 = params[BoundIndices::eBoundLoc0];
277  const double z0 = params[BoundIndices::eBoundLoc1];
278  const double phi = params[BoundIndices::eBoundPhi];
279  const double theta = params[BoundIndices::eBoundTheta];
280 
281  const double sinPhi = std::sin(phi);
282  const double sinTheta = std::sin(theta);
283  const double cosPhi = std::cos(phi);
284  const double cosTheta = std::cos(theta);
285 
286  SymMatrix2D vrtXYCov = vtx.covariance().template block<2, 2>(0, 0);
287 
288  // Covariance of perigee parameters after propagation to perigee surface
289  const auto& perigeeCov = *(propRes.endParameters->covariance());
290 
291  Vector2D d0JacXY(-sinPhi, cosPhi);
292 
293  ImpactParametersAndSigma newIPandSigma;
294 
295  newIPandSigma.IPd0 = d0;
296  double d0_PVcontrib = d0JacXY.transpose() * (vrtXYCov * d0JacXY);
297  if (d0_PVcontrib >= 0) {
298  newIPandSigma.sigmad0 =
299  std::sqrt(d0_PVcontrib + perigeeCov(BoundIndices::eBoundLoc0,
301  newIPandSigma.PVsigmad0 = std::sqrt(d0_PVcontrib);
302  } else {
303  newIPandSigma.sigmad0 = std::sqrt(
305  newIPandSigma.PVsigmad0 = 0;
306  }
307 
308  SymMatrix2D covPerigeeZ0Theta;
309  covPerigeeZ0Theta(0, 0) =
311  covPerigeeZ0Theta(0, 1) =
313  covPerigeeZ0Theta(1, 0) =
315  covPerigeeZ0Theta(1, 1) =
317 
318  double vtxZZCov = vtx.covariance()(eZ, eZ);
319 
320  Vector2D z0JacZ0Theta(sinTheta, z0 * cosTheta);
321 
322  if (vtxZZCov >= 0) {
323  newIPandSigma.IPz0SinTheta = z0 * sinTheta;
324  newIPandSigma.sigmaz0SinTheta = std::sqrt(
325  z0JacZ0Theta.transpose() * (covPerigeeZ0Theta * z0JacZ0Theta) +
326  sinTheta * vtxZZCov * sinTheta);
327 
328  newIPandSigma.PVsigmaz0SinTheta = std::sqrt(sinTheta * vtxZZCov * sinTheta);
329  newIPandSigma.IPz0 = z0;
330  newIPandSigma.sigmaz0 =
331  std::sqrt(vtxZZCov + perigeeCov(BoundIndices::eBoundLoc1,
333  newIPandSigma.PVsigmaz0 = std::sqrt(vtxZZCov);
334  } else {
335  // Remove contribution from PV
336  newIPandSigma.IPz0SinTheta = z0 * sinTheta;
337  double sigma2z0sinTheta =
338  (z0JacZ0Theta.transpose() * (covPerigeeZ0Theta * z0JacZ0Theta));
339  newIPandSigma.sigmaz0SinTheta = std::sqrt(sigma2z0sinTheta);
340  newIPandSigma.PVsigmaz0SinTheta = 0;
341 
342  newIPandSigma.IPz0 = z0;
343  newIPandSigma.sigmaz0 = std::sqrt(
345  newIPandSigma.PVsigmaz0 = 0;
346  }
347 
348  return newIPandSigma;
349 }