EIC 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 
24 
25 #include <cmath>
26 #include <limits>
27 
28 namespace {
29 
30 namespace bdata = boost::unit_test::data;
31 using namespace Acts;
32 
33 constexpr auto eps = 8 * std::numeric_limits<double>::epsilon();
35 
36 void runTest(const Surface& surface, double l0, double l1, double phi,
37  double theta) {
38  const Vector3D dir = makeDirectionUnitFromPhiTheta(phi, theta);
39 
40  // convert local-to-global
41  Vector3D sentinel = Vector3D::Random();
42  Vector3D pos = surface.localToGlobal(geoCtx, Vector2D(l0, l1), dir);
43  BOOST_CHECK_MESSAGE(pos != sentinel, "Position was not changed");
44  BOOST_CHECK_MESSAGE(
45  std::isfinite(pos[0]),
46  "Position " << pos.transpose() << " contains non-finite entries");
47  BOOST_CHECK_MESSAGE(
48  std::isfinite(pos[1]),
49  "Position " << pos.transpose() << " contains non-finite entries");
50  BOOST_CHECK_MESSAGE(
51  std::isfinite(pos[2]),
52  "Position " << pos.transpose() << " contains non-finite entries");
53  BOOST_CHECK_MESSAGE(
54  surface.isOnSurface(geoCtx, pos, dir),
55  "Position " << pos.transpose() << " is not on the surface");
56 
57  // convert global-to-local
58  auto lpResult = surface.globalToLocal(geoCtx, pos, dir);
59  BOOST_CHECK(lpResult.ok());
60  CHECK_CLOSE_OR_SMALL(lpResult.value()[ePos0], l0, eps, eps);
61  CHECK_CLOSE_OR_SMALL(lpResult.value()[ePos1], l1, eps, eps);
62 }
63 
64 // test datasets
65 
66 // local positions
67 const auto posAngle = bdata::xrange(-M_PI, M_PI, 0.25);
68 const auto posPositiveNonzero = bdata::xrange(0.25, 1.0, 0.25);
69 const auto posPositive = bdata::make(0.0) + posPositiveNonzero;
70 const auto posSymmetric = bdata::xrange(-1.0, 1.0, 0.25);
71 // direction angles
72 const auto phis = bdata::xrange(-M_PI, M_PI, M_PI_4);
73 const auto thetasNoForwardBackward = bdata::xrange(M_PI_4, M_PI, M_PI_4);
74 const auto thetas = bdata::make({0.0, M_PI}) + thetasNoForwardBackward;
75 
76 // different surfaces
77 // parameters must be chosen such that all possible local positions (as defined
78 // in the datasets above) represent valid points on the surface.
79 const auto cones = bdata::make({
80  Surface::makeShared<ConeSurface>(Transform3D::Identity(),
81  0.5 /* opening angle */),
82 });
83 const auto cylinders = bdata::make({
84  Surface::makeShared<CylinderSurface>(Transform3D::Identity(),
85  10.0 /* radius */, 100 /* half z */),
86 });
87 const auto discs = bdata::make({
88  Surface::makeShared<DiscSurface>(Transform3D::Identity(),
89  0 /* radius min */, 100 /* radius max */),
90 });
91 const auto perigees = bdata::make({
92  Surface::makeShared<PerigeeSurface>(Vector3D(0, 0, -1.5)),
93 });
94 const auto planes = bdata::make({
95  Surface::makeShared<PlaneSurface>(Vector3D(1, 2, 3), Vector3D::UnitX()),
96  Surface::makeShared<PlaneSurface>(Vector3D(-2, -3, -4), Vector3D::UnitY()),
97  Surface::makeShared<PlaneSurface>(Vector3D(3, -4, 5), Vector3D::UnitZ()),
98 });
99 const auto straws = bdata::make({
100  Surface::makeShared<StrawSurface>(Transform3D::Identity(), 2.0 /* radius */,
101  200.0 /* half z */),
102 });
103 
104 } // namespace
105 
106 BOOST_AUTO_TEST_SUITE(SurfaceLocalToGlobalRoundtrip)
107 
109  cones* posAngle* posPositiveNonzero* phis* thetas, surface,
110  lphi, lz, phi, theta) {
111  // TODO extend lz to zero after fixing the transform implementation
112  // local parameter r*phi has limits that depend on the z position
113  const auto r = lz * surface->bounds().tanAlpha();
114  // local coordinates are singular at z = 0 -> normalize local phi
115  runTest(*surface, (0 < lz) ? (r * lphi) : 0.0, lz, phi, theta);
116 }
117 
119  cylinders* posSymmetric* posSymmetric* phis* thetas,
120  surface, lrphi, lz, phi, theta) {
121  runTest(*surface, lrphi, lz, phi, theta);
122 }
123 
124 BOOST_DATA_TEST_CASE(DiscSurface, discs* posPositive* posAngle* phis* thetas,
125  surface, lr, lphi, phi, theta) {
126  // local coordinates are singular at r = 0 -> normalize local phi
127  runTest(*surface, lr, (0 < lr) ? lphi : 0.0, phi, theta);
128 }
129 
132  perigees* posSymmetric* posSymmetric* phis* thetasNoForwardBackward,
133  surface, d0, z0, phi, theta) {
134  // TODO extend theta to forward/back extreme cases fixing the transform
135  runTest(*surface, d0, z0, phi, theta);
136 }
137 
139  planes* posSymmetric* posSymmetric* phis* thetas, surface,
140  l0, l1, phi, theta) {
141  runTest(*surface, l0, l1, phi, theta);
142 }
143 
145  StrawSurface,
146  straws* posSymmetric* posSymmetric* phis* thetasNoForwardBackward, surface,
147  lr, lz, phi, theta) {
148  // TODO extend theta to forward/back extreme cases fixing the transform
149  runTest(*surface, lr, lz, phi, theta);
150 }
151 
152 BOOST_AUTO_TEST_SUITE_END()