Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CovarianceEngine.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CovarianceEngine.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019-2020 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 
10 
20 
21 #include <algorithm>
22 #include <cmath>
23 #include <optional>
24 #include <system_error>
25 #include <type_traits>
26 #include <utility>
27 
28 namespace Acts {
29 namespace {
31 using Jacobian = BoundMatrix;
32 
33 using BoundState = std::tuple<BoundTrackParameters, Jacobian, double>;
34 using CurvilinearState =
35  std::tuple<CurvilinearTrackParameters, Jacobian, double>;
36 
43  // Optimized trigonometry on the propagation direction
44  const double x = direction(0); // == cos(phi) * sin(theta)
45  const double y = direction(1); // == sin(phi) * sin(theta)
46  const double z = direction(2); // == cos(theta)
47  // can be turned into cosine/sine
48  const double cosTheta = z;
49  const double sinTheta = std::hypot(x, y);
50  const double invSinTheta = 1. / sinTheta;
51  const double cosPhi = x * invSinTheta;
52  const double sinPhi = y * invSinTheta;
53  // prepare the jacobian to curvilinear
54  FreeToBoundMatrix jacToCurv = FreeToBoundMatrix::Zero();
55  if (std::abs(cosTheta) < s_curvilinearProjTolerance) {
56  // We normally operate in curvilinear coordinates defined as follows
57  jacToCurv(0, 0) = -sinPhi;
58  jacToCurv(0, 1) = cosPhi;
59  jacToCurv(1, 0) = -cosPhi * cosTheta;
60  jacToCurv(1, 1) = -sinPhi * cosTheta;
61  jacToCurv(1, 2) = sinTheta;
62  } else {
63  // Under grazing incidence to z, the above coordinate system definition
64  // becomes numerically unstable, and we need to switch to another one
65  const double c = std::hypot(y, z);
66  const double invC = 1. / c;
67  jacToCurv(0, 1) = -z * invC;
68  jacToCurv(0, 2) = y * invC;
69  jacToCurv(1, 0) = c;
70  jacToCurv(1, 1) = -x * y * invC;
71  jacToCurv(1, 2) = -x * z * invC;
72  }
73  // Time parameter
74  jacToCurv(5, 3) = 1.;
75  // Directional and momentum parameters for curvilinear
76  jacToCurv(2, 4) = -sinPhi * invSinTheta;
77  jacToCurv(2, 5) = cosPhi * invSinTheta;
78  jacToCurv(3, 4) = cosPhi * cosTheta;
79  jacToCurv(3, 5) = sinPhi * cosTheta;
80  jacToCurv(3, 6) = -sinTheta;
81  jacToCurv(4, 7) = 1.;
82 
83  return jacToCurv;
84 }
85 
107 void boundToBoundJacobian(const GeometryContext& geoContext,
108  const FreeVector& freeParameters,
109  const BoundToFreeMatrix& boundToFreeJacobian,
110  const FreeMatrix& freeTransportJacobian,
111  const FreeVector& freeToPathDerivatives,
112  BoundMatrix& fullTransportJacobian,
113  const Surface& surface) {
114  // Calculate the derivative of path length at the final surface or the
115  // point-of-closest approach w.r.t. free parameters
116  const FreeToPathMatrix freeToPath =
117  surface.freeToPathDerivative(geoContext, freeParameters);
118  // Calculate the jacobian from free to bound at the final surface
119  FreeToBoundMatrix freeToBoundJacobian =
120  surface.freeToBoundJacobian(geoContext, freeParameters);
121  // Calculate the full jacobian from the local/bound parameters at the start
122  // surface to local/bound parameters at the final surface
123  // @note jac(locA->locB) = jac(gloB->locB)*(1+
124  // pathCorrectionFactor(gloB))*jacTransport(gloA->gloB) *jac(locA->gloA)
125  fullTransportJacobian =
126  freeToBoundJacobian *
127  (FreeMatrix::Identity() + freeToPathDerivatives * freeToPath) *
128  freeTransportJacobian * boundToFreeJacobian;
129 }
130 
153 void boundToCurvilinearJacobian(const Vector3& direction,
154  const BoundToFreeMatrix& boundToFreeJacobian,
155  const FreeMatrix& freeTransportJacobian,
156  const FreeVector& freeToPathDerivatives,
157  BoundMatrix& fullTransportJacobian) {
158  // Calculate the jacobian from global to local at the curvilinear surface
159  FreeToBoundMatrix freeToBoundJacobian = freeToCurvilinearJacobian(direction);
160 
161  // Update the jacobian to include the derivative of the path length at the
162  // curvilinear surface w.r.t. the free parameters
163  freeToBoundJacobian.topLeftCorner<6, 3>() +=
164  (freeToBoundJacobian * freeToPathDerivatives) *
165  (-1.0 * direction).transpose();
166 
167  // Calculate the full jocobian from the local parameters at the start surface
168  // to curvilinear parameters
169  // @note jac(locA->locB) = jac(gloB->locB)*(1+
170  // pathCorrectionFactor(gloB))*jacTransport(gloA->gloB) *jac(locA->gloA)
171  fullTransportJacobian =
172  blockedMult(freeToBoundJacobian,
173  blockedMult(freeTransportJacobian, boundToFreeJacobian));
174 }
175 
188 Result<void> reinitializeJacobians(const GeometryContext& geoContext,
189  FreeMatrix& freeTransportJacobian,
190  FreeVector& freeToPathDerivatives,
191  BoundToFreeMatrix& boundToFreeJacobian,
192  const FreeVector& freeParameters,
193  const Surface& surface) {
194  using VectorHelpers::phi;
195  using VectorHelpers::theta;
196 
197  // Reset the jacobians
198  freeTransportJacobian = FreeMatrix::Identity();
199  freeToPathDerivatives = FreeVector::Zero();
200 
201  // Get the local position
202  const Vector3 position = freeParameters.segment<3>(eFreePos0);
203  const Vector3 direction = freeParameters.segment<3>(eFreeDir0);
204  auto lpResult = surface.globalToLocal(geoContext, position, direction);
205  if (not lpResult.ok()) {
206  return lpResult.error();
207  }
208  // Transform from free to bound parameters
209  Result<BoundVector> boundParameters = detail::transformFreeToBoundParameters(
210  freeParameters, surface, geoContext);
211  if (!boundParameters.ok()) {
212  return boundParameters.error();
213  }
214  // Reset the jacobian from local to global
215  boundToFreeJacobian =
216  surface.boundToFreeJacobian(geoContext, *boundParameters);
217  return Result<void>::success();
218 }
219 
230 void reinitializeJacobians(FreeMatrix& freeTransportJacobian,
231  FreeVector& freeToPathDerivatives,
232  BoundToFreeMatrix& boundToFreeJacobian,
233  const Vector3& direction) {
234  // Reset the jacobians
235  freeTransportJacobian = FreeMatrix::Identity();
236  freeToPathDerivatives = FreeVector::Zero();
237  boundToFreeJacobian = BoundToFreeMatrix::Zero();
238 
239  // Optimized trigonometry on the propagation direction
240  const double x = direction(0); // == cos(phi) * sin(theta)
241  const double y = direction(1); // == sin(phi) * sin(theta)
242  const double z = direction(2); // == cos(theta)
243  // can be turned into cosine/sine
244  const double cosTheta = z;
245  const double sinTheta = std::hypot(x, y);
246  const double invSinTheta = 1. / sinTheta;
247  const double cosPhi = x * invSinTheta;
248  const double sinPhi = y * invSinTheta;
249 
250  boundToFreeJacobian(eFreePos0, eBoundLoc0) = -sinPhi;
251  boundToFreeJacobian(eFreePos0, eBoundLoc1) = -cosPhi * cosTheta;
252  boundToFreeJacobian(eFreePos1, eBoundLoc0) = cosPhi;
253  boundToFreeJacobian(eFreePos1, eBoundLoc1) = -sinPhi * cosTheta;
254  boundToFreeJacobian(eFreePos2, eBoundLoc1) = sinTheta;
255  boundToFreeJacobian(eFreeTime, eBoundTime) = 1;
256  boundToFreeJacobian(eFreeDir0, eBoundPhi) = -sinTheta * sinPhi;
257  boundToFreeJacobian(eFreeDir0, eBoundTheta) = cosTheta * cosPhi;
258  boundToFreeJacobian(eFreeDir1, eBoundPhi) = sinTheta * cosPhi;
259  boundToFreeJacobian(eFreeDir1, eBoundTheta) = cosTheta * sinPhi;
260  boundToFreeJacobian(eFreeDir2, eBoundTheta) = -sinTheta;
261  boundToFreeJacobian(eFreeQOverP, eBoundQOverP) = 1;
262 }
263 } // namespace
264 
265 namespace detail {
266 
268  const GeometryContext& geoContext, BoundSquareMatrix& covarianceMatrix,
269  BoundMatrix& jacobian, FreeMatrix& transportJacobian,
270  FreeVector& derivatives, BoundToFreeMatrix& jacToGlobal,
272  bool covTransport, double accumulatedPath, const Surface& surface,
273  const FreeToBoundCorrection& freeToBoundCorrection) {
274  // Covariance transport
275  std::optional<BoundSquareMatrix> cov = std::nullopt;
276  if (covTransport) {
277  // Initialize the jacobian from start local to final local
278  jacobian = BoundMatrix::Identity();
279  // Calculate the jacobian and transport the covarianceMatrix to final local.
280  // Then reinitialize the transportJacobian, derivatives and the
281  // jacToGlobal
282  transportCovarianceToBound(geoContext, covarianceMatrix, jacobian,
283  transportJacobian, derivatives, jacToGlobal,
284  parameters, surface, freeToBoundCorrection);
285  }
286  if (covarianceMatrix != BoundSquareMatrix::Zero()) {
287  cov = covarianceMatrix;
288  }
289 
290  // Create the bound parameters
292  detail::transformFreeToBoundParameters(parameters, surface, geoContext);
293  if (!bv.ok()) {
294  return bv.error();
295  }
296  // Create the bound state
297  return std::make_tuple(
298  BoundTrackParameters(surface.getSharedPtr(), *bv, std::move(cov),
300  jacobian, accumulatedPath);
301 }
302 
303 CurvilinearState curvilinearState(BoundSquareMatrix& covarianceMatrix,
304  BoundMatrix& jacobian,
305  FreeMatrix& transportJacobian,
306  FreeVector& derivatives,
307  BoundToFreeMatrix& jacToGlobal,
308  const FreeVector& parameters,
310  bool covTransport, double accumulatedPath) {
311  const Vector3& direction = parameters.segment<3>(eFreeDir0);
312 
313  // Covariance transport
314  std::optional<BoundSquareMatrix> cov = std::nullopt;
315  if (covTransport) {
316  // Initialize the jacobian from start local to final local
317  jacobian = BoundMatrix::Identity();
318  // Calculate the jacobian and transport the covarianceMatrix to final local.
319  // Then reinitialize the transportJacobian, derivatives and the
320  // jacToGlobal
321  transportCovarianceToCurvilinear(covarianceMatrix, jacobian,
322  transportJacobian, derivatives,
323  jacToGlobal, direction);
324  }
325  if (covarianceMatrix != BoundSquareMatrix::Zero()) {
326  cov = covarianceMatrix;
327  }
328 
329  // Create the curvilinear parameters
330  Vector4 pos4 = Vector4::Zero();
331  pos4[ePos0] = parameters[eFreePos0];
332  pos4[ePos1] = parameters[eFreePos1];
333  pos4[ePos2] = parameters[eFreePos2];
334  pos4[eTime] = parameters[eFreeTime];
335  CurvilinearTrackParameters curvilinearParams(
336  pos4, direction, parameters[eFreeQOverP], std::move(cov),
337  particleHypothesis);
338  // Create the curvilinear state
339  return std::make_tuple(std::move(curvilinearParams), jacobian,
340  accumulatedPath);
341 }
342 
344  const GeometryContext& geoContext, BoundSquareMatrix& boundCovariance,
345  BoundMatrix& fullTransportJacobian, FreeMatrix& freeTransportJacobian,
346  FreeVector& freeToPathDerivatives, BoundToFreeMatrix& boundToFreeJacobian,
347  FreeVector& freeParameters, const Surface& surface,
348  const FreeToBoundCorrection& freeToBoundCorrection) {
349  // Calculate the full jacobian from local parameters at the start surface to
350  // current bound parameters
351  boundToBoundJacobian(geoContext, freeParameters, boundToFreeJacobian,
352  freeTransportJacobian, freeToPathDerivatives,
353  fullTransportJacobian, surface);
354 
355  bool correction = false;
356  if (freeToBoundCorrection) {
357  BoundToFreeMatrix startBoundToFinalFreeJacobian =
358  freeTransportJacobian * boundToFreeJacobian;
359  FreeSquareMatrix freeCovariance = startBoundToFinalFreeJacobian *
360  boundCovariance *
361  startBoundToFinalFreeJacobian.transpose();
362 
363  auto transformer =
364  detail::CorrectedFreeToBoundTransformer(freeToBoundCorrection);
365  auto correctedRes =
366  transformer(freeParameters, freeCovariance, surface, geoContext);
367 
368  if (correctedRes.has_value()) {
369  auto correctedValue = correctedRes.value();
370  BoundVector boundParams = std::get<BoundVector>(correctedValue);
371  // 1. Update the free parameters with the corrected bound parameters
373  surface, geoContext, boundParams);
374 
375  // 2. Update the bound covariance
376  boundCovariance = std::get<BoundSquareMatrix>(correctedValue);
377 
378  correction = true;
379  }
380  }
381 
382  if (not correction) {
383  // Apply the actual covariance transport to get covariance of the current
384  // bound parameters
385  boundCovariance = fullTransportJacobian * boundCovariance *
386  fullTransportJacobian.transpose();
387  }
388 
389  // Reinitialize jacobian components:
390  // ->The transportJacobian is reinitialized to Identity
391  // ->The derivatives is reinitialized to Zero
392  // ->The boundToFreeJacobian is initialized to that at the current surface
393  reinitializeJacobians(geoContext, freeTransportJacobian,
394  freeToPathDerivatives, boundToFreeJacobian,
395  freeParameters, surface);
396 }
397 
399  BoundMatrix& fullTransportJacobian,
400  FreeMatrix& freeTransportJacobian,
401  FreeVector& freeToPathDerivatives,
402  BoundToFreeMatrix& boundToFreeJacobian,
403  const Vector3& direction) {
404  // Calculate the full jacobian from local parameters at the start surface to
405  // current curvilinear parameters
406  boundToCurvilinearJacobian(direction, boundToFreeJacobian,
407  freeTransportJacobian, freeToPathDerivatives,
408  fullTransportJacobian);
409 
410  // Apply the actual covariance transport to get covariance of the current
411  // curvilinear parameters
412  boundCovariance = fullTransportJacobian * boundCovariance *
413  fullTransportJacobian.transpose();
414 
415  // Reinitialize jacobian components:
416  // ->The free transportJacobian is reinitialized to Identity
417  // ->The path derivatives is reinitialized to Zero
418  // ->The boundToFreeJacobian is reinitialized to that at the current
419  // curvilinear surface
420  reinitializeJacobians(freeTransportJacobian, freeToPathDerivatives,
421  boundToFreeJacobian, direction);
422 }
423 
424 } // namespace detail
425 } // namespace Acts