Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SurfaceLocalToGlobalRoundtripTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SurfaceLocalToGlobalRoundtripTests.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 // This file contains systematic tests to verify the local->global->local
10 // transformation roundtrip for all available surfaces with a large range of
11 // possible parameters.
12 
13 #include <boost/test/data/test_case.hpp>
14 #include <boost/test/unit_test.hpp>
15 
29 
30 #include <cmath>
31 #include <limits>
32 #include <memory>
33 #include <ostream>
34 #include <type_traits>
35 #include <utility>
36 #include <vector>
37 
38 namespace {
39 
40 namespace bdata = boost::unit_test::data;
41 using namespace Acts;
42 
43 constexpr auto eps = 8 * std::numeric_limits<double>::epsilon();
45 
46 void runTest(const Surface& surface, double l0, double l1, double phi,
47  double theta) {
48  const Vector3 dir = makeDirectionFromPhiTheta(phi, theta);
49 
50  // convert local-to-global
51  Vector3 sentinel = Vector3::Random();
52  Vector3 pos = surface.localToGlobal(geoCtx, Vector2(l0, l1), dir);
53  BOOST_CHECK_MESSAGE(pos != sentinel, "Position was not changed");
54  BOOST_CHECK_MESSAGE(
55  std::isfinite(pos[0]),
56  "Position " << pos.transpose() << " contains non-finite entries");
57  BOOST_CHECK_MESSAGE(
58  std::isfinite(pos[1]),
59  "Position " << pos.transpose() << " contains non-finite entries");
60  BOOST_CHECK_MESSAGE(
61  std::isfinite(pos[2]),
62  "Position " << pos.transpose() << " contains non-finite entries");
63  BOOST_CHECK_MESSAGE(
64  surface.isOnSurface(geoCtx, pos, dir),
65  "Position " << pos.transpose() << " is not on the surface");
66 
67  // convert global-to-local
68  auto lpResult = surface.globalToLocal(geoCtx, pos, dir);
69  BOOST_CHECK(lpResult.ok());
70  CHECK_CLOSE_OR_SMALL(lpResult.value()[ePos0], l0, eps, eps);
71  CHECK_CLOSE_OR_SMALL(lpResult.value()[ePos1], l1, eps, eps);
72 }
73 
74 // test datasets
75 
76 // local positions
77 const auto posAngle = bdata::xrange(-M_PI, M_PI, 0.25);
78 const auto posPositiveNonzero = bdata::xrange(0.25, 1.0, 0.25);
79 const auto posPositive = bdata::make(0.0) + posPositiveNonzero;
80 const auto posSymmetric = bdata::xrange(-1.0, 1.0, 0.25);
81 // direction angles
82 const auto phis = bdata::xrange(-M_PI, M_PI, M_PI_4);
83 const auto thetasNoForwardBackward = bdata::xrange(M_PI_4, M_PI, M_PI_4);
84 const auto thetas = bdata::make({0.0, M_PI}) + thetasNoForwardBackward;
85 
86 // different surfaces
87 // parameters must be chosen such that all possible local positions (as defined
88 // in the datasets above) represent valid points on the surface.
89 const auto cones = bdata::make({
90  Surface::makeShared<ConeSurface>(Transform3::Identity(),
91  0.5 /* opening angle */),
92 });
93 const auto cylinders = bdata::make({
94  Surface::makeShared<CylinderSurface>(Transform3::Identity(),
95  10.0 /* radius */, 100 /* half z */),
96 });
97 const auto discs = bdata::make({
98  Surface::makeShared<DiscSurface>(Transform3::Identity(), 0 /* radius min */,
99  100 /* radius max */),
100 });
101 const auto perigees = bdata::make({
102  Surface::makeShared<PerigeeSurface>(Vector3(0, 0, -1.5)),
103 });
104 const auto planes = bdata::make({
105  Surface::makeShared<PlaneSurface>(Vector3(1, 2, 3), Vector3::UnitX()),
106  Surface::makeShared<PlaneSurface>(Vector3(-2, -3, -4), Vector3::UnitY()),
107  Surface::makeShared<PlaneSurface>(Vector3(3, -4, 5), Vector3::UnitZ()),
108 });
109 const auto straws = bdata::make({
110  Surface::makeShared<StrawSurface>(Transform3::Identity(), 2.0 /* radius */,
111  200.0 /* half z */),
112 });
113 
114 } // namespace
115 
116 BOOST_AUTO_TEST_SUITE(SurfaceLocalToGlobalRoundtrip)
117 
119  cones* posAngle* posPositiveNonzero* phis* thetas, surface,
120  lphi, lz, phi, theta) {
121  // TODO extend lz to zero after fixing the transform implementation
122  // local parameter r*phi has limits that depend on the z position
123  const auto r = lz * surface->bounds().tanAlpha();
124  // local coordinates are singular at z = 0 -> normalize local phi
125  runTest(*surface, (0 < lz) ? (r * lphi) : 0.0, lz, phi, theta);
126 }
127 
129  cylinders* posSymmetric* posSymmetric* phis* thetas,
130  surface, lrphi, lz, phi, theta) {
131  runTest(*surface, lrphi, lz, phi, theta);
132 }
133 
134 BOOST_DATA_TEST_CASE(DiscSurface, discs* posPositive* posAngle* phis* thetas,
135  surface, lr, lphi, phi, theta) {
136  // local coordinates are singular at r = 0 -> normalize local phi
137  runTest(*surface, lr, (0 < lr) ? lphi : 0.0, phi, theta);
138 }
139 
142  perigees* posSymmetric* posSymmetric* phis* thetasNoForwardBackward,
143  surface, d0, z0, phi, theta) {
144  // TODO extend theta to forward/back extreme cases fixing the transform
145  runTest(*surface, d0, z0, phi, theta);
146 }
147 
149  planes* posSymmetric* posSymmetric* phis* thetas, surface,
150  l0, l1, phi, theta) {
151  runTest(*surface, l0, l1, phi, theta);
152 }
153 
155  StrawSurface,
156  straws* posSymmetric* posSymmetric* phis* thetasNoForwardBackward, surface,
157  lr, lz, phi, theta) {
158  // TODO extend theta to forward/back extreme cases fixing the transform
159  runTest(*surface, lr, lz, phi, theta);
160 }
161 
162 BOOST_AUTO_TEST_SUITE_END()