EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AtlasStepperTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file AtlasStepperTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 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 
9 #include <boost/test/test_tools.hpp>
10 #include <boost/test/unit_test.hpp>
11 
21 #include "Acts/Utilities/Units.hpp"
22 
23 namespace Acts {
24 namespace Test {
25 
26 using namespace Acts::UnitLiterals;
31 
35  : stepping(std::move(stepperState)) {}
36 
40  struct {
41  double mass = 1_GeV;
42  double tolerance = 10_um;
43  } options;
44 };
45 
46 // epsilon for floating point comparisons
47 static constexpr auto eps = 1024 * std::numeric_limits<double>::epsilon();
48 
49 // propagation settings
50 static constexpr auto stepSize = 10_mm;
51 static constexpr auto tolerance = 10_um;
52 static constexpr NavigationDirection navDir = backward;
53 static const ConstantBField magneticField(Vector3D(0.1_T, -0.2_T, 2_T));
54 
55 // initial parameter state
56 static const Vector4D pos4(1_mm, -1_mm, 2_mm, 2_ns);
57 static const Vector3D pos = pos4.segment<3>(ePos0);
58 static const auto time = pos4[eTime];
59 static const Vector3D unitDir = Vector3D(-2, 2, 1).normalized();
60 static constexpr auto absMom = 1_GeV;
61 static constexpr auto charge = -1_e;
62 static const Covariance cov = Covariance::Identity();
63 
64 // context objects
65 static const GeometryContext geoCtx;
67 
68 BOOST_AUTO_TEST_SUITE(AtlasStepper)
69 
70 // test state construction from parameters w/o covariance
71 BOOST_AUTO_TEST_CASE(ConstructState) {
72  Stepper::State state(
75 
76  BOOST_CHECK(!state.covTransport);
77  BOOST_CHECK_EQUAL(state.covariance, nullptr);
78  BOOST_CHECK_EQUAL(state.pVector[0], pos.x());
79  BOOST_CHECK_EQUAL(state.pVector[1], pos.y());
80  BOOST_CHECK_EQUAL(state.pVector[2], pos.z());
81  BOOST_CHECK_EQUAL(state.pVector[3], time);
82  CHECK_CLOSE_ABS(state.pVector[4], unitDir.x(), eps);
83  CHECK_CLOSE_ABS(state.pVector[5], unitDir.y(), eps);
84  CHECK_CLOSE_ABS(state.pVector[6], unitDir.z(), eps);
85  BOOST_CHECK_EQUAL(state.pVector[7], charge / absMom);
86  BOOST_CHECK_EQUAL(state.navDir, navDir);
87  BOOST_CHECK_EQUAL(state.pathAccumulated, 0.);
88  BOOST_CHECK_EQUAL(state.stepSize, navDir * stepSize);
89  BOOST_CHECK_EQUAL(state.previousStepSize, 0.);
90  BOOST_CHECK_EQUAL(state.tolerance, tolerance);
91 }
92 
93 // test state construction from parameters w/ covariance
94 BOOST_AUTO_TEST_CASE(ConstructStateWithCovariance) {
95  Stepper::State state(
96  geoCtx, magCtx,
99 
100  BOOST_CHECK(state.covTransport);
101  BOOST_CHECK_EQUAL(*state.covariance, cov);
102  BOOST_CHECK_EQUAL(state.pVector[0], pos.x());
103  BOOST_CHECK_EQUAL(state.pVector[1], pos.y());
104  BOOST_CHECK_EQUAL(state.pVector[2], pos.z());
105  BOOST_CHECK_EQUAL(state.pVector[3], time);
106  CHECK_CLOSE_ABS(state.pVector[4], unitDir.x(), eps);
107  CHECK_CLOSE_ABS(state.pVector[5], unitDir.y(), eps);
108  CHECK_CLOSE_ABS(state.pVector[6], unitDir.z(), eps);
109  BOOST_CHECK_EQUAL(state.pVector[7], charge / absMom);
110  BOOST_CHECK_EQUAL(state.navDir, navDir);
111  BOOST_CHECK_EQUAL(state.pathAccumulated, 0.);
112  BOOST_CHECK_EQUAL(state.stepSize, navDir * stepSize);
113  BOOST_CHECK_EQUAL(state.previousStepSize, 0.);
114  BOOST_CHECK_EQUAL(state.tolerance, tolerance);
115 }
116 
117 // test stepper getters for particle state
120  Stepper::State state(
121  geoCtx, magCtx,
124 
125  CHECK_CLOSE_ABS(stepper.position(state), pos, eps);
126  CHECK_CLOSE_ABS(stepper.time(state), time, eps);
127  CHECK_CLOSE_ABS(stepper.direction(state), unitDir, eps);
128  CHECK_CLOSE_ABS(stepper.momentum(state), absMom, eps);
129  BOOST_CHECK_EQUAL(stepper.charge(state), charge);
130 }
131 
132 // test stepper update methods with bound state as input
133 BOOST_AUTO_TEST_CASE(UpdateFromBound) {
135  Stepper::State state(
136  geoCtx, magCtx,
139 
140  auto newPos4 = (pos4 + Vector4D(1_mm, 2_mm, 3_mm, 20_ns)).eval();
141  auto newPos = newPos4.segment<3>(ePos0);
142  auto newTime = newPos4[eTime];
143  auto newUnitDir = (unitDir + Vector3D(1, -1, -1)).normalized();
144  auto newAbsMom = 0.9 * absMom;
145 
146  // example surface and bound parameters at the updated position
147  auto plane = Surface::makeShared<PlaneSurface>(newPos, newUnitDir);
148  BoundTrackParameters params(plane, geoCtx, newPos4, newUnitDir, charge, cov);
149  FreeVector freeParams;
150  freeParams[eFreePos0] = newPos4[ePos0];
151  freeParams[eFreePos1] = newPos4[ePos1];
152  freeParams[eFreePos2] = newPos4[ePos2];
153  freeParams[eFreeTime] = newPos4[eTime];
154  freeParams[eFreeDir0] = newUnitDir[eMom0];
155  freeParams[eFreeDir1] = newUnitDir[eMom1];
156  freeParams[eFreeDir2] = newUnitDir[eMom2];
157  freeParams[eFreeQOverP] = charge / newAbsMom;
158 
159  // WARNING for some reason there seems to be an additional flag that makes
160  // the update method not do anything when it is set. Why?
161  state.state_ready = false;
162  stepper.update(state, freeParams, *params.covariance());
163  CHECK_CLOSE_ABS(stepper.position(state), newPos, eps);
164  CHECK_CLOSE_ABS(stepper.time(state), newTime, eps);
165  CHECK_CLOSE_ABS(stepper.direction(state), newUnitDir, eps);
166  CHECK_CLOSE_ABS(stepper.momentum(state), newAbsMom, eps);
167  BOOST_CHECK_EQUAL(stepper.charge(state), charge);
168 }
169 
170 // test stepper update methods with individual components as input
171 BOOST_AUTO_TEST_CASE(UpdateFromComponents) {
173  Stepper::State state(
174  geoCtx, magCtx,
177 
178  auto newPos = (pos + Vector3D(1_mm, 2_mm, 3_mm)).eval();
179  auto newTime = time + 20_ns;
180  auto newUnitDir = (unitDir + Vector3D(1, -1, -1)).normalized();
181  auto newAbsMom = 0.9 * absMom;
182 
183  stepper.update(state, newPos, newUnitDir, newAbsMom, newTime);
184  CHECK_CLOSE_ABS(stepper.position(state), newPos, eps);
185  CHECK_CLOSE_ABS(stepper.time(state), newTime, eps);
186  CHECK_CLOSE_ABS(stepper.direction(state), newUnitDir, eps);
187  CHECK_CLOSE_ABS(stepper.momentum(state), newAbsMom, eps);
188  BOOST_CHECK_EQUAL(stepper.charge(state), charge);
189 }
190 
191 // test building a bound state object from the stepper state
192 BOOST_AUTO_TEST_CASE(BuildBound) {
194  Stepper::State state(
195  geoCtx, magCtx,
198  // example surface at the current state position
199  auto plane = Surface::makeShared<PlaneSurface>(pos, unitDir);
200 
201  auto&& [pars, jac, pathLength] = stepper.boundState(state, *plane);
202  // check parameters
203  CHECK_CLOSE_ABS(pars.position(geoCtx), pos, eps);
204  CHECK_CLOSE_ABS(pars.time(), time, eps);
205  CHECK_CLOSE_ABS(pars.momentum(), absMom * unitDir, eps);
206  BOOST_CHECK_EQUAL(pars.charge(), charge);
207  BOOST_CHECK(pars.covariance().has_value());
208  BOOST_CHECK_NE(*pars.covariance(), cov);
209  // check Jacobian. should be identity since there was no propagation yet
210  CHECK_CLOSE_ABS(jac, Jacobian(Jacobian::Identity()), eps);
211  // check propagation length
213 }
214 
215 // test building a curvilinear state object from the stepper state
216 BOOST_AUTO_TEST_CASE(BuildCurvilinear) {
218  Stepper::State state(
219  geoCtx, magCtx,
222 
223  auto&& [pars, jac, pathLength] = stepper.curvilinearState(state);
224  // check parameters
225  CHECK_CLOSE_ABS(pars.position(geoCtx), pos, eps);
226  CHECK_CLOSE_ABS(pars.time(), time, eps);
227  CHECK_CLOSE_ABS(pars.momentum(), absMom * unitDir, eps);
228  BOOST_CHECK_EQUAL(pars.charge(), charge);
229  BOOST_CHECK(pars.covariance().has_value());
230  BOOST_CHECK_NE(*pars.covariance(), cov);
231  // check Jacobian. should be identity since there was no propagation yet
232  CHECK_CLOSE_ABS(jac, Jacobian(Jacobian::Identity()), eps);
233  // check propagation length
235 }
236 
237 // test step method without covariance transport
241  geoCtx, magCtx,
243  stepSize, tolerance));
244  state.stepping.covTransport = false;
245 
246  // ensure step does not result in an error
247  auto res = stepper.step(state);
248  BOOST_CHECK(res.ok());
249 
250  // extract the actual step size
251  auto h = res.value();
252  BOOST_CHECK_EQUAL(state.stepping.stepSize, navDir * stepSize);
253  BOOST_CHECK_EQUAL(state.stepping.stepSize, h);
254 
255  // check that the position has moved
256  auto deltaPos = (stepper.position(state.stepping) - pos).eval();
257  BOOST_CHECK_LT(0, deltaPos.norm());
258  // check that time has changed
259  auto deltaTime = stepper.time(state.stepping) - time;
260  BOOST_CHECK_LT(0, std::abs(deltaTime));
261  // check that the direction was rotated
262  auto projDir = stepper.direction(state.stepping).dot(unitDir);
263  BOOST_CHECK_LT(projDir, 1);
264 
265  // momentum and charge should not change
266  CHECK_CLOSE_ABS(stepper.momentum(state.stepping), absMom, eps);
267  BOOST_CHECK_EQUAL(stepper.charge(state.stepping), charge);
268 }
269 
270 // test step method with covariance transport
271 BOOST_AUTO_TEST_CASE(StepWithCovariance) {
274  geoCtx, magCtx,
276  stepSize, tolerance));
277  state.stepping.covTransport = true;
278 
279  // ensure step does not result in an error
280  auto res = stepper.step(state);
281  BOOST_CHECK(res.ok());
282 
283  // extract the actual step size
284  auto h = res.value();
285  BOOST_CHECK_EQUAL(state.stepping.stepSize, navDir * stepSize);
286  BOOST_CHECK_EQUAL(state.stepping.stepSize, h);
287 
288  // check that the position has moved
289  auto deltaPos = (stepper.position(state.stepping) - pos).eval();
290  BOOST_CHECK_LT(0, deltaPos.norm());
291  // check that time has changed
292  auto deltaTime = stepper.time(state.stepping) - time;
293  BOOST_CHECK_LT(0, std::abs(deltaTime));
294  // check that the direction was rotated
295  auto projDir = stepper.direction(state.stepping).dot(unitDir);
296  BOOST_CHECK_LT(projDir, 1);
297 
298  // momentum and charge should not change
299  CHECK_CLOSE_ABS(stepper.momentum(state.stepping), absMom, eps);
300  BOOST_CHECK_EQUAL(stepper.charge(state.stepping), charge);
301 
302  stepper.covarianceTransport(state.stepping);
303  BOOST_CHECK_NE(state.stepping.cov, cov);
304 }
305 
306 // test state reset method
310  geoCtx, magCtx,
312  stepSize, tolerance));
313  state.stepping.covTransport = true;
314 
315  // ensure step does not result in an error
316  stepper.step(state);
317 
318  // Construct the parameters
319  Vector3D pos(1.5, -2.5, 3.5);
320  Vector3D mom(4.5, -5.5, 6.5);
321  double time = 7.5;
322  double charge = 1.;
323  BoundSymMatrix cov = 8.5 * Covariance::Identity();
324  CurvilinearTrackParameters cp(makeVector4(pos, time), unitDir, absMom, charge,
325  cov);
327  cp.referenceSurface(), geoCtx, cp.parameters());
329  double stepSize = -256.;
330 
331  // Reset all possible parameters
332  Stepper::State stateCopy(state.stepping);
333  stepper.resetState(stateCopy, cp.parameters(), *cp.covariance(),
334  cp.referenceSurface(), ndir, stepSize);
335  // Test all components
336  BOOST_CHECK(stateCopy.covTransport);
337  BOOST_CHECK_EQUAL(*stateCopy.covariance, cov);
338  BOOST_CHECK_EQUAL(stepper.position(stateCopy),
339  freeParams.template segment<3>(eFreePos0));
340  BOOST_CHECK_EQUAL(stepper.direction(stateCopy),
341  freeParams.template segment<3>(eFreeDir0).normalized());
342  BOOST_CHECK_EQUAL(stepper.momentum(stateCopy),
343  std::abs(1. / freeParams[eFreeQOverP]));
344  BOOST_CHECK_EQUAL(stepper.charge(stateCopy), stepper.charge(state.stepping));
345  BOOST_CHECK_EQUAL(stepper.time(stateCopy), freeParams[eFreeTime]);
346  BOOST_CHECK_EQUAL(stateCopy.navDir, ndir);
347  BOOST_CHECK_EQUAL(stateCopy.pathAccumulated, 0.);
348  BOOST_CHECK_EQUAL(stateCopy.stepSize, ndir * stepSize);
349  BOOST_CHECK_EQUAL(stateCopy.previousStepSize,
350  state.stepping.previousStepSize);
351  BOOST_CHECK_EQUAL(stateCopy.tolerance, state.stepping.tolerance);
352 
353  // Reset all possible parameters except the step size
354  stateCopy = state.stepping;
355  stepper.resetState(stateCopy, cp.parameters(), *cp.covariance(),
356  cp.referenceSurface(), ndir);
357  // Test all components
358  BOOST_CHECK(stateCopy.covTransport);
359  BOOST_CHECK_EQUAL(*stateCopy.covariance, cov);
360  BOOST_CHECK_EQUAL(stepper.position(stateCopy),
361  freeParams.template segment<3>(eFreePos0));
362  BOOST_CHECK_EQUAL(stepper.direction(stateCopy),
363  freeParams.template segment<3>(eFreeDir0).normalized());
364  BOOST_CHECK_EQUAL(stepper.momentum(stateCopy),
365  std::abs(1. / freeParams[eFreeQOverP]));
366  BOOST_CHECK_EQUAL(stepper.charge(stateCopy), stepper.charge(state.stepping));
367  BOOST_CHECK_EQUAL(stepper.time(stateCopy), freeParams[eFreeTime]);
368  BOOST_CHECK_EQUAL(stateCopy.navDir, ndir);
369  BOOST_CHECK_EQUAL(stateCopy.pathAccumulated, 0.);
370  BOOST_CHECK_EQUAL(stateCopy.stepSize,
372  BOOST_CHECK_EQUAL(stateCopy.previousStepSize,
373  state.stepping.previousStepSize);
374  BOOST_CHECK_EQUAL(stateCopy.tolerance, state.stepping.tolerance);
375 
376  // Reset the least amount of parameters
377  stateCopy = state.stepping;
378  stepper.resetState(stateCopy, cp.parameters(), *cp.covariance(),
379  cp.referenceSurface());
380  // Test all components
381  BOOST_CHECK(stateCopy.covTransport);
382  BOOST_CHECK_EQUAL(*stateCopy.covariance, cov);
383  BOOST_CHECK_EQUAL(stepper.position(stateCopy),
384  freeParams.template segment<3>(eFreePos0));
385  BOOST_CHECK_EQUAL(stepper.direction(stateCopy),
386  freeParams.template segment<3>(eFreeDir0).normalized());
387  BOOST_CHECK_EQUAL(stepper.momentum(stateCopy),
388  std::abs(1. / freeParams[eFreeQOverP]));
389  BOOST_CHECK_EQUAL(stepper.charge(stateCopy), stepper.charge(state.stepping));
390  BOOST_CHECK_EQUAL(stepper.time(stateCopy), freeParams[eFreeTime]);
391  BOOST_CHECK_EQUAL(stateCopy.navDir, forward);
392  BOOST_CHECK_EQUAL(stateCopy.pathAccumulated, 0.);
393  BOOST_CHECK_EQUAL(stateCopy.stepSize, std::numeric_limits<double>::max());
394  BOOST_CHECK_EQUAL(stateCopy.previousStepSize,
395  state.stepping.previousStepSize);
396  BOOST_CHECK_EQUAL(stateCopy.tolerance, state.stepping.tolerance);
397 
398  // Reset using different surface shapes
399  // 1) Disc surface
400  // Setting some parameters
401  pos << 1.5, -2.5, 0.;
402  mom << 4.5, -5.5, 6.5;
403  time = 7.5;
404  charge = 1.;
405  cov = 8.5 * Covariance::Identity();
406  Transform3D trafo = Transform3D::Identity();
407  auto disc = Surface::makeShared<DiscSurface>(trafo);
408  BoundTrackParameters boundDisc(disc, geoCtx, pos4, unitDir, absMom, charge);
409 
410  // Reset the state and test
411  Stepper::State stateDisc = state.stepping;
412  stepper.resetState(stateDisc, boundDisc.parameters(), *boundDisc.covariance(),
413  boundDisc.referenceSurface());
414 
415  CHECK_NE_COLLECTIONS(stateDisc.pVector, stateCopy.pVector);
416  CHECK_NE_COLLECTIONS(stateDisc.pVector, state.stepping.pVector);
417 
418  // 2) Perigee surface
419  // Setting some parameters
420  pos << 1.5, -2.5, 3.5;
421  mom << 4.5, -5.5, 6.5;
422  time = 7.5;
423  charge = 1.;
424  cov = 8.5 * Covariance::Identity();
425  auto perigee = Surface::makeShared<PerigeeSurface>(trafo);
426  BoundTrackParameters boundPerigee(perigee, geoCtx, pos4, unitDir, absMom,
427  charge);
428 
429  // Reset the state and test
430  Stepper::State statePerigee = state.stepping;
431  stepper.resetState(statePerigee, boundPerigee.parameters(),
432  *boundPerigee.covariance(),
433  boundPerigee.referenceSurface());
434  CHECK_NE_COLLECTIONS(statePerigee.pVector, stateCopy.pVector);
435  CHECK_NE_COLLECTIONS(statePerigee.pVector, state.stepping.pVector);
436  CHECK_NE_COLLECTIONS(statePerigee.pVector, stateDisc.pVector);
437 
438  // 3) Straw surface
439  // Setting some parameters
440  pos << 1.5, -2.5, 3.5;
441  mom << 4.5, -5.5, 6.5;
442  time = 7.5;
443  charge = 1.;
444  cov = 8.5 * Covariance::Identity();
445  auto straw = Surface::makeShared<StrawSurface>(trafo);
446  BoundTrackParameters boundStraw(straw, geoCtx, pos4, unitDir, absMom, charge);
447 
448  // Reset the state and test
449  Stepper::State stateStraw = state.stepping;
450  stepper.resetState(stateStraw, boundStraw.parameters(),
451  *boundStraw.covariance(), boundStraw.referenceSurface());
452  CHECK_NE_COLLECTIONS(stateStraw.pVector, stateCopy.pVector);
453  CHECK_NE_COLLECTIONS(stateStraw.pVector, state.stepping.pVector);
454  CHECK_NE_COLLECTIONS(stateStraw.pVector, stateDisc.pVector);
455  BOOST_CHECK_EQUAL_COLLECTIONS(
456  stateStraw.pVector.begin(), stateStraw.pVector.end(),
457  statePerigee.pVector.begin(), statePerigee.pVector.end());
458 }
459 
462  Stepper::State state(
463  geoCtx, magCtx,
466 
467  // TODO figure out why this fails and what it should be
468  // BOOST_CHECK_EQUAL(stepper.overstepLimit(state), tolerance);
469 
470  stepper.setStepSize(state, 5_cm);
471  BOOST_CHECK_EQUAL(state.previousStepSize, navDir * stepSize);
472  BOOST_CHECK_EQUAL(state.stepSize, 5_cm);
473 
474  stepper.releaseStepSize(state);
475  BOOST_CHECK_EQUAL(state.stepSize, navDir * stepSize);
476 }
477 
478 // test step size modification with target surfaces
479 BOOST_AUTO_TEST_CASE(StepSizeSurface) {
481  Stepper::State state(
482  geoCtx, magCtx,
485 
486  auto distance = 10_mm;
487  auto target = Surface::makeShared<PlaneSurface>(
488  pos + navDir * distance * unitDir, unitDir);
489 
490  stepper.updateSurfaceStatus(state, *target, BoundaryCheck(false));
491  BOOST_CHECK_EQUAL(state.stepSize.value(ConstrainedStep::actor),
492  navDir * distance);
493 
494  // test the step size modification in the context of a surface
495  stepper.updateStepSize(
496  state,
497  target->intersect(state.geoContext, stepper.position(state),
498  state.navDir * stepper.direction(state), false),
499  false);
500  BOOST_CHECK_EQUAL(state.stepSize, distance);
501 
502  // start with a different step size
503  state.stepSize = navDir * stepSize;
504  stepper.updateStepSize(
505  state,
506  target->intersect(state.geoContext, stepper.position(state),
507  state.navDir * stepper.direction(state), false),
508  true);
509  BOOST_CHECK_EQUAL(state.stepSize, distance);
510 }
511 
512 BOOST_AUTO_TEST_SUITE_END()
513 
514 } // namespace Test
515 } // namespace Acts