Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EDM4hepUtil.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EDM4hepUtil.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022 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 
14 
15 #include "edm4hep/TrackState.h"
16 
17 namespace Acts {
18 namespace EDM4hepUtil {
19 namespace detail {
20 
21 ActsSquareMatrix<6> jacobianToEdm4hep(double theta, double qOverP, double Bz) {
22  // Calculate jacobian from our internal parametrization (d0, z0, phi, theta,
23  // q/p) to the LCIO / edm4hep (see:
24  // https://bib-pubdb1.desy.de/record/81214/files/LC-DET-2006-004%5B1%5D.pdf)
25  // one (d0, z0, phi, tan(lambda), omega). Top left 3x3 matrix in the
26  // jacobian is 1. Bottom right 2x2 matrix is:
27  //
28  // [ d ]
29  // [------(cot(theta)) 0 ]
30  // [dtheta ]
31  // [ ]
32  // [ d / B*q/p \ d / B*q/p \]
33  // [------|----------| ----|----------|]
34  // [dtheta\sin(theta)/ dq/p\sin(theta)/]
35  //
36  // =
37  //
38  // [ 2 ]
39  // [- cot (theta) - 1 0 ]
40  // [ ]
41  // [-B*q/p*cos(theta) B ]
42  // [------------------ ----------]
43  // [ 2 sin(theta)]
44  // [ sin (theta) ]
45 
47  J.setIdentity();
48  double cotTheta = std::tan(M_PI_2 + theta);
49  J(3, 3) = -cotTheta * cotTheta - 1; // d(tanLambda) / dTheta
50  J(4, 4) = Bz / std::sin(theta); // dOmega / d(qop)
51  double sinTheta = std::sin(theta);
52  J(4, 3) = -Bz * qOverP * std::cos(theta) /
53  (sinTheta * sinTheta); // dOmega / dTheta
54  return J;
55 }
56 
57 ActsSquareMatrix<6> jacobianFromEdm4hep(double tanLambda, double omega,
58  double Bz) {
59  // [ d / pi\ ]
60  // [------------|-atan(\tan\lambda) + --| 0 ]
61  // [d\tan\lambda\ 2 / ]
62  // [ ]
63  // [ d / \Omega \ d / \Omega \]
64  // [------------|-----------------------| -------|-----------------------|]
65  // [d\tan\lambda| __________________| d\Omega| __________________|]
66  // [ | / 2 | | / 2 |]
67  // [ \B*\/ \tan\lambda + 1 / \B*\/ \tan\lambda + 1 /]
68  //
69  // =
70  //
71  // [ -1 ]
72  // [ ---------------- 0 ]
73  // [ 2 ]
74  // [ \tan\lambda + 1 ]
75  // [ ]
76  // [ -\Omega*\tan\lambda 1 ]
77  // [----------------------- -----------------------]
78  // [ 3/2 __________________]
79  // [ / 2 \ / 2 ]
80  // [B*\\tan\lambda + 1/ B*\/ \tan\lambda + 1 ]
81 
83  J.setIdentity();
84  J(3, 3) = -1 / (tanLambda * tanLambda + 1);
85  J(4, 3) = -1 * omega * tanLambda /
86  (Bz * std::pow(tanLambda * tanLambda + 1, 3. / 2.));
87  J(4, 4) = 1 / (Bz * std::hypot(tanLambda, 1));
88 
89  return J;
90 }
91 
92 void packCovariance(const ActsSquareMatrix<6>& from, float* to) {
93  for (int i = 0; i < from.rows(); i++) {
94  for (int j = 0; j <= i; j++) {
95  size_t k = (i + 1) * i / 2 + j;
96  to[k] = from(i, j);
97  }
98  }
99 }
100 
101 void unpackCovariance(const float* from, ActsSquareMatrix<6>& to) {
102  auto k = [](size_t i, size_t j) { return (i + 1) * i / 2 + j; };
103  for (int i = 0; i < to.rows(); i++) {
104  for (int j = 0; j < to.cols(); j++) {
105  to(i, j) = from[j <= i ? k(i, j) : k(j, i)];
106  }
107  }
108 }
109 
111  double Bz,
112  const BoundTrackParameters& params) {
113  Acts::Vector3 global = params.referenceSurface().localToGlobal(
114  gctx, params.parameters().template head<2>(), params.direction());
115 
116  std::shared_ptr<const Acts::Surface> refSurface =
117  params.referenceSurface().getSharedPtr();
118 
119  Acts::BoundVector targetPars = params.parameters();
120  std::optional<Acts::FreeVector> freePars;
121 
122  auto makeFreePars = [&]() {
124  params.referenceSurface(), gctx, params.parameters());
125  };
126 
127  // If the reference surface is a perigee surface, we use that. Otherwise
128  // we create a new perigee surface at the global position of the track
129  // parameters.
130  if (dynamic_cast<const Acts::PerigeeSurface*>(refSurface.get()) == nullptr) {
131  refSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(global);
132 
133  // We need to convert to the target parameters
134  // Keep the free parameters around we might need them for the covariance
135  // conversion
136  freePars = makeFreePars();
137  targetPars = Acts::detail::transformFreeToBoundParameters(freePars.value(),
138  *refSurface, gctx)
139  .value();
140  }
141 
142  Parameters result;
143  result.surface = refSurface;
144 
145  // Only run covariance conversion if we have a covariance input
146  if (params.covariance()) {
147  auto boundToFree =
148  refSurface->boundToFreeJacobian(gctx, params.parameters());
149  Acts::FreeMatrix freeCov =
150  boundToFree * params.covariance().value() * boundToFree.transpose();
151 
152  // ensure we have free pars
153  if (!freePars.has_value()) {
154  freePars = makeFreePars();
155  }
156 
157  Acts::CovarianceCache covCache{freePars.value(), freeCov};
158  auto [varNewCov, varNewJac] = Acts::transportCovarianceToBound(
159  gctx, *refSurface, freePars.value(), covCache);
160  auto targetCov = std::get<Acts::BoundSquareMatrix>(varNewCov);
161 
163  targetPars[eBoundTheta], targetPars[eBoundQOverP], Bz);
164  Acts::ActsSquareMatrix<6> cIn = targetCov.template topLeftCorner<6, 6>();
165  result.covariance = J * cIn * J.transpose();
166  }
167 
168  result.values[0] = targetPars[Acts::eBoundLoc0];
169  result.values[1] = targetPars[Acts::eBoundLoc1];
170  result.values[2] = targetPars[Acts::eBoundPhi];
171  result.values[3] = std::tan(M_PI_2 - targetPars[Acts::eBoundTheta]);
172  result.values[4] = targetPars[Acts::eBoundQOverP] /
173  std::sin(targetPars[Acts::eBoundTheta]) * Bz;
174  result.values[5] = targetPars[Acts::eBoundTime];
175 
176  result.particleHypothesis = params.particleHypothesis();
177 
178  return result;
179 }
180 
182  double Bz, const Parameters& params) {
183  BoundVector targetPars;
184 
186  jacobianFromEdm4hep(params.values[3], params.values[4], Bz);
187 
188  std::optional<BoundMatrix> cov;
189  if (params.covariance.has_value()) {
190  cov = J * params.covariance.value() * J.transpose();
191  }
192 
193  targetPars[eBoundLoc0] = params.values[0];
194  targetPars[eBoundLoc1] = params.values[1];
195  targetPars[eBoundPhi] = params.values[2];
196  targetPars[eBoundTheta] = M_PI_2 - std::atan(params.values[3]);
197  targetPars[eBoundQOverP] =
198  params.values[4] * std::sin(targetPars[eBoundTheta]) / Bz;
199  targetPars[eBoundTime] = params.values[5];
200 
201  return {params.surface, targetPars, cov, params.particleHypothesis};
202 }
203 
204 } // namespace detail
205 } // namespace EDM4hepUtil
206 } // namespace Acts