Analysis Software
Documentation for sPHENIX simulation 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 
39 
40 #include <algorithm>
41 #include <array>
42 #include <functional>
43 #include <iterator>
44 #include <limits>
45 #include <memory>
46 #include <optional>
47 #include <tuple>
48 #include <type_traits>
49 #include <utility>
50 
51 namespace Acts {
52 namespace Test {
53 
54 using namespace Acts::UnitLiterals;
59 
63  : stepping(std::move(stepperState)) {}
64 
68  struct {
69  double tolerance = 10_um;
71  } options;
72 };
73 
74 struct MockNavigator {};
75 
76 static constexpr MockNavigator navigator;
77 
78 // epsilon for floating point comparisons
79 static constexpr auto eps = 1024 * std::numeric_limits<double>::epsilon();
80 
81 // propagation settings
82 static constexpr auto stepSize = 10_mm;
83 static constexpr auto tolerance = 10_um;
85 static auto magneticField =
86  std::make_shared<ConstantBField>(Vector3(0.1_T, -0.2_T, 2_T));
87 
88 // initial parameter state
89 static const Vector4 pos4(1_mm, -1_mm, 2_mm, 2_ns);
90 static const Vector3 pos = pos4.segment<3>(ePos0);
91 static const auto time = pos4[eTime];
92 static const Vector3 unitDir = Vector3(-2, 2, 1).normalized();
93 static constexpr auto absMom = 1_GeV;
94 static constexpr auto charge = -1_e;
96 static const Covariance cov = Covariance::Identity();
97 
98 // context objects
99 static const GeometryContext geoCtx;
101 
102 BOOST_AUTO_TEST_SUITE(AtlasStepper)
103 
104 // test state construction from parameters w/o covariance
105 BOOST_AUTO_TEST_CASE(ConstructState) {
107  geoCtx, magneticField->makeCache(magCtx),
111 
112  BOOST_CHECK(!state.covTransport);
113  BOOST_CHECK_EQUAL(state.covariance, nullptr);
114  BOOST_CHECK_EQUAL(state.pVector[0], pos.x());
115  BOOST_CHECK_EQUAL(state.pVector[1], pos.y());
116  BOOST_CHECK_EQUAL(state.pVector[2], pos.z());
117  BOOST_CHECK_EQUAL(state.pVector[3], time);
118  CHECK_CLOSE_ABS(state.pVector[4], unitDir.x(), eps);
119  CHECK_CLOSE_ABS(state.pVector[5], unitDir.y(), eps);
120  CHECK_CLOSE_ABS(state.pVector[6], unitDir.z(), eps);
121  BOOST_CHECK_EQUAL(state.pVector[7], charge / absMom);
122  BOOST_CHECK_EQUAL(state.pathAccumulated, 0.);
123  BOOST_CHECK_EQUAL(state.stepSize.value(), stepSize);
124  BOOST_CHECK_EQUAL(state.previousStepSize, 0.);
125  BOOST_CHECK_EQUAL(state.tolerance, tolerance);
126 }
127 
128 // test state construction from parameters w/ covariance
129 BOOST_AUTO_TEST_CASE(ConstructStateWithCovariance) {
131  geoCtx, magneticField->makeCache(magCtx),
135 
136  BOOST_CHECK(state.covTransport);
137  BOOST_CHECK_EQUAL(*state.covariance, cov);
138  BOOST_CHECK_EQUAL(state.pVector[0], pos.x());
139  BOOST_CHECK_EQUAL(state.pVector[1], pos.y());
140  BOOST_CHECK_EQUAL(state.pVector[2], pos.z());
141  BOOST_CHECK_EQUAL(state.pVector[3], time);
142  CHECK_CLOSE_ABS(state.pVector[4], unitDir.x(), eps);
143  CHECK_CLOSE_ABS(state.pVector[5], unitDir.y(), eps);
144  CHECK_CLOSE_ABS(state.pVector[6], unitDir.z(), eps);
145  BOOST_CHECK_EQUAL(state.pVector[7], charge / absMom);
146  BOOST_CHECK_EQUAL(state.pathAccumulated, 0.);
147  BOOST_CHECK_EQUAL(state.stepSize.value(), stepSize);
148  BOOST_CHECK_EQUAL(state.previousStepSize, 0.);
149  BOOST_CHECK_EQUAL(state.tolerance, tolerance);
150 }
151 
152 // test stepper getters for particle state
156  geoCtx, magneticField->makeCache(magCtx),
160 
161  CHECK_CLOSE_ABS(stepper.position(state), pos, eps);
162  CHECK_CLOSE_ABS(stepper.time(state), time, eps);
165  BOOST_CHECK_EQUAL(stepper.charge(state), charge);
166 }
167 
168 // test stepper update methods with bound state as input
169 BOOST_AUTO_TEST_CASE(UpdateFromBound) {
172  geoCtx, magneticField->makeCache(magCtx),
176 
177  auto newPos4 = (pos4 + Vector4(1_mm, 2_mm, 3_mm, 20_ns)).eval();
178  auto newPos = newPos4.segment<3>(ePos0);
179  auto newTime = newPos4[eTime];
180  auto newUnitDir = (unitDir + Vector3(1, -1, -1)).normalized();
181  auto newAbsMom = 0.9 * absMom;
182 
183  // example surface and bound parameters at the updated position
184  auto plane = Surface::makeShared<PlaneSurface>(newPos, newUnitDir);
185  auto params =
186  BoundTrackParameters::create(plane, geoCtx, newPos4, newUnitDir,
188  .value();
189  FreeVector freeParams;
190  freeParams[eFreePos0] = newPos4[ePos0];
191  freeParams[eFreePos1] = newPos4[ePos1];
192  freeParams[eFreePos2] = newPos4[ePos2];
193  freeParams[eFreeTime] = newPos4[eTime];
194  freeParams[eFreeDir0] = newUnitDir[eMom0];
195  freeParams[eFreeDir1] = newUnitDir[eMom1];
196  freeParams[eFreeDir2] = newUnitDir[eMom2];
197  freeParams[eFreeQOverP] = charge / newAbsMom;
198 
199  // WARNING for some reason there seems to be an additional flag that makes
200  // the update method not do anything when it is set. Why?
201  state.state_ready = false;
202  BOOST_CHECK(params.covariance().has_value());
203  stepper.update(state, freeParams, params.parameters(), *params.covariance(),
204  *plane);
205  CHECK_CLOSE_ABS(stepper.position(state), newPos, eps);
206  CHECK_CLOSE_ABS(stepper.time(state), newTime, eps);
207  CHECK_CLOSE_ABS(stepper.direction(state), newUnitDir, eps);
208  CHECK_CLOSE_ABS(stepper.absoluteMomentum(state), newAbsMom, eps);
209  BOOST_CHECK_EQUAL(stepper.charge(state), charge);
210 }
211 
212 // test stepper update methods with individual components as input
213 BOOST_AUTO_TEST_CASE(UpdateFromComponents) {
216  geoCtx, magneticField->makeCache(magCtx),
220 
221  auto newPos = (pos + Vector3(1_mm, 2_mm, 3_mm)).eval();
222  auto newTime = time + 20_ns;
223  auto newUnitDir = (unitDir + Vector3(1, -1, -1)).normalized();
224  auto newAbsMom = 0.9 * absMom;
225 
226  stepper.update(state, newPos, newUnitDir, charge / newAbsMom, newTime);
227  CHECK_CLOSE_ABS(stepper.position(state), newPos, eps);
228  CHECK_CLOSE_ABS(stepper.time(state), newTime, eps);
229  CHECK_CLOSE_ABS(stepper.direction(state), newUnitDir, eps);
230  CHECK_CLOSE_ABS(stepper.absoluteMomentum(state), newAbsMom, eps);
231  BOOST_CHECK_EQUAL(stepper.charge(state), charge);
232 }
233 
234 // test building a bound state object from the stepper state
235 BOOST_AUTO_TEST_CASE(BuildBound) {
238  geoCtx, magneticField->makeCache(magCtx),
242  // example surface at the current state position
243  auto plane = Surface::makeShared<PlaneSurface>(pos, unitDir);
244 
245  auto&& [pars, jac, pathLength] = stepper.boundState(state, *plane).value();
246  // check parameters
247  CHECK_CLOSE_ABS(pars.position(geoCtx), pos, eps);
248  CHECK_CLOSE_ABS(pars.time(), time, eps);
249  CHECK_CLOSE_ABS(pars.momentum(), absMom * unitDir, eps);
250  BOOST_CHECK_EQUAL(pars.charge(), charge);
251  BOOST_CHECK(pars.covariance().has_value());
252  BOOST_CHECK_NE(*pars.covariance(), cov);
253  // check Jacobian. should be identity since there was no propagation yet
254  CHECK_CLOSE_ABS(jac, Jacobian(Jacobian::Identity()), eps);
255  // check propagation length
257 }
258 
259 // test building a curvilinear state object from the stepper state
260 BOOST_AUTO_TEST_CASE(BuildCurvilinear) {
263  geoCtx, magneticField->makeCache(magCtx),
267 
268  auto&& [pars, jac, pathLength] = stepper.curvilinearState(state);
269  // check parameters
270  CHECK_CLOSE_ABS(pars.position(geoCtx), pos, eps);
271  CHECK_CLOSE_ABS(pars.time(), time, eps);
272  CHECK_CLOSE_ABS(pars.momentum(), absMom * unitDir, eps);
273  BOOST_CHECK_EQUAL(pars.charge(), charge);
274  BOOST_CHECK(pars.covariance().has_value());
275  BOOST_CHECK_NE(*pars.covariance(), cov);
276  // check Jacobian. should be identity since there was no propagation yet
277  CHECK_CLOSE_ABS(jac, Jacobian(Jacobian::Identity()), eps);
278  // check propagation length
280 }
281 
282 // test step method without covariance transport
289  stepSize, tolerance));
290  state.stepping.covTransport = false;
291 
292  // ensure step does not result in an error
293  auto res = stepper.step(state, navigator);
294  BOOST_CHECK(res.ok());
295 
296  // extract the actual step size
297  auto h = res.value();
298  BOOST_CHECK_EQUAL(state.stepping.stepSize.value(), stepSize);
299  BOOST_CHECK_EQUAL(state.stepping.stepSize.value(), h * navDir);
300 
301  // check that the position has moved
302  auto deltaPos = (stepper.position(state.stepping) - pos).eval();
303  BOOST_CHECK_LT(0, deltaPos.norm());
304  // check that time has changed
305  auto deltaTime = stepper.time(state.stepping) - time;
306  BOOST_CHECK_LT(0, std::abs(deltaTime));
307  // check that the direction was rotated
308  auto projDir = stepper.direction(state.stepping).dot(unitDir);
309  BOOST_CHECK_LT(projDir, 1);
310 
311  // momentum and charge should not change
313  BOOST_CHECK_EQUAL(stepper.charge(state.stepping), charge);
314 }
315 
316 // test step method with covariance transport
317 BOOST_AUTO_TEST_CASE(StepWithCovariance) {
323  stepSize, tolerance));
324  state.stepping.covTransport = true;
325 
326  // ensure step does not result in an error
327  auto res = stepper.step(state, navigator);
328  BOOST_CHECK(res.ok());
329 
330  // extract the actual step size
331  auto h = res.value();
332  BOOST_CHECK_EQUAL(state.stepping.stepSize.value(), stepSize);
333  BOOST_CHECK_EQUAL(state.stepping.stepSize.value(), h * navDir);
334 
335  // check that the position has moved
336  auto deltaPos = (stepper.position(state.stepping) - pos).eval();
337  BOOST_CHECK_LT(0, deltaPos.norm());
338  // check that time has changed
339  auto deltaTime = stepper.time(state.stepping) - time;
340  BOOST_CHECK_LT(0, std::abs(deltaTime));
341  // check that the direction was rotated
342  auto projDir = stepper.direction(state.stepping).dot(unitDir);
343  BOOST_CHECK_LT(projDir, 1);
344 
345  // momentum and charge should not change
347  BOOST_CHECK_EQUAL(stepper.charge(state.stepping), charge);
348 
349  stepper.transportCovarianceToCurvilinear(state.stepping);
350  BOOST_CHECK_NE(state.stepping.cov, cov);
351 }
352 
353 // test state reset method
360  stepSize, tolerance));
361  state.stepping.covTransport = true;
362 
363  // ensure step does not result in an error
364  stepper.step(state, navigator);
365 
366  // Construct the parameters
367  Vector3 newPos(1.5, -2.5, 3.5);
368  auto newAbsMom = 4.2 * absMom;
369  double newTime = 7.5;
370  double newCharge = 1.;
371  BoundSquareMatrix newCov = 8.5 * Covariance::Identity();
372  CurvilinearTrackParameters cp(makeVector4(newPos, newTime), unitDir,
373  newCharge / newAbsMom, newCov,
376  cp.referenceSurface(), geoCtx, cp.parameters());
378  double stepSize = -256.;
379 
380  auto copyState = [&](auto& field, const auto& other) {
381  using field_t = std::decay_t<decltype(field)>;
382  std::decay_t<decltype(other)> copy(geoCtx, field.makeCache(magCtx), cp,
384 
385  copy.state_ready = other.state_ready;
386  copy.useJacobian = other.useJacobian;
387  copy.step = other.step;
388  copy.maxPathLength = other.maxPathLength;
389  copy.mcondition = other.mcondition;
390  copy.needgradient = other.needgradient;
391  copy.newfield = other.newfield;
392  copy.field = other.field;
393  copy.pVector = other.pVector;
394  std::copy(std::begin(other.parameters), std::end(other.parameters),
395  std::begin(copy.parameters));
396  copy.covariance = other.covariance;
397  copy.covTransport = other.covTransport;
398  std::copy(std::begin(other.jacobian), std::end(other.jacobian),
399  std::begin(copy.jacobian));
400  copy.pathAccumulated = other.pathAccumulated;
401  copy.stepSize = other.stepSize;
402  copy.previousStepSize = other.previousStepSize;
403  copy.tolerance = other.tolerance;
404 
405  copy.fieldCache =
406  MagneticFieldProvider::Cache::make<typename field_t::Cache>(
407  other.fieldCache.template get<typename field_t::Cache>());
408 
409  copy.geoContext = other.geoContext;
410  copy.debug = other.debug;
411  copy.debugString = other.debugString;
412  copy.debugPfxWidth = other.debugPfxWidth;
413  copy.debugMsgWidth = other.debugMsgWidth;
414 
415  return copy;
416  };
417 
418  // Reset all possible parameters
419  Stepper::State stateCopy(copyState(*magneticField, state.stepping));
420  BOOST_CHECK(cp.covariance().has_value());
421  stepper.resetState(stateCopy, cp.parameters(), *cp.covariance(),
422  cp.referenceSurface(), stepSize);
423  // Test all components
424  BOOST_CHECK(stateCopy.covTransport);
425  BOOST_CHECK_EQUAL(*stateCopy.covariance, newCov);
426  BOOST_CHECK_EQUAL(stepper.position(stateCopy),
427  freeParams.template segment<3>(eFreePos0));
428  BOOST_CHECK_EQUAL(stepper.direction(stateCopy),
429  freeParams.template segment<3>(eFreeDir0).normalized());
430  BOOST_CHECK_EQUAL(stepper.absoluteMomentum(stateCopy),
431  std::abs(1. / freeParams[eFreeQOverP]));
432  BOOST_CHECK_EQUAL(stepper.charge(stateCopy), stepper.charge(state.stepping));
433  BOOST_CHECK_EQUAL(stepper.time(stateCopy), freeParams[eFreeTime]);
434  BOOST_CHECK_EQUAL(stateCopy.pathAccumulated, 0.);
435  BOOST_CHECK_EQUAL(stateCopy.stepSize.value(), navDir * stepSize);
436  BOOST_CHECK_EQUAL(stateCopy.previousStepSize,
437  state.stepping.previousStepSize);
438  BOOST_CHECK_EQUAL(stateCopy.tolerance, state.stepping.tolerance);
439 
440  // Reset all possible parameters except the step size
441  stateCopy = copyState(*magneticField, state.stepping);
442  stepper.resetState(stateCopy, cp.parameters(), *cp.covariance(),
443  cp.referenceSurface());
444  // Test all components
445  BOOST_CHECK(stateCopy.covTransport);
446  BOOST_CHECK_EQUAL(*stateCopy.covariance, newCov);
447  BOOST_CHECK_EQUAL(stepper.position(stateCopy),
448  freeParams.template segment<3>(eFreePos0));
449  BOOST_CHECK_EQUAL(stepper.direction(stateCopy),
450  freeParams.template segment<3>(eFreeDir0).normalized());
451  BOOST_CHECK_EQUAL(stepper.absoluteMomentum(stateCopy),
452  std::abs(1. / freeParams[eFreeQOverP]));
453  BOOST_CHECK_EQUAL(stepper.charge(stateCopy), stepper.charge(state.stepping));
454  BOOST_CHECK_EQUAL(stepper.time(stateCopy), freeParams[eFreeTime]);
455  BOOST_CHECK_EQUAL(stateCopy.pathAccumulated, 0.);
456  BOOST_CHECK_EQUAL(stateCopy.stepSize.value(),
457  std::numeric_limits<double>::max());
458  BOOST_CHECK_EQUAL(stateCopy.previousStepSize,
459  state.stepping.previousStepSize);
460  BOOST_CHECK_EQUAL(stateCopy.tolerance, state.stepping.tolerance);
461 
462  // Reset the least amount of parameters
463  stateCopy = copyState(*magneticField, state.stepping);
464  stepper.resetState(stateCopy, cp.parameters(), *cp.covariance(),
465  cp.referenceSurface());
466  // Test all components
467  BOOST_CHECK(stateCopy.covTransport);
468  BOOST_CHECK_EQUAL(*stateCopy.covariance, newCov);
469  BOOST_CHECK_EQUAL(stepper.position(stateCopy),
470  freeParams.template segment<3>(eFreePos0));
471  BOOST_CHECK_EQUAL(stepper.direction(stateCopy),
472  freeParams.template segment<3>(eFreeDir0).normalized());
473  BOOST_CHECK_EQUAL(stepper.absoluteMomentum(stateCopy),
474  std::abs(1. / freeParams[eFreeQOverP]));
475  BOOST_CHECK_EQUAL(stepper.charge(stateCopy), stepper.charge(state.stepping));
476  BOOST_CHECK_EQUAL(stepper.time(stateCopy), freeParams[eFreeTime]);
477  BOOST_CHECK_EQUAL(stateCopy.pathAccumulated, 0.);
478  BOOST_CHECK_EQUAL(stateCopy.stepSize.value(),
479  std::numeric_limits<double>::max());
480  BOOST_CHECK_EQUAL(stateCopy.previousStepSize,
481  state.stepping.previousStepSize);
482  BOOST_CHECK_EQUAL(stateCopy.tolerance, state.stepping.tolerance);
483 
484  // Reset using different surface shapes
485  // 1) Disc surface
486  // Setting some parameters
487  newPos << 0.5, -1.5, 0.;
488  newAbsMom *= 1.23;
489  newTime = 8.4;
490  newCharge = -1.;
491  newCov = 10.9 * Covariance::Identity();
492  Transform3 trafo = Transform3::Identity();
493  auto disc = Surface::makeShared<DiscSurface>(trafo);
494  auto boundDisc = BoundTrackParameters::create(
495  disc, geoCtx, makeVector4(newPos, newTime), unitDir,
496  newCharge / newAbsMom, newCov, particleHypothesis)
497  .value();
498 
499  // Reset the state and test
500  Stepper::State stateDisc = copyState(*magneticField, state.stepping);
501  BOOST_CHECK(boundDisc.covariance().has_value());
502  stepper.resetState(stateDisc, boundDisc.parameters(), *boundDisc.covariance(),
503  boundDisc.referenceSurface());
504 
505  CHECK_NE_COLLECTIONS(stateDisc.pVector, stateCopy.pVector);
506  CHECK_NE_COLLECTIONS(stateDisc.pVector, state.stepping.pVector);
507 
508  // 2) Perigee surface
509  // Setting some parameters
510  newPos << -2.06155, -2.06155, 3.5;
511  newAbsMom *= 0.45;
512  newTime = 2.3;
513  newCharge = 1.;
514  newCov = 8.7 * Covariance::Identity();
515  auto perigee = Surface::makeShared<PerigeeSurface>(trafo);
516  auto boundPerigee =
518  perigee, geoCtx, makeVector4(newPos, newTime), unitDir,
519  newCharge / newAbsMom, newCov, particleHypothesis)
520  .value();
521 
522  // Reset the state and test
523  Stepper::State statePerigee = copyState(*magneticField, state.stepping);
524  BOOST_CHECK(boundPerigee.covariance().has_value());
525  stepper.resetState(statePerigee, boundPerigee.parameters(),
526  *boundPerigee.covariance(),
527  boundPerigee.referenceSurface());
528  CHECK_NE_COLLECTIONS(statePerigee.pVector, stateCopy.pVector);
529  CHECK_NE_COLLECTIONS(statePerigee.pVector, state.stepping.pVector);
530  CHECK_NE_COLLECTIONS(statePerigee.pVector, stateDisc.pVector);
531 
532  // 3) Straw surface
533  // Use the same parameters as for previous Perigee surface
534  auto straw = Surface::makeShared<StrawSurface>(trafo);
535  auto boundStraw = BoundTrackParameters::create(
536  straw, geoCtx, makeVector4(newPos, newTime), unitDir,
537  newCharge / newAbsMom, newCov, particleHypothesis)
538  .value();
539 
540  // Reset the state and test
541  Stepper::State stateStraw = copyState(*magneticField, state.stepping);
542  BOOST_CHECK(boundStraw.covariance().has_value());
543  stepper.resetState(stateStraw, boundStraw.parameters(),
544  *boundStraw.covariance(), boundStraw.referenceSurface());
545  CHECK_NE_COLLECTIONS(stateStraw.pVector, stateCopy.pVector);
546  CHECK_NE_COLLECTIONS(stateStraw.pVector, state.stepping.pVector);
547  CHECK_NE_COLLECTIONS(stateStraw.pVector, stateDisc.pVector);
548  BOOST_CHECK_EQUAL_COLLECTIONS(
549  stateStraw.pVector.begin(), stateStraw.pVector.end(),
550  statePerigee.pVector.begin(), statePerigee.pVector.end());
551 }
552 
556  geoCtx, magneticField->makeCache(magCtx),
560 
561  // TODO figure out why this fails and what it should be
562  // BOOST_CHECK_EQUAL(stepper.overstepLimit(state), tolerance);
563 
564  stepper.setStepSize(state, -5_cm);
565  BOOST_CHECK_EQUAL(state.previousStepSize, stepSize);
566  BOOST_CHECK_EQUAL(state.stepSize.value(), -5_cm);
567 
568  stepper.releaseStepSize(state);
569  BOOST_CHECK_EQUAL(state.stepSize.value(), stepSize);
570 }
571 
572 // test step size modification with target surfaces
573 BOOST_AUTO_TEST_CASE(StepSizeSurface) {
576  geoCtx, magneticField->makeCache(magCtx),
580 
581  auto distance = 10_mm;
582  auto target = Surface::makeShared<PlaneSurface>(
583  pos + navDir * distance * unitDir, unitDir);
584 
585  stepper.updateSurfaceStatus(state, *target, navDir, BoundaryCheck(false));
586  BOOST_CHECK_EQUAL(state.stepSize.value(ConstrainedStep::actor), distance);
587 
588  // test the step size modification in the context of a surface
589  stepper.updateStepSize(
590  state,
591  target
592  ->intersect(state.geoContext, stepper.position(state),
593  navDir * stepper.direction(state), false)
594  .closest(),
595  navDir, false);
596  BOOST_CHECK_EQUAL(state.stepSize.value(), distance);
597 
598  // start with a different step size
599  state.stepSize.setUser(navDir * stepSize);
600  stepper.updateStepSize(
601  state,
602  target
603  ->intersect(state.geoContext, stepper.position(state),
604  navDir * stepper.direction(state), false)
605  .closest(),
606  navDir, true);
607  BOOST_CHECK_EQUAL(state.stepSize.value(), navDir * stepSize);
608 }
609 
610 BOOST_AUTO_TEST_SUITE_END()
611 
612 } // namespace Test
613 } // namespace Acts