EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
StepperTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file StepperTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2018-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/unit_test.hpp>
10 
36 
37 #include <fstream>
38 
39 namespace tt = boost::test_tools;
40 using namespace Acts::UnitLiterals;
42 
43 namespace Acts {
44 namespace Test {
45 
47 
48 static constexpr auto eps = 2 * std::numeric_limits<double>::epsilon();
49 
50 // Create a test context
53 
55 template <typename stepper_state_t>
56 struct PropState {
58  PropState(stepper_state_t sState) : stepping(sState) {}
60  stepper_state_t stepping;
62  struct {
63  double mass = 42.;
64  double tolerance = 1e-4;
65  double stepSizeCutOff = 0.;
66  unsigned int maxRungeKuttaStepTrials = 10000;
67  } options;
68 };
69 
73 struct EndOfWorld {
75  double maxX = 1_m;
76 
78  EndOfWorld() = default;
79 
87  template <typename propagator_state_t, typename stepper_t>
88  bool operator()(propagator_state_t& state, const stepper_t& stepper) const {
89  const double tolerance = state.options.targetTolerance;
90  if (maxX - std::abs(stepper.position(state.stepping).x()) <= tolerance ||
91  std::abs(stepper.position(state.stepping).y()) >= 0.5_m ||
92  std::abs(stepper.position(state.stepping).z()) >= 0.5_m)
93  return true;
94  return false;
95  }
96 };
97 
105  struct this_result {
106  // Position of the propagator after each step
107  std::vector<Vector3D> position;
108  // Momentum of the propagator after each step
109  std::vector<Vector3D> momentum;
110  };
111 
113 
122  template <typename propagator_state_t, typename stepper_t>
123  void operator()(propagator_state_t& state, const stepper_t& stepper,
124  result_type& result) const {
125  result.position.push_back(stepper.position(state.stepping));
126  result.momentum.push_back(stepper.momentum(state.stepping) *
127  stepper.direction(state.stepping));
128  }
129 };
130 
132 BOOST_AUTO_TEST_CASE(eigen_stepper_state_test) {
133  // Set up some variables
135  double stepSize = 123.;
136  double tolerance = 234.;
137  ConstantBField bField(Vector3D(1., 2.5, 33.33));
138 
139  Vector3D pos(1., 2., 3.);
140  Vector3D dir(4., 5., 6.);
141  double time = 7.;
142  double absMom = 8.;
143  double charge = -1.;
144 
145  // Test charged parameters without covariance matrix
146  CurvilinearTrackParameters cp(makeVector4(pos, time), dir, charge / absMom);
148  stepSize, tolerance);
149 
150  // Test the result & compare with the input/test for reasonable members
151  BOOST_CHECK_EQUAL(esState.jacToGlobal, BoundToFreeMatrix::Zero());
152  BOOST_CHECK_EQUAL(esState.jacTransport, FreeMatrix::Identity());
153  BOOST_CHECK_EQUAL(esState.derivative, FreeVector::Zero());
154  BOOST_CHECK(!esState.covTransport);
155  BOOST_CHECK_EQUAL(esState.cov, Covariance::Zero());
156  CHECK_CLOSE_OR_SMALL(esState.pos, pos, eps, eps);
157  CHECK_CLOSE_OR_SMALL(esState.dir, dir.normalized(), eps, eps);
158  CHECK_CLOSE_REL(esState.p, absMom, eps);
159  BOOST_CHECK_EQUAL(esState.q, charge);
160  CHECK_CLOSE_OR_SMALL(esState.t, time, eps, eps);
161  BOOST_CHECK_EQUAL(esState.navDir, ndir);
162  BOOST_CHECK_EQUAL(esState.pathAccumulated, 0.);
163  BOOST_CHECK_EQUAL(esState.stepSize, ndir * stepSize);
164  BOOST_CHECK_EQUAL(esState.previousStepSize, 0.);
165  BOOST_CHECK_EQUAL(esState.tolerance, tolerance);
166 
167  // Test without charge and covariance matrix
169  1 / absMom);
171  stepSize, tolerance);
172  BOOST_CHECK_EQUAL(esState.q, 0.);
173 
174  // Test with covariance matrix
175  Covariance cov = 8. * Covariance::Identity();
176  ncp = NeutralCurvilinearTrackParameters(makeVector4(pos, time), dir,
177  1 / absMom, cov);
179  stepSize, tolerance);
180  BOOST_CHECK_NE(esState.jacToGlobal, BoundToFreeMatrix::Zero());
181  BOOST_CHECK(esState.covTransport);
182  BOOST_CHECK_EQUAL(esState.cov, cov);
183 }
184 
187 BOOST_AUTO_TEST_CASE(eigen_stepper_test) {
188  // Set up some variables for the state
190  double stepSize = 123.;
191  double tolerance = 234.;
192  ConstantBField bField(Vector3D(1., 2.5, 33.33));
193 
194  // Construct the parameters
195  Vector3D pos(1., 2., 3.);
196  Vector3D dir = Vector3D(4., 5., 6.).normalized();
197  double time = 7.;
198  double absMom = 8.;
199  double charge = -1.;
200  Covariance cov = 8. * Covariance::Identity();
201  CurvilinearTrackParameters cp(makeVector4(pos, time), dir, charge / absMom,
202  cov);
203 
204  // Build the state and the stepper
206  stepSize, tolerance);
207  EigenStepper<ConstantBField> es(bField);
208 
209  // Test the getters
210  BOOST_CHECK_EQUAL(es.position(esState), esState.pos);
211  BOOST_CHECK_EQUAL(es.direction(esState), esState.dir);
212  BOOST_CHECK_EQUAL(es.momentum(esState), esState.p);
213  BOOST_CHECK_EQUAL(es.charge(esState), esState.q);
214  BOOST_CHECK_EQUAL(es.time(esState), esState.t);
215  //~ BOOST_CHECK_EQUAL(es.overstepLimit(esState), tolerance);
216  BOOST_CHECK_EQUAL(es.getField(esState, pos), bField.getField(pos));
217 
218  // Step size modifies
219  const std::string originalStepSize = esState.stepSize.toString();
220 
221  es.setStepSize(esState, 1337.);
222  BOOST_CHECK_EQUAL(esState.previousStepSize, ndir * stepSize);
223  BOOST_CHECK_EQUAL(esState.stepSize, 1337.);
224 
225  es.releaseStepSize(esState);
226  BOOST_CHECK_EQUAL(esState.stepSize, -123.);
227  BOOST_CHECK_EQUAL(es.outputStepSize(esState), originalStepSize);
228 
229  // Test the curvilinear state construction
230  auto curvState = es.curvilinearState(esState);
231  auto curvPars = std::get<0>(curvState);
232  CHECK_CLOSE_ABS(curvPars.position(tgContext), cp.position(tgContext), 1e-6);
233  CHECK_CLOSE_ABS(curvPars.momentum(), cp.momentum(), 1e-6);
234  CHECK_CLOSE_ABS(curvPars.charge(), cp.charge(), 1e-6);
235  CHECK_CLOSE_ABS(curvPars.time(), cp.time(), 1e-6);
236  BOOST_CHECK(curvPars.covariance().has_value());
237  BOOST_CHECK_NE(*curvPars.covariance(), cov);
238  CHECK_CLOSE_COVARIANCE(std::get<1>(curvState),
239  BoundMatrix(BoundMatrix::Identity()), 1e-6);
240  CHECK_CLOSE_ABS(std::get<2>(curvState), 0., 1e-6);
241 
242  // Test the update method
243  Vector3D newPos(2., 4., 8.);
244  Vector3D newMom(3., 9., 27.);
245  double newTime(321.);
246  es.update(esState, newPos, newMom.normalized(), newMom.norm(), newTime);
247  BOOST_CHECK_EQUAL(esState.pos, newPos);
248  BOOST_CHECK_EQUAL(esState.dir, newMom.normalized());
249  BOOST_CHECK_EQUAL(esState.p, newMom.norm());
250  BOOST_CHECK_EQUAL(esState.q, charge);
251  BOOST_CHECK_EQUAL(esState.t, newTime);
252 
253  // The covariance transport
254  esState.cov = cov;
255  es.covarianceTransport(esState);
256  BOOST_CHECK_NE(esState.cov, cov);
257  BOOST_CHECK_NE(esState.jacToGlobal, BoundToFreeMatrix::Zero());
258  BOOST_CHECK_EQUAL(esState.jacTransport, FreeMatrix::Identity());
259  BOOST_CHECK_EQUAL(esState.derivative, FreeVector::Zero());
260 
261  // Perform a step without and with covariance transport
262  esState.cov = cov;
263  PropState ps(esState);
264 
265  ps.stepping.covTransport = false;
266  double h = es.step(ps).value();
267  BOOST_CHECK_EQUAL(ps.stepping.stepSize, h);
268  CHECK_CLOSE_COVARIANCE(ps.stepping.cov, cov, 1e-6);
269  BOOST_CHECK_NE(ps.stepping.pos.norm(), newPos.norm());
270  BOOST_CHECK_NE(ps.stepping.dir, newMom.normalized());
271  BOOST_CHECK_EQUAL(ps.stepping.q, charge);
272  BOOST_CHECK_LT(ps.stepping.t, newTime);
273  BOOST_CHECK_EQUAL(ps.stepping.derivative, FreeVector::Zero());
274  BOOST_CHECK_EQUAL(ps.stepping.jacTransport, FreeMatrix::Identity());
275 
276  ps.stepping.covTransport = true;
277  double h2 = es.step(ps).value();
278  BOOST_CHECK_EQUAL(h2, h);
279  CHECK_CLOSE_COVARIANCE(ps.stepping.cov, cov, 1e-6);
280  BOOST_CHECK_NE(ps.stepping.pos.norm(), newPos.norm());
281  BOOST_CHECK_NE(ps.stepping.dir, newMom.normalized());
282  BOOST_CHECK_EQUAL(ps.stepping.q, charge);
283  BOOST_CHECK_LT(ps.stepping.t, newTime);
284  BOOST_CHECK_NE(ps.stepping.derivative, FreeVector::Zero());
285  BOOST_CHECK_NE(ps.stepping.jacTransport, FreeMatrix::Identity());
286 
288  // Construct the parameters
289  Vector3D pos2(1.5, -2.5, 3.5);
290  Vector3D dir2 = Vector3D(4.5, -5.5, 6.5).normalized();
291  double time2 = 7.5;
292  double absMom2 = 8.5;
293  double charge2 = 1.;
294  BoundSymMatrix cov2 = 8.5 * Covariance::Identity();
295  CurvilinearTrackParameters cp2(makeVector4(pos2, time2), dir2, absMom2,
296  charge2, cov2);
298  cp2.referenceSurface(), tgContext, cp2.parameters());
299  ndir = forward;
300  double stepSize2 = -2. * stepSize;
301 
302  // Reset all possible parameters
304  es.resetState(esStateCopy, cp2.parameters(), *cp2.covariance(),
305  cp2.referenceSurface(), ndir, stepSize2);
306  // Test all components
307  BOOST_CHECK_NE(esStateCopy.jacToGlobal, BoundToFreeMatrix::Zero());
308  BOOST_CHECK_NE(esStateCopy.jacToGlobal, ps.stepping.jacToGlobal);
309  BOOST_CHECK_EQUAL(esStateCopy.jacTransport, FreeMatrix::Identity());
310  BOOST_CHECK_EQUAL(esStateCopy.derivative, FreeVector::Zero());
311  BOOST_CHECK(esStateCopy.covTransport);
312  BOOST_CHECK_EQUAL(esStateCopy.cov, cov2);
313  BOOST_CHECK_EQUAL(esStateCopy.pos, freeParams.template segment<3>(eFreePos0));
314  BOOST_CHECK_EQUAL(esStateCopy.dir,
315  freeParams.template segment<3>(eFreeDir0).normalized());
316  BOOST_CHECK_EQUAL(esStateCopy.p, std::abs(1. / freeParams[eFreeQOverP]));
317  BOOST_CHECK_EQUAL(esStateCopy.q, ps.stepping.q);
318  BOOST_CHECK_EQUAL(esStateCopy.t, freeParams[eFreeTime]);
319  BOOST_CHECK_EQUAL(esStateCopy.navDir, ndir);
320  BOOST_CHECK_EQUAL(esStateCopy.pathAccumulated, 0.);
321  BOOST_CHECK_EQUAL(esStateCopy.stepSize, ndir * stepSize2);
322  BOOST_CHECK_EQUAL(esStateCopy.previousStepSize, ps.stepping.previousStepSize);
323  BOOST_CHECK_EQUAL(esStateCopy.tolerance, ps.stepping.tolerance);
324 
325  // Reset all possible parameters except the step size
326  esStateCopy = ps.stepping;
327  es.resetState(esStateCopy, cp2.parameters(), *cp2.covariance(),
328  cp2.referenceSurface(), ndir);
329  // Test all components
330  BOOST_CHECK_NE(esStateCopy.jacToGlobal, BoundToFreeMatrix::Zero());
331  BOOST_CHECK_NE(esStateCopy.jacToGlobal, ps.stepping.jacToGlobal);
332  BOOST_CHECK_EQUAL(esStateCopy.jacTransport, FreeMatrix::Identity());
333  BOOST_CHECK_EQUAL(esStateCopy.derivative, FreeVector::Zero());
334  BOOST_CHECK(esStateCopy.covTransport);
335  BOOST_CHECK_EQUAL(esStateCopy.cov, cov2);
336  BOOST_CHECK_EQUAL(esStateCopy.pos, freeParams.template segment<3>(eFreePos0));
337  BOOST_CHECK_EQUAL(esStateCopy.dir,
338  freeParams.template segment<3>(eFreeDir0).normalized());
339  BOOST_CHECK_EQUAL(esStateCopy.p, std::abs(1. / freeParams[eFreeQOverP]));
340  BOOST_CHECK_EQUAL(esStateCopy.q, ps.stepping.q);
341  BOOST_CHECK_EQUAL(esStateCopy.t, freeParams[eFreeTime]);
342  BOOST_CHECK_EQUAL(esStateCopy.navDir, ndir);
343  BOOST_CHECK_EQUAL(esStateCopy.pathAccumulated, 0.);
344  BOOST_CHECK_EQUAL(esStateCopy.stepSize,
346  BOOST_CHECK_EQUAL(esStateCopy.previousStepSize, ps.stepping.previousStepSize);
347  BOOST_CHECK_EQUAL(esStateCopy.tolerance, ps.stepping.tolerance);
348 
349  // Reset the least amount of parameters
350  esStateCopy = ps.stepping;
351  es.resetState(esStateCopy, cp2.parameters(), *cp2.covariance(),
352  cp2.referenceSurface());
353  // Test all components
354  BOOST_CHECK_NE(esStateCopy.jacToGlobal, BoundToFreeMatrix::Zero());
355  BOOST_CHECK_NE(esStateCopy.jacToGlobal, ps.stepping.jacToGlobal);
356  BOOST_CHECK_EQUAL(esStateCopy.jacTransport, FreeMatrix::Identity());
357  BOOST_CHECK_EQUAL(esStateCopy.derivative, FreeVector::Zero());
358  BOOST_CHECK(esStateCopy.covTransport);
359  BOOST_CHECK_EQUAL(esStateCopy.cov, cov2);
360  BOOST_CHECK_EQUAL(esStateCopy.pos, freeParams.template segment<3>(eFreePos0));
361  BOOST_CHECK_EQUAL(esStateCopy.dir,
362  freeParams.template segment<3>(eFreeDir0).normalized());
363  BOOST_CHECK_EQUAL(esStateCopy.p, std::abs(1. / freeParams[eFreeQOverP]));
364  BOOST_CHECK_EQUAL(esStateCopy.q, ps.stepping.q);
365  BOOST_CHECK_EQUAL(esStateCopy.t, freeParams[eFreeTime]);
366  BOOST_CHECK_EQUAL(esStateCopy.navDir, forward);
367  BOOST_CHECK_EQUAL(esStateCopy.pathAccumulated, 0.);
368  BOOST_CHECK_EQUAL(esStateCopy.stepSize, std::numeric_limits<double>::max());
369  BOOST_CHECK_EQUAL(esStateCopy.previousStepSize, ps.stepping.previousStepSize);
370  BOOST_CHECK_EQUAL(esStateCopy.tolerance, ps.stepping.tolerance);
371 
373  auto plane = Surface::makeShared<PlaneSurface>(pos, dir.normalized());
374  BoundTrackParameters bp(plane, tgContext, makeVector4(pos, time), dir,
375  charge / absMom, cov);
377  stepSize, tolerance);
378 
379  // Test the intersection in the context of a surface
380  auto targetSurface =
381  Surface::makeShared<PlaneSurface>(pos + ndir * 2. * dir, dir);
382  es.updateSurfaceStatus(esState, *targetSurface, BoundaryCheck(false));
384  1e-6);
385 
386  // Test the step size modification in the context of a surface
387  es.updateStepSize(
388  esState,
389  targetSurface->intersect(esState.geoContext, esState.pos,
390  esState.navDir * esState.dir, false),
391  false);
392  CHECK_CLOSE_ABS(esState.stepSize, 2., 1e-6);
393  esState.stepSize = ndir * stepSize;
394  es.updateStepSize(
395  esState,
396  targetSurface->intersect(esState.geoContext, esState.pos,
397  esState.navDir * esState.dir, false),
398  true);
399  CHECK_CLOSE_ABS(esState.stepSize, 2., 1e-6);
400 
401  // Test the bound state construction
402  auto boundState = es.boundState(esState, *plane);
403  auto boundPars = std::get<0>(boundState);
404  CHECK_CLOSE_ABS(boundPars.position(tgContext), bp.position(tgContext), 1e-6);
405  CHECK_CLOSE_ABS(boundPars.momentum(), bp.momentum(), 1e-6);
406  CHECK_CLOSE_ABS(boundPars.charge(), bp.charge(), 1e-6);
407  CHECK_CLOSE_ABS(boundPars.time(), bp.time(), 1e-6);
408  BOOST_CHECK(boundPars.covariance().has_value());
409  BOOST_CHECK_NE(*boundPars.covariance(), cov);
410  CHECK_CLOSE_COVARIANCE(std::get<1>(boundState),
411  BoundMatrix(BoundMatrix::Identity()), 1e-6);
412  CHECK_CLOSE_ABS(std::get<2>(boundState), 0., 1e-6);
413 
414  // Transport the covariance in the context of a surface
415  es.covarianceTransport(esState, *plane);
416  BOOST_CHECK_NE(esState.cov, cov);
417  BOOST_CHECK_NE(esState.jacToGlobal, BoundToFreeMatrix::Zero());
418  BOOST_CHECK_EQUAL(esState.jacTransport, FreeMatrix::Identity());
419  BOOST_CHECK_EQUAL(esState.derivative, FreeVector::Zero());
420 
421  // Update in context of a surface
423  bp.referenceSurface(), tgContext, bp.parameters());
424  freeParams.segment<3>(eFreePos0) *= 2;
425  freeParams[eFreeTime] *= 2;
426  freeParams.segment<3>(eFreeDir0) *= 2;
427  freeParams[eFreeQOverP] *= -0.5;
428 
429  es.update(esState, freeParams, 2 * (*bp.covariance()));
430  CHECK_CLOSE_OR_SMALL(esState.pos, 2. * pos, eps, eps);
431  CHECK_CLOSE_OR_SMALL(esState.dir, dir, eps, eps);
432  CHECK_CLOSE_REL(esState.p, 2 * absMom, eps);
433  // update does not change the particle hypothesis
434  BOOST_CHECK_EQUAL(esState.q, 1. * charge);
435  CHECK_CLOSE_OR_SMALL(esState.t, 2. * time, eps, eps);
436  CHECK_CLOSE_COVARIANCE(esState.cov, Covariance(2. * cov), 1e-6);
437 
438  // Test a case where no step size adjustment is required
439  ps.options.tolerance = 2. * 4.4258e+09;
440  double h0 = esState.stepSize;
441  es.step(ps);
442  CHECK_CLOSE_ABS(h0, esState.stepSize, 1e-6);
443 
444  // Produce some errors
445  NullBField nBfield;
446  EigenStepper<NullBField> nes(nBfield);
448  stepSize, tolerance);
449  PropState nps(nesState);
450  // Test that we can reach the minimum step size
451  nps.options.tolerance = 1e-21;
452  nps.options.stepSizeCutOff = 1e20;
453  auto res = nes.step(nps);
454  BOOST_CHECK(!res.ok());
455  BOOST_CHECK_EQUAL(res.error(), EigenStepperError::StepSizeStalled);
456 
457  // Test that the number of trials exceeds
458  nps.options.stepSizeCutOff = 0.;
460  res = nes.step(nps);
461  BOOST_CHECK(!res.ok());
462  BOOST_CHECK_EQUAL(res.error(), EigenStepperError::StepSizeAdjustmentFailed);
463 }
464 
473 
474 // Test case a). The DenseEnvironmentExtension should state that it is not
475 // valid in this case.
476 BOOST_AUTO_TEST_CASE(step_extension_vacuum_test) {
479  vConf.position = {0.5_m, 0., 0.};
480  vConf.length = {1_m, 1_m, 1_m};
482  conf.volumeCfg.push_back(vConf);
483  conf.position = {0.5_m, 0., 0.};
484  conf.length = {1_m, 1_m, 1_m};
485 
486  // Build detector
487  cvb.setConfig(conf);
489  tgbCfg.trackingVolumeBuilders.push_back(
490  [=](const auto& context, const auto& inner, const auto& vb) {
491  return cvb.trackingVolume(context, inner, vb);
492  });
493  TrackingGeometryBuilder tgb(tgbCfg);
494  std::shared_ptr<const TrackingGeometry> vacuum =
496 
497  // Build navigator
498  Navigator naviVac(vacuum);
499  naviVac.resolvePassive = true;
500  naviVac.resolveMaterial = true;
501  naviVac.resolveSensitive = true;
502 
503  // Set initial parameters for the particle track
504  Covariance cov = Covariance::Identity();
505  const Vector3D startDir = makeDirectionUnitFromPhiTheta(0_degree, 90_degree);
506  const Vector3D startMom = 1_GeV * startDir;
507  const CurvilinearTrackParameters sbtp(Vector4D::Zero(), startDir, 1_GeV, 1_e,
508  cov);
509 
510  // Create action list for surface collection
512  AbortList<EndOfWorld> abortList;
513 
514  // Set options for propagator
517  propOpts(tgContext, mfContext, getDummyLogger());
518  propOpts.actionList = aList;
519  propOpts.abortList = abortList;
520  propOpts.maxSteps = 100;
521  propOpts.maxStepSize = 1.5_m;
522 
523  // Build stepper and propagator
524  ConstantBField bField(Vector3D(0., 0., 0.));
525  EigenStepper<
529  es(bField);
530  Propagator<EigenStepper<ConstantBField,
534  Navigator>
535  prop(es, naviVac);
536 
537  // Launch and collect results
538  const auto& result = prop.propagate(sbtp, propOpts).value();
539  const StepCollector::this_result& stepResult =
540  result.get<typename StepCollector::result_type>();
541 
542  // Check that the propagation happend without interactions
543  for (const auto& pos : stepResult.position) {
544  CHECK_SMALL(pos.y(), 1_um);
545  CHECK_SMALL(pos.z(), 1_um);
546  if (pos == stepResult.position.back())
547  CHECK_CLOSE_ABS(pos.x(), 1_m, 1_um);
548  }
549  for (const auto& mom : stepResult.momentum) {
550  CHECK_CLOSE_ABS(mom, startMom, 1_keV);
551  }
552 
553  // Rebuild and check the choice of extension
554  ActionList<StepCollector> aListDef;
555 
556  // Set options for propagator
558  propOptsDef(tgContext, mfContext, getDummyLogger());
559  propOptsDef.actionList = aListDef;
560  propOptsDef.abortList = abortList;
561  propOptsDef.maxSteps = 100;
562  propOptsDef.maxStepSize = 1.5_m;
563 
565  bField);
566  Propagator<
568  Navigator>
569  propDef(esDef, naviVac);
570 
571  // Launch and collect results
572  const auto& resultDef = propDef.propagate(sbtp, propOptsDef).value();
573  const StepCollector::this_result& stepResultDef =
574  resultDef.get<typename StepCollector::result_type>();
575 
576  // Check that the right extension was chosen
577  // If chosen correctly, the number of elements should be identical
578  BOOST_CHECK_EQUAL(stepResult.position.size(), stepResultDef.position.size());
579  for (unsigned int i = 0; i < stepResult.position.size(); i++) {
580  CHECK_CLOSE_ABS(stepResult.position[i], stepResultDef.position[i], 1_um);
581  }
582  BOOST_CHECK_EQUAL(stepResult.momentum.size(), stepResultDef.momentum.size());
583  for (unsigned int i = 0; i < stepResult.momentum.size(); i++) {
584  CHECK_CLOSE_ABS(stepResult.momentum[i], stepResultDef.momentum[i], 1_keV);
585  }
586 }
587 // Test case b). The DefaultExtension should state that it is invalid here.
588 BOOST_AUTO_TEST_CASE(step_extension_material_test) {
591  vConf.position = {0.5_m, 0., 0.};
592  vConf.length = {1_m, 1_m, 1_m};
593  vConf.volumeMaterial =
594  std::make_shared<HomogeneousVolumeMaterial>(makeBeryllium());
596  conf.volumeCfg.push_back(vConf);
597  conf.position = {0.5_m, 0., 0.};
598  conf.length = {1_m, 1_m, 1_m};
599 
600  // Build detector
601  cvb.setConfig(conf);
603  tgbCfg.trackingVolumeBuilders.push_back(
604  [=](const auto& context, const auto& inner, const auto& vb) {
605  return cvb.trackingVolume(context, inner, vb);
606  });
607  TrackingGeometryBuilder tgb(tgbCfg);
608  std::shared_ptr<const TrackingGeometry> material =
610 
611  // Build navigator
612  Navigator naviMat(material);
613  naviMat.resolvePassive = true;
614  naviMat.resolveMaterial = true;
615  naviMat.resolveSensitive = true;
616 
617  // Set initial parameters for the particle track
618  Covariance cov = Covariance::Identity();
619  const Vector3D startDir = makeDirectionUnitFromPhiTheta(0_degree, 90_degree);
620  const Vector3D startMom = 5_GeV * startDir;
621  const CurvilinearTrackParameters sbtp(Vector4D::Zero(), startDir, 5_GeV, 1_e,
622  cov);
623 
624  // Create action list for surface collection
626  AbortList<EndOfWorld> abortList;
627 
628  // Set options for propagator
631  propOpts(tgContext, mfContext, getDummyLogger());
632  propOpts.actionList = aList;
633  propOpts.abortList = abortList;
634  propOpts.maxSteps = 10000;
635  propOpts.maxStepSize = 1.5_m;
636 
637  // Build stepper and propagator
638  ConstantBField bField(Vector3D(0., 0., 0.));
639  EigenStepper<
643  es(bField);
644  Propagator<EigenStepper<ConstantBField,
648  Navigator>
649  prop(es, naviMat);
650 
651  // Launch and collect results
652  const auto& result = prop.propagate(sbtp, propOpts).value();
653  const StepCollector::this_result& stepResult =
654  result.get<typename StepCollector::result_type>();
655 
656  // Check that there occured interaction
657  for (const auto& pos : stepResult.position) {
658  CHECK_SMALL(pos.y(), 1_um);
659  CHECK_SMALL(pos.z(), 1_um);
660  if (pos == stepResult.position.front()) {
661  CHECK_SMALL(pos.x(), 1_um);
662  } else {
663  BOOST_CHECK_GT(std::abs(pos.x()), 1_um);
664  }
665  }
666  for (const auto& mom : stepResult.momentum) {
667  CHECK_SMALL(mom.y(), 1_keV);
668  CHECK_SMALL(mom.z(), 1_keV);
669  if (mom == stepResult.momentum.front()) {
670  CHECK_CLOSE_ABS(mom.x(), 5_GeV, 1_keV);
671  } else {
672  BOOST_CHECK_LT(mom.x(), 5_GeV);
673  }
674  }
675 
676  // Rebuild and check the choice of extension
677  // Set options for propagator
680  propOptsDense(tgContext, mfContext, getDummyLogger());
681  propOptsDense.actionList = aList;
682  propOptsDense.abortList = abortList;
683  propOptsDense.maxSteps = 1000;
684  propOptsDense.maxStepSize = 1.5_m;
685 
686  // Build stepper and propagator
688  esDense(bField);
689  Propagator<EigenStepper<ConstantBField,
691  Navigator>
692  propDense(esDense, naviMat);
693 
694  // Launch and collect results
695  const auto& resultDense = propDense.propagate(sbtp, propOptsDense).value();
696  const StepCollector::this_result& stepResultDense =
697  resultDense.get<typename StepCollector::result_type>();
698 
699  // Check that the right extension was chosen
700  // If chosen correctly, the number of elements should be identical
701  BOOST_CHECK_EQUAL(stepResult.position.size(),
702  stepResultDense.position.size());
703  for (unsigned int i = 0; i < stepResult.position.size(); i++) {
704  CHECK_CLOSE_ABS(stepResult.position[i], stepResultDense.position[i], 1_um);
705  }
706  BOOST_CHECK_EQUAL(stepResult.momentum.size(),
707  stepResultDense.momentum.size());
708  for (unsigned int i = 0; i < stepResult.momentum.size(); i++) {
709  CHECK_CLOSE_ABS(stepResult.momentum[i], stepResultDense.momentum[i], 1_keV);
710  }
711 
713 
714  // Re-launch the configuration with magnetic field
715  bField.setField(0., 1_T, 0.);
716  EigenStepper<
717  ConstantBField,
718  StepperExtensionList<DefaultExtension, DenseEnvironmentExtension>,
719  detail::HighestValidAuctioneer>
720  esB(bField);
721  Propagator<EigenStepper<ConstantBField,
722  StepperExtensionList<DefaultExtension,
723  DenseEnvironmentExtension>,
724  detail::HighestValidAuctioneer>,
725  Navigator>
726  propB(esB, naviMat);
727 
728  const auto& resultB = propB.propagate(sbtp, propOptsDense).value();
729  const StepCollector::this_result& stepResultB =
730  resultB.get<typename StepCollector::result_type>();
731 
732  // Check that there occured interaction
733  for (const auto& pos : stepResultB.position) {
734  if (pos == stepResultB.position.front()) {
735  CHECK_SMALL(pos, 1_um);
736  } else {
737  BOOST_CHECK_GT(std::abs(pos.x()), 1_um);
738  CHECK_SMALL(pos.y(), 1_um);
739  BOOST_CHECK_GT(std::abs(pos.z()), 0.125_um);
740  }
741  }
742  for (const auto& mom : stepResultB.momentum) {
743  if (mom == stepResultB.momentum.front()) {
744  CHECK_CLOSE_ABS(mom, startMom, 1_keV);
745  } else {
746  BOOST_CHECK_NE(mom.x(), 5_GeV);
747  CHECK_SMALL(mom.y(), 1_keV);
748  BOOST_CHECK_NE(mom.z(), 0.);
749  }
750  }
751 }
752 // Test case c). Both should be involved in their part of the detector
753 BOOST_AUTO_TEST_CASE(step_extension_vacmatvac_test) {
756  vConfVac1.position = {0.5_m, 0., 0.};
757  vConfVac1.length = {1_m, 1_m, 1_m};
758  vConfVac1.name = "First vacuum volume";
760  vConfMat.position = {1.5_m, 0., 0.};
761  vConfMat.length = {1_m, 1_m, 1_m};
762  vConfMat.volumeMaterial =
763  std::make_shared<const HomogeneousVolumeMaterial>(makeBeryllium());
764  vConfMat.name = "Material volume";
766  vConfVac2.position = {2.5_m, 0., 0.};
767  vConfVac2.length = {1_m, 1_m, 1_m};
768  vConfVac2.name = "Second vacuum volume";
770  conf.volumeCfg = {vConfVac1, vConfMat, vConfVac2};
771  conf.position = {1.5_m, 0., 0.};
772  conf.length = {3_m, 1_m, 1_m};
773 
774  // Build detector
775  cvb.setConfig(conf);
777  tgbCfg.trackingVolumeBuilders.push_back(
778  [=](const auto& context, const auto& inner, const auto& vb) {
779  return cvb.trackingVolume(context, inner, vb);
780  });
781  TrackingGeometryBuilder tgb(tgbCfg);
782  std::shared_ptr<const TrackingGeometry> det = tgb.trackingGeometry(tgContext);
783 
784  // Build navigator
785  Navigator naviDet(det);
786  naviDet.resolvePassive = true;
787  naviDet.resolveMaterial = true;
788  naviDet.resolveSensitive = true;
789 
790  // Set initial parameters for the particle track
791  CurvilinearTrackParameters sbtp(Vector4D::Zero(), 0_degree, 90_degree, 5_GeV,
792  1_e, Covariance::Identity());
793 
794  // Create action list for surface collection
795  AbortList<EndOfWorld> abortList;
796  abortList.get<EndOfWorld>().maxX = 3_m;
797 
798  // Set options for propagator
801  propOpts(tgContext, mfContext, getDummyLogger());
802  propOpts.abortList = abortList;
803  propOpts.maxSteps = 1000;
804  propOpts.maxStepSize = 1.5_m;
805 
806  // Build stepper and propagator
807  ConstantBField bField(Vector3D(0., 1_T, 0.));
808  EigenStepper<
812  es(bField);
813  Propagator<EigenStepper<ConstantBField,
817  Navigator>
818  prop(es, naviDet);
819 
820  // Launch and collect results
821  const auto& result = prop.propagate(sbtp, propOpts).value();
822  const StepCollector::this_result& stepResult =
823  result.get<typename StepCollector::result_type>();
824 
825  // Manually set the extensions for each step and propagate through each
826  // volume by propagation to the boundaries
827  // Collect boundaries
828  std::vector<Surface const*> surs;
829  std::vector<std::shared_ptr<const BoundarySurfaceT<TrackingVolume>>>
830  boundaries = det->lowestTrackingVolume(tgContext, {0.5_m, 0., 0.})
831  ->boundarySurfaces();
832  for (auto& b : boundaries) {
833  if (b->surfaceRepresentation().center(tgContext).x() == 1_m) {
834  surs.push_back(&(b->surfaceRepresentation()));
835  break;
836  }
837  }
838  boundaries =
839  det->lowestTrackingVolume(tgContext, {1.5_m, 0., 0.})->boundarySurfaces();
840  for (auto& b : boundaries) {
841  if (b->surfaceRepresentation().center(tgContext).x() == 2_m) {
842  surs.push_back(&(b->surfaceRepresentation()));
843  break;
844  }
845  }
846  boundaries =
847  det->lowestTrackingVolume(tgContext, {2.5_m, 0., 0.})->boundarySurfaces();
848  for (auto& b : boundaries) {
849  if (b->surfaceRepresentation().center(tgContext).x() == 3_m) {
850  surs.push_back(&(b->surfaceRepresentation()));
851  break;
852  }
853  }
854 
855  // Build launcher through vacuum
856  // Set options for propagator
857 
859  propOptsDef(tgContext, mfContext, getDummyLogger());
860  abortList.get<EndOfWorld>().maxX = 1_m;
861  propOptsDef.abortList = abortList;
862  propOptsDef.maxSteps = 1000;
863  propOptsDef.maxStepSize = 1.5_m;
864 
865  // Build stepper and propagator
867  bField);
868  Propagator<
870  Navigator>
871  propDef(esDef, naviDet);
872 
873  // Launch and collect results
874  const auto& resultDef =
875  propDef.propagate(sbtp, *(surs[0]), propOptsDef).value();
876  const StepCollector::this_result& stepResultDef =
877  resultDef.get<typename StepCollector::result_type>();
878 
879  // Check the exit situation of the first volume
880  std::pair<Vector3D, Vector3D> endParams, endParamsControl;
881  for (unsigned int i = 0; i < stepResultDef.position.size(); i++) {
882  if (1_m - stepResultDef.position[i].x() < 1e-4) {
883  endParams =
884  std::make_pair(stepResultDef.position[i], stepResultDef.momentum[i]);
885  break;
886  }
887  }
888  for (unsigned int i = 0; i < stepResult.position.size(); i++) {
889  if (1_m - stepResult.position[i].x() < 1e-4) {
890  endParamsControl =
891  std::make_pair(stepResult.position[i], stepResult.momentum[i]);
892  break;
893  }
894  }
895 
896  CHECK_CLOSE_ABS(endParams.first, endParamsControl.first, 1_um);
897  CHECK_CLOSE_ABS(endParams.second, endParamsControl.second, 1_um);
898 
899  CHECK_CLOSE_ABS(endParams.first.x(), endParamsControl.first.x(), 1e-5);
900  CHECK_CLOSE_ABS(endParams.first.y(), endParamsControl.first.y(), 1e-5);
901  CHECK_CLOSE_ABS(endParams.first.z(), endParamsControl.first.z(), 1e-5);
902  CHECK_CLOSE_ABS(endParams.second.x(), endParamsControl.second.x(), 1e-5);
903  CHECK_CLOSE_ABS(endParams.second.y(), endParamsControl.second.y(), 1e-5);
904  CHECK_CLOSE_ABS(endParams.second.z(), endParamsControl.second.z(), 1e-5);
905 
906  // Build launcher through material
907  // Set initial parameters for the particle track by using the result of the
908  // first volume
909  CurvilinearTrackParameters sbtpPiecewise(makeVector4(endParams.first, 0),
910  endParams.second,
911  1 / endParams.second.norm());
912 
913  // Set options for propagator
914  DenseStepperPropagatorOptions<ActionList<StepCollector>,
916  propOptsDense(tgContext, mfContext, getDummyLogger());
917  abortList.get<EndOfWorld>().maxX = 2_m;
918  propOptsDense.abortList = abortList;
919  propOptsDense.maxSteps = 1000;
920  propOptsDense.maxStepSize = 1.5_m;
921 
922  // Build stepper and propagator
924  esDense(bField);
925  Propagator<EigenStepper<ConstantBField,
927  Navigator>
928  propDense(esDense, naviDet);
929 
930  // Launch and collect results
931  const auto& resultDense =
932  propDense.propagate(sbtpPiecewise, *(surs[1]), propOptsDense).value();
933  const StepCollector::this_result& stepResultDense =
934  resultDense.get<typename StepCollector::result_type>();
935 
936  // Check the exit situation of the second volume
937  for (unsigned int i = 0; i < stepResultDense.position.size(); i++) {
938  if (2_m - stepResultDense.position[i].x() < 1e-4) {
939  endParams = std::make_pair(stepResultDense.position[i],
940  stepResultDense.momentum[i]);
941  break;
942  }
943  }
944  for (unsigned int i = 0; i < stepResult.position.size(); i++) {
945  if (2_m - stepResult.position[i].x() < 1e-4) {
946  endParamsControl =
947  std::make_pair(stepResult.position[i], stepResult.momentum[i]);
948  break;
949  }
950  }
951 
952  CHECK_CLOSE_ABS(endParams.first, endParamsControl.first, 1_um);
953  CHECK_CLOSE_ABS(endParams.second, endParamsControl.second, 1_um);
954 }
955 
956 // Test case a). The DenseEnvironmentExtension should state that it is not
957 // valid in this case.
958 BOOST_AUTO_TEST_CASE(step_extension_trackercalomdt_test) {
959  double rotationAngle = M_PI * 0.5;
960  Vector3D xPos(cos(rotationAngle), 0., sin(rotationAngle));
961  Vector3D yPos(0., 1., 0.);
962  Vector3D zPos(-sin(rotationAngle), 0., cos(rotationAngle));
963  MaterialSlab matProp(makeBeryllium(), 0.5_mm);
964 
967  sConf1.position = Vector3D(0.3_m, 0., 0.);
968  sConf1.rotation.col(0) = xPos;
969  sConf1.rotation.col(1) = yPos;
970  sConf1.rotation.col(2) = zPos;
971  sConf1.rBounds =
972  std::make_shared<const RectangleBounds>(RectangleBounds(0.5_m, 0.5_m));
973  sConf1.surMat = std::shared_ptr<const ISurfaceMaterial>(
974  new HomogeneousSurfaceMaterial(matProp));
975  sConf1.thickness = 1._mm;
977  lConf1.surfaceCfg = sConf1;
978 
980  sConf2.position = Vector3D(0.6_m, 0., 0.);
981  sConf2.rotation.col(0) = xPos;
982  sConf2.rotation.col(1) = yPos;
983  sConf2.rotation.col(2) = zPos;
984  sConf2.rBounds =
985  std::make_shared<const RectangleBounds>(RectangleBounds(0.5_m, 0.5_m));
986  sConf2.surMat = std::shared_ptr<const ISurfaceMaterial>(
987  new HomogeneousSurfaceMaterial(matProp));
988  sConf2.thickness = 1._mm;
990  lConf2.surfaceCfg = sConf2;
991 
993  muConf1.position = {2.3_m, 0., 0.};
994  muConf1.length = {20._cm, 20._cm, 20._cm};
995  muConf1.volumeMaterial =
996  std::make_shared<HomogeneousVolumeMaterial>(makeBeryllium());
997  muConf1.name = "MDT1";
999  muConf2.position = {2.7_m, 0., 0.};
1000  muConf2.length = {20._cm, 20._cm, 20._cm};
1001  muConf2.volumeMaterial =
1002  std::make_shared<HomogeneousVolumeMaterial>(makeBeryllium());
1003  muConf2.name = "MDT2";
1004 
1006  vConf1.position = {0.5_m, 0., 0.};
1007  vConf1.length = {1._m, 1._m, 1._m};
1008  vConf1.layerCfg = {lConf1, lConf2};
1009  vConf1.name = "Tracker";
1011  vConf2.position = {1.5_m, 0., 0.};
1012  vConf2.length = {1._m, 1._m, 1._m};
1013  vConf2.volumeMaterial =
1014  std::make_shared<HomogeneousVolumeMaterial>(makeBeryllium());
1015  vConf2.name = "Calorimeter";
1017  vConf3.position = {2.5_m, 0., 0.};
1018  vConf3.length = {1._m, 1._m, 1._m};
1019  vConf3.volumeCfg = {muConf1, muConf2};
1020  vConf3.name = "Muon system";
1022  conf.volumeCfg = {vConf1, vConf2, vConf3};
1023  conf.position = {1.5_m, 0., 0.};
1024  conf.length = {3._m, 1._m, 1._m};
1025 
1026  // Build detector
1027  cvb.setConfig(conf);
1029  tgbCfg.trackingVolumeBuilders.push_back(
1030  [=](const auto& context, const auto& inner, const auto& vb) {
1031  return cvb.trackingVolume(context, inner, vb);
1032  });
1033  TrackingGeometryBuilder tgb(tgbCfg);
1034  std::shared_ptr<const TrackingGeometry> detector =
1036 
1037  // Build navigator
1038  Navigator naviVac(detector);
1039  naviVac.resolvePassive = true;
1040  naviVac.resolveMaterial = true;
1041  naviVac.resolveSensitive = true;
1042 
1043  // Set initial parameters for the particle track
1044  CurvilinearTrackParameters sbtp(Vector4D::Zero(), 0_degree, 90_degree,
1045  1_e / 1_GeV, Covariance::Identity());
1046 
1047  // Set options for propagator
1050  propOpts(tgContext, mfContext, getDummyLogger());
1051  propOpts.abortList.get<EndOfWorld>().maxX = 3._m;
1052  propOpts.maxSteps = 10000;
1053 
1054  // Build stepper and propagator
1055  ConstantBField bField(Vector3D(0., 0., 0.));
1056  EigenStepper<
1060  es(bField);
1061  Propagator<EigenStepper<ConstantBField,
1065  Navigator>
1066  prop(es, naviVac);
1067 
1068  // Launch and collect results
1069  const auto& result = prop.propagate(sbtp, propOpts).value();
1070  const StepCollector::this_result& stepResult =
1071  result.get<typename StepCollector::result_type>();
1072 
1073  // Test that momentum changes only occured at the right detector parts
1074  double lastMomentum = stepResult.momentum[0].x();
1075  for (unsigned int i = 0; i < stepResult.position.size(); i++) {
1076  // Test for changes
1077  if ((stepResult.position[i].x() > 0.3_m &&
1078  stepResult.position[i].x() < 0.6_m) ||
1079  (stepResult.position[i].x() > 0.6_m &&
1080  stepResult.position[i].x() <= 1._m) ||
1081  (stepResult.position[i].x() > 1._m &&
1082  stepResult.position[i].x() <= 2._m) ||
1083  (stepResult.position[i].x() > 2.2_m &&
1084  stepResult.position[i].x() <= 2.4_m) ||
1085  (stepResult.position[i].x() > 2.6_m &&
1086  stepResult.position[i].x() <= 2.8_m)) {
1087  BOOST_CHECK_LE(stepResult.momentum[i].x(), lastMomentum);
1088  lastMomentum = stepResult.momentum[i].x();
1089  } else
1090  // Test the absence of momentum loss
1091  {
1092  if (stepResult.position[i].x() < 0.3_m ||
1093  (stepResult.position[i].x() > 2._m &&
1094  stepResult.position[i].x() <= 2.2_m) ||
1095  (stepResult.position[i].x() > 2.4_m &&
1096  stepResult.position[i].x() <= 2.6_m) ||
1097  (stepResult.position[i].x() > 2.8_m &&
1098  stepResult.position[i].x() <= 3._m)) {
1099  BOOST_CHECK_EQUAL(stepResult.momentum[i].x(), lastMomentum);
1100  }
1101  }
1102  }
1103 }
1104 } // namespace Test
1105 } // namespace Acts