Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PropagatorTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PropagatorTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-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 #include <boost/test/data/test_case.hpp>
10 #include <boost/test/tools/output_test_stream.hpp>
11 #include <boost/test/unit_test.hpp>
12 
36 
37 #include <algorithm>
38 #include <array>
39 #include <cmath>
40 #include <cstddef>
41 #include <limits>
42 #include <memory>
43 #include <optional>
44 #include <random>
45 #include <tuple>
46 #include <utility>
47 
48 namespace Acts {
49 class Logger;
50 } // namespace Acts
51 
52 namespace bdata = boost::unit_test::data;
53 namespace tt = boost::test_tools;
54 using namespace Acts::UnitLiterals;
57 
58 namespace Acts {
59 namespace Test {
60 
61 // Create a test context
64 
66 
70  struct this_result {
71  double distance = std::numeric_limits<double>::max();
72  };
73 
75 
76  PerpendicularMeasure() = default;
77 
78  template <typename propagator_state_t, typename stepper_t,
79  typename navigator_t>
80  void operator()(propagator_state_t& state, const stepper_t& stepper,
81  const navigator_t& /*navigator*/, result_type& result) const {
82  result.distance = perp(stepper.position(state.stepping));
83  }
84 };
85 
87 template <typename Surface>
89  // the surface to be intersected
90  const Surface* surface = nullptr;
91  // the tolerance for intersection
92  double tolerance = 1.e-5;
93 
95  struct this_result {
96  size_t surfaces_passed = 0;
97  double surface_passed_r = std::numeric_limits<double>::max();
98  };
99 
101 
102  SurfaceObserver() = default;
103 
104  template <typename propagator_state_t, typename stepper_t,
105  typename navigator_t>
106  void operator()(propagator_state_t& state, const stepper_t& stepper,
107  const navigator_t& /*navigator*/, result_type& result,
108  const Logger& /*logger*/) const {
109  if (surface && !result.surfaces_passed) {
110  // calculate the distance to the surface
111  const double distance =
112  surface
113  ->intersect(state.geoContext, stepper.position(state.stepping),
114  stepper.direction(state.stepping), true)
115  .closest()
116  .pathLength();
117  // Adjust the step size so that we cannot cross the target surface
118  state.stepping.stepSize.update(distance * state.options.direction,
120  // return true if you fall below tolerance
121  if (std::abs(distance) <= tolerance) {
122  ++result.surfaces_passed;
123  result.surface_passed_r = perp(stepper.position(state.stepping));
124  // release the step size, will be re-adjusted
125  state.stepping.stepSize.release(ConstrainedStep::actor);
126  }
127  }
128  }
129 };
130 
131 // Global definitions
132 // The path limit abort
134 
135 using BFieldType = ConstantBField;
138 
139 const double Bz = 2_T;
140 auto bField = std::make_shared<BFieldType>(Vector3{0, 0, Bz});
143 
144 auto mCylinder = std::make_shared<CylinderBounds>(10_mm, 1000_mm);
145 auto mSurface =
146  Surface::makeShared<CylinderSurface>(Transform3::Identity(), mCylinder);
147 auto cCylinder = std::make_shared<CylinderBounds>(150_mm, 1000_mm);
148 auto cSurface =
149  Surface::makeShared<CylinderSurface>(Transform3::Identity(), cCylinder);
150 
151 const int ntests = 5;
152 
153 // This tests the Options
154 BOOST_AUTO_TEST_CASE(PropagatorOptions_) {
155  using null_optionsType = PropagatorOptions<>;
156  null_optionsType null_options(tgContext, mfContext);
157  // todo write null options test
158 
159  using ActionListType = ActionList<PerpendicularMeasure>;
160  using AbortConditionsType = AbortList<>;
161 
163 
164  optionsType options(tgContext, mfContext);
165 }
166 
168  cylinder_passage_observer_,
169  bdata::random((bdata::seed = 0,
170  bdata::distribution =
171  std::uniform_real_distribution<>(0.4_GeV, 10_GeV))) ^
172  bdata::random((bdata::seed = 1,
173  bdata::distribution =
174  std::uniform_real_distribution<>(-M_PI, M_PI))) ^
175  bdata::random((bdata::seed = 2,
176  bdata::distribution =
177  std::uniform_real_distribution<>(1.0, M_PI - 1.0))) ^
178  bdata::random(
179  (bdata::seed = 3,
180  bdata::distribution = std::uniform_int_distribution<>(0, 1))) ^
181  bdata::random(
182  (bdata::seed = 4,
183  bdata::distribution = std::uniform_int_distribution<>(0, 100))) ^
184  bdata::xrange(ntests),
185  pT, phi, theta, charge, time, index) {
186  double dcharge = -1 + 2 * charge;
187  (void)index;
188 
189  using CylinderObserver = SurfaceObserver<CylinderSurface>;
190  using ActionListType = ActionList<CylinderObserver>;
191  using AbortConditionsType = AbortList<>;
192 
193  // setup propagation options
195  mfContext);
196 
197  options.pathLimit = 20_m;
198  options.maxStepSize = 1_cm;
199 
200  // set the surface to be passed by
201  options.actionList.get<CylinderObserver>().surface = mSurface.get();
202 
203  using so_result = typename CylinderObserver::result_type;
204 
205  // define start parameters
206  double x = 0;
207  double y = 0;
208  double z = 0;
209  double px = pT * cos(phi);
210  double py = pT * sin(phi);
211  double pz = pT / tan(theta);
212  double q = dcharge;
213  Vector3 pos(x, y, z);
214  Vector3 mom(px, py, pz);
215  CurvilinearTrackParameters start(makeVector4(pos, time), mom.normalized(),
216  q / mom.norm(), std::nullopt,
218  // propagate to the cylinder surface
219  const auto& result = epropagator.propagate(start, *cSurface, options).value();
220  auto& sor = result.get<so_result>();
221 
222  BOOST_CHECK_EQUAL(sor.surfaces_passed, 1u);
223  CHECK_CLOSE_ABS(sor.surface_passed_r, 10., 1e-5);
224 }
225 
227  curvilinear_additive_,
228  bdata::random((bdata::seed = 0,
229  bdata::distribution =
230  std::uniform_real_distribution<>(0.4_GeV, 10_GeV))) ^
231  bdata::random((bdata::seed = 1,
232  bdata::distribution =
233  std::uniform_real_distribution<>(-M_PI, M_PI))) ^
234  bdata::random((bdata::seed = 2,
235  bdata::distribution =
236  std::uniform_real_distribution<>(1.0, M_PI - 1.0))) ^
237  bdata::random(
238  (bdata::seed = 3,
239  bdata::distribution = std::uniform_int_distribution<>(0, 1))) ^
240  bdata::random(
241  (bdata::seed = 4,
242  bdata::distribution = std::uniform_int_distribution<>(0, 100))) ^
243  bdata::xrange(ntests),
244  pT, phi, theta, charge, time, index) {
245  double dcharge = -1 + 2 * charge;
246  (void)index;
247 
248  // setup propagation options - the tow step options
250  options_2s.pathLimit = 50_cm;
251  options_2s.maxStepSize = 1_cm;
252 
253  // define start parameters
254  double x = 0;
255  double y = 0;
256  double z = 0;
257  double px = pT * cos(phi);
258  double py = pT * sin(phi);
259  double pz = pT / tan(theta);
260  double q = dcharge;
261  Vector3 pos(x, y, z);
262  Vector3 mom(px, py, pz);
264  Covariance cov;
265  // take some major correlations (off-diagonals)
266  cov << 10_mm, 0, 0.123, 0, 0.5, 0, 0, 10_mm, 0, 0.162, 0, 0, 0.123, 0, 0.1, 0,
267  0, 0, 0, 0.162, 0, 0.1, 0, 0, 0.5, 0, 0, 0, 1. / (10_GeV), 0, 0, 0, 0, 0,
268  0, 0;
269  CurvilinearTrackParameters start(makeVector4(pos, time), mom.normalized(),
270  q / mom.norm(), cov,
272  // propagate to a path length of 100 with two steps of 50
273  const auto& mid_parameters =
274  epropagator.propagate(start, options_2s).value().endParameters;
275  const auto& end_parameters_2s =
276  epropagator.propagate(*mid_parameters, options_2s).value().endParameters;
277 
278  // setup propagation options - the one step options
280  options_1s.pathLimit = 100_cm;
281  options_1s.maxStepSize = 1_cm;
282  // propagate to a path length of 100 in one step
283  const auto& end_parameters_1s =
284  epropagator.propagate(start, options_1s).value().endParameters;
285 
286  // test that the propagation is additive
287  CHECK_CLOSE_REL(end_parameters_1s->position(tgContext),
288  end_parameters_2s->position(tgContext), 0.001);
289 
290  BOOST_CHECK(end_parameters_1s->covariance().has_value());
291  const auto& cov_1s = *(end_parameters_1s->covariance());
292  BOOST_CHECK(end_parameters_2s->covariance().has_value());
293  const auto& cov_2s = *(end_parameters_2s->covariance());
294 
295  // CHECK_CLOSE_COVARIANCE(cov_1s, cov_2s, 0.001);
296  for (unsigned int i = 0; i < cov_1s.rows(); i++) {
297  for (unsigned int j = 0; j < cov_1s.cols(); j++) {
298  CHECK_CLOSE_OR_SMALL(cov_1s(i, j), cov_2s(i, j), 0.001, 1e-6);
299  }
300  }
301 }
302 
304  cylinder_additive_,
305  bdata::random((bdata::seed = 0,
306  bdata::distribution =
307  std::uniform_real_distribution<>(0.4_GeV, 10_GeV))) ^
308  bdata::random((bdata::seed = 1,
309  bdata::distribution =
310  std::uniform_real_distribution<>(-M_PI, M_PI))) ^
311  bdata::random((bdata::seed = 2,
312  bdata::distribution =
313  std::uniform_real_distribution<>(1.0, M_PI - 1.0))) ^
314  bdata::random(
315  (bdata::seed = 3,
316  bdata::distribution = std::uniform_int_distribution<>(0, 1))) ^
317  bdata::random(
318  (bdata::seed = 4,
319  bdata::distribution = std::uniform_int_distribution<>(0, 100))) ^
320  bdata::xrange(ntests),
321  pT, phi, theta, charge, time, index) {
322  double dcharge = -1 + 2 * charge;
323  (void)index;
324 
325  // setup propagation options - 2 setp options
327  options_2s.pathLimit = 10_m;
328  options_2s.maxStepSize = 1_cm;
329 
330  // define start parameters
331  double x = 0;
332  double y = 0;
333  double z = 0;
334  double px = pT * cos(phi);
335  double py = pT * sin(phi);
336  double pz = pT / tan(theta);
337  double q = dcharge;
338  Vector3 pos(x, y, z);
339  Vector3 mom(px, py, pz);
341  Covariance cov;
342  // take some major correlations (off-diagonals)
343  cov << 10_mm, 0, 0.123, 0, 0.5, 0, 0, 10_mm, 0, 0.162, 0, 0, 0.123, 0, 0.1, 0,
344  0, 0, 0, 0.162, 0, 0.1, 0, 0, 0.5, 0, 0, 0, 1. / (10_GeV), 0, 0, 0, 0, 0,
345  0, 0;
346  CurvilinearTrackParameters start(makeVector4(pos, time), mom.normalized(),
347  q / mom.norm(), cov,
349  // propagate to a final surface with one stop in between
350  const auto& mid_parameters =
351  epropagator.propagate(start, *mSurface, options_2s).value().endParameters;
352 
353  const auto& end_parameters_2s =
354  epropagator.propagate(*mid_parameters, *cSurface, options_2s)
355  .value()
356  .endParameters;
357 
358  // setup propagation options - one step options
360  options_1s.pathLimit = 10_m;
361  options_1s.maxStepSize = 1_cm;
362  // propagate to a final surface in one stop
363  const auto& end_parameters_1s =
364  epropagator.propagate(start, *cSurface, options_1s).value().endParameters;
365 
366  // test that the propagation is additive
367  CHECK_CLOSE_REL(end_parameters_1s->position(tgContext),
368  end_parameters_2s->position(tgContext), 0.001);
369 
370  BOOST_CHECK(end_parameters_1s->covariance().has_value());
371  const auto& cov_1s = (*(end_parameters_1s->covariance()));
372  BOOST_CHECK(end_parameters_2s->covariance().has_value());
373  const auto& cov_2s = (*(end_parameters_2s->covariance()));
374 
375  // CHECK_CLOSE_COVARIANCE(cov_1s, cov_2s, 0.001);
376  for (unsigned int i = 0; i < cov_1s.rows(); i++) {
377  for (unsigned int j = 0; j < cov_1s.cols(); j++) {
378  CHECK_CLOSE_OR_SMALL(cov_1s(i, j), cov_2s(i, j), 0.001, 1e-6);
379  }
380  }
381 }
382 
383 } // namespace Test
384 } // namespace Acts