ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PropagationTestHelper.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PropagationTestHelper.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-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 
9 #pragma once
10 
11 #include <limits>
12 
19 
20 namespace tt = boost::test_tools;
21 
22 namespace Acts {
23 namespace IntegrationTest {
24 
26 
27 // Create a test context
30 
38 std::shared_ptr<Transform3D> createPlanarTransform(const Vector3D& nposition,
39  const Vector3D& nnormal,
40  double angleT,
41  double angleU) {
42  // the rotation of the destination surface
43  Vector3D T = nnormal.normalized();
44  Vector3D U = std::abs(T.dot(Vector3D::UnitZ())) < 0.99
45  ? Vector3D::UnitZ().cross(T).normalized()
46  : Vector3D::UnitX().cross(T).normalized();
47  Vector3D V = T.cross(U);
48  // that's the plane curvilinear Rotation
49  RotationMatrix3D curvilinearRotation;
50  curvilinearRotation.col(0) = U;
51  curvilinearRotation.col(1) = V;
52  curvilinearRotation.col(2) = T;
53  // curvilinear surfaces are boundless
54  Transform3D ctransform{curvilinearRotation};
55  ctransform.pretranslate(nposition);
56  ctransform.prerotate(AngleAxis3D(angleT, T));
57  ctransform.prerotate(AngleAxis3D(angleU, U));
58  //
59  return std::make_shared<Transform3D>(ctransform);
60 }
61 
69 std::shared_ptr<Transform3D> createCylindricTransform(const Vector3D& nposition,
70  double angleX,
71  double angleY) {
72  Transform3D ctransform;
73  ctransform.setIdentity();
74  ctransform.pretranslate(nposition);
75  ctransform.prerotate(AngleAxis3D(angleX, Vector3D::UnitX()));
76  ctransform.prerotate(AngleAxis3D(angleY, Vector3D::UnitY()));
77  return std::make_shared<Transform3D>(ctransform);
78 }
79 
80 template <typename Propagator_type>
81 Vector3D constant_field_propagation(const Propagator_type& propagator,
82  double pT, double phi, double theta,
83  double charge, double time, double Bz,
84  double disttol = 0.1 *
86  bool debug = false) {
87  using namespace Acts::UnitLiterals;
88  namespace VH = VectorHelpers;
89 
90  // setup propagation options
92  options.pathLimit = 5_m;
93  options.maxStepSize = 1_cm;
94  options.debug = debug;
95 
96  // define start parameters
97  double x = 0;
98  double y = 0;
99  double z = 0;
100  double px = pT * cos(phi);
101  double py = pT * sin(phi);
102  double pz = pT / tan(theta);
103  double q = charge;
104  Vector3D pos(x, y, z);
105  Vector3D mom(px, py, pz);
106  CurvilinearParameters pars(std::nullopt, pos, mom, q, time);
107 
108  // do propagation
109  const auto& tp = propagator.propagate(pars, options).value().endParameters;
110 
111  // test propagation invariants
112  // clang-format off
113  CHECK_CLOSE_ABS(pT, VH::perp(tp->momentum()), 1_keV);
114  CHECK_CLOSE_ABS(pz, tp->momentum()(2), 1_keV);
115  CHECK_CLOSE_ABS(theta, VH::theta(tp->momentum()), 1e-4);
116  // clang-format on
117 
118  double r = (q * Bz != 0.) ? std::abs(pT / (q * Bz))
120 
121  // calculate number of turns of helix
122  double turns = options.pathLimit / (2 * M_PI * r) * sin(theta);
123  // respect direction of curl
124  turns = (q * Bz < 0) ? turns : -turns;
125 
126  // calculate expected final momentum direction in phi in [-pi,pi]
127  double exp_phi = std::fmod(phi + turns * 2 * M_PI, 2 * M_PI);
128  if (exp_phi < -M_PI) {
129  exp_phi += 2 * M_PI;
130  }
131  if (exp_phi > M_PI) {
132  exp_phi -= 2 * M_PI;
133  }
134 
135  // calculate expected position
136  double exp_z = z + pz / pT * 2 * M_PI * r * std::abs(turns);
137 
138  // calculate center of bending circle in transverse plane
139  double xc, yc;
140  // offset with respect to starting point
141  double dx = r * cos(M_PI / 2 - phi);
142  double dy = r * sin(M_PI / 2 - phi);
143  if (q * Bz < 0) {
144  xc = x - dx;
145  yc = y + dy;
146  } else {
147  xc = x + dx;
148  yc = y - dy;
149  }
150  // phi position of starting point in bending circle
151  double phi0 = std::atan2(y - yc, x - xc);
152 
153  // calculated expected position in transverse plane
154  double exp_x = xc + r * cos(phi0 + turns * 2 * M_PI);
155  double exp_y = yc + r * sin(phi0 + turns * 2 * M_PI);
156 
157  // clang-format off
158  CHECK_CLOSE_ABS(exp_phi, VH::phi(tp->momentum()), 1e-4);
159  CHECK_CLOSE_ABS(exp_x, tp->position()(0), disttol);
160  CHECK_CLOSE_ABS(exp_y, tp->position()(1), disttol);
161  CHECK_CLOSE_ABS(exp_z, tp->position()(2), disttol);
162  // clang-format on
163  return tp->position();
164 }
165 
166 template <typename Propagator_type>
167 void foward_backward(const Propagator_type& propagator, double pT, double phi,
168  double theta, double charge, double plimit,
169  double disttol = 1 * Acts::UnitConstants::um,
170  double momtol = 10 * Acts::UnitConstants::keV,
171  bool debug = false) {
172  using namespace Acts::UnitLiterals;
173 
174  // setup propagation options
175  // Action list and abort list
178 
180  fwdOptions.pathLimit = plimit;
181  fwdOptions.maxStepSize = 1_cm;
182  fwdOptions.debug = debug;
183 
185  bwdOptions.direction = backward;
186  bwdOptions.pathLimit = -plimit;
187  bwdOptions.maxStepSize = 1_cm;
188  bwdOptions.debug = debug;
189 
190  // define start parameters
191  double x = 0;
192  double y = 0;
193  double z = 0;
194  double px = pT * cos(phi);
195  double py = pT * sin(phi);
196  double pz = pT / tan(theta);
197  double q = charge;
198  double time = 0.;
199  Vector3D pos(x, y, z);
200  Vector3D mom(px, py, pz);
201  CurvilinearParameters start(std::nullopt, pos, mom, q, time);
202 
203  // do forward-backward propagation
204  const auto& fwdResult = propagator.propagate(start, fwdOptions).value();
205  const auto& bwdResult =
206  propagator.propagate(*fwdResult.endParameters, bwdOptions).value();
207 
208  const Vector3D& bwdPosition = bwdResult.endParameters->position();
209  const Vector3D& bwdMomentum = bwdResult.endParameters->momentum();
210 
211  // test propagation invariants
212  // clang-format off
213  CHECK_CLOSE_ABS(x, bwdPosition(0), disttol);
214  CHECK_CLOSE_ABS(y, bwdPosition(1), disttol);
215  CHECK_CLOSE_ABS(z, bwdPosition(2), disttol);
216  CHECK_CLOSE_ABS(px, bwdMomentum(0), momtol);
217  CHECK_CLOSE_ABS(py, bwdMomentum(1), momtol);
218  CHECK_CLOSE_ABS(pz, bwdMomentum(2), momtol);
219  // clang-format on
220 
221  if (debug) {
222  auto fwdOutput = fwdResult.template get<DebugOutput::result_type>();
223  std::cout << ">>>>> Output for forward propagation " << std::endl;
224  std::cout << fwdOutput.debugString << std::endl;
225  std::cout << " - resulted at position : "
226  << fwdResult.endParameters->position() << std::endl;
227 
228  auto bwdOutput = bwdResult.template get<DebugOutput::result_type>();
229  std::cout << ">>>>> Output for backward propagation " << std::endl;
230  std::cout << bwdOutput.debugString << std::endl;
231  std::cout << " - resulted at position : "
232  << bwdResult.endParameters->position() << std::endl;
233  }
234 }
235 
236 // test propagation to cylinder
237 template <typename Propagator_type>
238 std::pair<Vector3D, double> to_cylinder(
239  const Propagator_type& propagator, double pT, double phi, double theta,
240  double charge, double plimit, double rand1, double rand2, double /*rand3*/,
241  bool covtransport = false, bool debug = false) {
242  using namespace Acts::UnitLiterals;
243 
244  // setup propagation options
246  // setup propagation options
247  options.maxStepSize = plimit * 0.1;
248  options.pathLimit = plimit;
249  options.debug = debug;
250 
251  // define start parameters
252  double x = 0;
253  double y = 0;
254  double z = 0;
255  double px = pT * cos(phi);
256  double py = pT * sin(phi);
257  double pz = pT / tan(theta);
258  double q = charge;
259  double time = 0.;
260  Vector3D pos(x, y, z);
261  Vector3D mom(px, py, pz);
262 
263  std::optional<Covariance> covOpt = std::nullopt;
264  if (covtransport) {
265  Covariance cov;
266  // take some major correlations (off-diagonals)
267  // clang-format off
268  cov <<
269  10_mm, 0, 0.123, 0, 0.5, 0,
270  0, 10_mm, 0, 0.162, 0, 0,
271  0.123, 0, 0.1, 0, 0, 0,
272  0, 0.162, 0, 0.1, 0, 0,
273  0.5, 0, 0, 0, 1_e / 10_GeV, 0,
274  0, 0, 0, 0, 0, 1_us;
275  // clang-format on
276  covOpt = cov;
277  }
278 
279  // The transform at the destination
280  auto seTransform = createCylindricTransform(Vector3D(0., 0., 0.),
281  0.04 * rand1, 0.04 * rand2);
282  auto endSurface = Surface::makeShared<CylinderSurface>(
283  seTransform, plimit, std::numeric_limits<double>::max());
284 
285  // Increase the path limit - to be safe hitting the surface
286  options.pathLimit *= 2;
287 
288  if (q == 0.) {
289  auto start = new NeutralCurvilinearParameters(covOpt, pos, mom, time);
290 
291  const auto result =
292  propagator.propagate(*start, *endSurface, options).value();
293  const auto& tp = result.endParameters;
294  // check for null pointer
295  BOOST_CHECK(tp != nullptr);
296  // The position and path length
297  return std::pair<Vector3D, double>(tp->position(), result.pathLength);
298  } else {
299  auto start = new CurvilinearParameters(covOpt, pos, mom, q, time);
300 
301  const auto result =
302  propagator.propagate(*start, *endSurface, options).value();
303  const auto& tp = result.endParameters;
304  // check for null pointer
305  BOOST_CHECK(tp != nullptr);
306  // The position and path length
307  return std::pair<Vector3D, double>(tp->position(), result.pathLength);
308  }
309 }
310 
311 // test propagation to most surfaces
312 template <typename Propagator_type, typename SurfaceType>
313 std::pair<Vector3D, double> to_surface(
314  const Propagator_type& propagator, double pT, double phi, double theta,
315  double charge, double plimit, double rand1, double rand2, double rand3,
316  bool planar = true, bool covtransport = false, bool debug = false) {
317  using namespace Acts::UnitLiterals;
319 
320  // setup propagation options
322  // setup propagation options
323  options.maxStepSize = plimit;
324  options.pathLimit = plimit;
325  options.debug = debug;
326 
327  // define start parameters
328  double x = 0;
329  double y = 0;
330  double z = 0;
331  double px = pT * cos(phi);
332  double py = pT * sin(phi);
333  double pz = pT / tan(theta);
334  double q = charge;
335  double time = 0.;
336  Vector3D pos(x, y, z);
337  Vector3D mom(px, py, pz);
338 
339  std::optional<Covariance> covOpt = std::nullopt;
340  if (covtransport) {
341  Covariance cov;
342  // take some major correlations (off-diagonals)
343  // clang-format off
344  cov <<
345  10_mm, 0, 0.123, 0, 0.5, 0,
346  0, 10_mm, 0, 0.162, 0, 0,
347  0.123, 0, 0.1, 0, 0, 0,
348  0, 0.162, 0, 0.1, 0, 0,
349  0.5, 0, 0, 0, 1_e / 10_GeV, 0,
350  0, 0, 0, 0, 0, 1_us;
351  // clang-format on
352  covOpt = cov;
353  }
354  // Create curvilinear start parameters
355  if (q == 0.) {
356  auto start = new NeutralCurvilinearParameters(covOpt, pos, mom, time);
357  const auto result_s = propagator.propagate(*start, options).value();
358  const auto& tp_s = result_s.endParameters;
359  // The transform at the destination
360  auto seTransform =
361  planar ? createPlanarTransform(tp_s->position(),
362  tp_s->momentum().normalized(),
363  0.1 * rand3, 0.1 * rand1)
364  : createCylindricTransform(tp_s->position(), 0.04 * rand1,
365  0.04 * rand2);
366 
367  auto endSurface = Surface::makeShared<SurfaceType>(seTransform, nullptr);
368  // Increase the path limit - to be safe hitting the surface
369  options.pathLimit *= 2;
370 
371  if (debug) {
372  std::cout << ">>> Path limit for this propgation is set to: "
373  << options.pathLimit << std::endl;
374  }
375 
376  auto result = propagator.propagate(*start, *endSurface, options);
377  const auto& propRes = *result;
378  const auto& tp = propRes.endParameters;
379  // check the result for nullptr
380  BOOST_CHECK(tp != nullptr);
381 
382  // screen output in case you are running in debug mode
383  if (debug) {
384  const auto& debugOutput =
385  propRes.template get<DebugOutput::result_type>();
386  std::cout << ">>> Debug output of this propagation " << std::endl;
387  std::cout << debugOutput.debugString << std::endl;
388  std::cout << ">>> Propagation status is : ";
389  if (result.ok()) {
390  std::cout << "success";
391  } else {
392  std::cout << result.error();
393  }
394  std::cout << std::endl;
395  }
396 
397  // The position and path length
398  return std::pair<Vector3D, double>(tp->position(), propRes.pathLength);
399  } else {
400  auto start = new CurvilinearParameters(covOpt, pos, mom, q, time);
401  const auto result_s = propagator.propagate(*start, options).value();
402  const auto& tp_s = result_s.endParameters;
403  // The transform at the destination
404  auto seTransform =
405  planar ? createPlanarTransform(tp_s->position(),
406  tp_s->momentum().normalized(),
407  0.1 * rand3, 0.1 * rand1)
408  : createCylindricTransform(tp_s->position(), 0.04 * rand1,
409  0.04 * rand2);
410 
411  auto endSurface = Surface::makeShared<SurfaceType>(seTransform, nullptr);
412  // Increase the path limit - to be safe hitting the surface
413  options.pathLimit *= 2;
414 
415  if (debug) {
416  std::cout << ">>> Path limit for this propgation is set to: "
417  << options.pathLimit << std::endl;
418  }
419 
420  auto result = propagator.propagate(*start, *endSurface, options);
421  const auto& propRes = *result;
422  const auto& tp = propRes.endParameters;
423  // check the result for nullptr
424  BOOST_CHECK(tp != nullptr);
425 
426  // screen output in case you are running in debug mode
427  if (debug) {
428  const auto& debugOutput =
429  propRes.template get<DebugOutput::result_type>();
430  std::cout << ">>> Debug output of this propagation " << std::endl;
431  std::cout << debugOutput.debugString << std::endl;
432  std::cout << ">>> Propagation status is : ";
433  if (result.ok()) {
434  std::cout << "success";
435  } else {
436  std::cout << result.error();
437  }
438  std::cout << std::endl;
439  }
440  // The position and path length
441  return std::pair<Vector3D, double>(tp->position(), propRes.pathLength);
442  }
443 }
444 
445 template <typename Propagator_type>
446 Covariance covariance_curvilinear(const Propagator_type& propagator, double pT,
447  double phi, double theta, double charge,
448  double plimit, bool debug = false) {
449  using namespace Acts::UnitLiterals;
450 
451  // setup propagation options
453  options.maxStepSize = plimit;
454  options.pathLimit = 0.1 * plimit;
455  options.debug = debug;
456  options.tolerance = 1e-9;
457 
458  // define start parameters
459  double x = 1.;
460  double y = 0.;
461  double z = 0.;
462  double px = pT * cos(phi);
463  double py = pT * sin(phi);
464  double pz = pT / tan(theta);
465  double q = charge;
466  double time = 0.;
467  Vector3D pos(x, y, z);
468  Vector3D mom(px, py, pz);
469 
470  Covariance cov;
471  // take some major correlations (off-diagonals)
472  // clang-format off
473  cov <<
474  10_mm, 0, 0.123, 0, 0.5, 0,
475  0, 10_mm, 0, 0.162, 0, 0,
476  0.123, 0, 0.1, 0, 0, 0,
477  0, 0.162, 0, 0.1, 0, 0,
478  0.5, 0, 0, 0, 1_e / 10_GeV, 0,
479  0, 0, 0, 0, 0, 1_us;
480  // clang-format on
481 
482  // do propagation of the start parameters
483  CurvilinearParameters start(cov, pos, mom, q, time);
484 
485  const auto result = propagator.propagate(start, options).value();
486  const auto& tp = result.endParameters;
487 
488  return *(tp->covariance());
489 }
490 
491 template <typename Propagator_type, typename StartSurfaceType,
492  typename DestSurfaceType>
493 Covariance covariance_bound(const Propagator_type& propagator, double pT,
494  double phi, double theta, double charge,
495  double plimit, double rand1, double rand2,
496  double rand3, bool startPlanar = true,
497  bool destPlanar = true, bool debug = false) {
498  using namespace Acts::UnitLiterals;
499 
500  // setup propagation options
502  options.maxStepSize = 0.1 * plimit;
503  options.pathLimit = plimit;
504  options.debug = debug;
505 
506  // define start parameters
507  double x = 1.;
508  double y = 0.;
509  double z = 0.;
510  double px = pT * cos(phi);
511  double py = pT * sin(phi);
512  double pz = pT / tan(theta);
513  double q = charge;
514  double time = 0.;
515  Vector3D pos(x, y, z);
516  Vector3D mom(px, py, pz);
517  Covariance cov;
518 
519  // take some major correlations (off-diagonals)
520  // clang-format off
521  cov <<
522  10_mm, 0, 0.123, 0, 0.5, 0,
523  0, 10_mm, 0, 0.162, 0, 0,
524  0.123, 0, 0.1, 0, 0, 0,
525  0, 0.162, 0, 0.1, 0, 0,
526  0.5, 0, 0, 0, 1_e / 10_GeV, 0,
527  0, 0, 0, 0, 0, 1_us;
528  // clang-format on
529 
530  // create curvilinear start parameters
531  CurvilinearParameters start_c(std::nullopt, pos, mom, q, time);
532  const auto result_c = propagator.propagate(start_c, options).value();
533  const auto& tp_c = result_c.endParameters;
534 
535  auto ssTransform =
536  startPlanar ? createPlanarTransform(pos, mom.normalized(), 0.05 * rand1,
537  0.05 * rand2)
538  : createCylindricTransform(pos, 0.01 * rand1, 0.01 * rand2);
539  auto seTransform = destPlanar
540  ? createPlanarTransform(tp_c->position(),
541  tp_c->momentum().normalized(),
542  0.05 * rand3, 0.05 * rand1)
543  : createCylindricTransform(tp_c->position(),
544  0.01 * rand1, 0.01 * rand2);
545 
546  auto startSurface =
547  Surface::makeShared<StartSurfaceType>(ssTransform, nullptr);
548  BoundParameters start(tgContext, cov, pos, mom, q, time, startSurface);
549 
550  // increase the path limit - to be safe hitting the surface
551  options.pathLimit *= 2;
552 
553  auto endSurface = Surface::makeShared<DestSurfaceType>(seTransform, nullptr);
554  const auto result = propagator.propagate(start, *endSurface, options).value();
555  const auto& tp = result.endParameters;
556 
557  // get obtained covariance matrix
558  return *(tp->covariance());
559 }
560 } // namespace IntegrationTest
561 } // namespace Acts