EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CylinderVolumeBoundsTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CylinderVolumeBoundsTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2018 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/unit_test.hpp>
11 
20 
21 namespace bdata = boost::unit_test::data;
22 namespace tt = boost::test_tools;
23 
24 namespace Acts {
25 
26 namespace Test {
27 
28 BOOST_AUTO_TEST_SUITE(Geometry)
29 
30 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsConstruction) {
31  double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
32 
33  // Test different construciton modes: solid
34  CylinderVolumeBounds solidCylinder(0., rmax, halfz);
35  BOOST_CHECK_EQUAL(solidCylinder.orientedSurfaces().size(), 3);
36 
37  // Test different construciton modes: sectoral solid
38  CylinderVolumeBounds solidCylinderSector(0., rmax, halfz, halfphi);
39  BOOST_CHECK_EQUAL(solidCylinderSector.orientedSurfaces().size(), 5);
40 
41  // Test different construciton modes: tube
42  CylinderVolumeBounds tubeCylinder(rmin, rmax, halfz);
43  BOOST_CHECK_EQUAL(tubeCylinder.orientedSurfaces().size(), 4);
44 
45  // Test different construciton modes: sectoral tube
46  CylinderVolumeBounds tubeCylinderSector(rmin, rmax, halfz, halfphi);
47  BOOST_CHECK_EQUAL(tubeCylinderSector.orientedSurfaces().size(), 6);
48 
49  CylinderVolumeBounds original(rmin, rmax, halfz, halfphi, avgphi);
50 
51  // Test construction from CylinderBounds and thickness
52  double rmed = 0.5 * (rmin + rmax);
53  double rthickness = (rmax - rmin);
54  CylinderBounds cBounds(rmed, halfz, halfphi, avgphi);
55  CylinderVolumeBounds fromCylinder(cBounds, rthickness);
56  BOOST_CHECK_EQUAL(original, fromCylinder);
57 
58  // Test construction from RadialBounds and thickness
59  RadialBounds rBounds(rmin, rmax, halfphi, avgphi);
60  CylinderVolumeBounds fromDisc(rBounds, 2 * halfz);
61  BOOST_CHECK_EQUAL(original, fromDisc);
62 
63  // Test the copy construction
64  CylinderVolumeBounds copied(original);
65  BOOST_CHECK_EQUAL(original, copied);
66 
67  // Test the assignment
68  CylinderVolumeBounds assigned = original;
69  BOOST_CHECK_EQUAL(original, assigned);
70 }
71 
72 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsRecreation) {
73  double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
74 
75  CylinderVolumeBounds original(rmin, rmax, halfz, halfphi, avgphi);
76  std::array<double, CylinderVolumeBounds::eSize> values;
77  std::vector<double> valvector = original.values();
78  std::copy_n(valvector.begin(), CylinderVolumeBounds::eSize, values.begin());
79  CylinderVolumeBounds recreated(values);
80  BOOST_CHECK_EQUAL(original, recreated);
81 }
82 
83 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsExceptions) {
84  double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
85 
86  // Negative inner radius
87  BOOST_CHECK_THROW(CylinderVolumeBounds(-rmin, rmax, halfz, halfphi, avgphi),
88  std::logic_error);
89 
90  // Negative outer radius
91  BOOST_CHECK_THROW(CylinderVolumeBounds(rmin, -rmax, halfz, halfphi, avgphi),
92  std::logic_error);
93 
94  // Swapped radii
95  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, halfphi, avgphi),
96  std::logic_error);
97 
98  // Zero half length
99  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, 0., halfphi, avgphi),
100  std::logic_error);
101 
102  // Negative half length
103  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, -halfz, halfphi, avgphi),
104  std::logic_error);
105 
106  // Out of bounds half phi
107  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, -4., avgphi),
108  std::logic_error);
109 
110  // Wrong positioning phi
111  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, halfphi, 4.),
112  std::logic_error);
113 
114  // Test construction from CylinderBounds and thickness
115  double rmed = 0.5 * (rmin + rmax);
116  CylinderBounds cBounds(rmed, halfz, halfphi, avgphi);
117  RadialBounds rBounds(rmin, rmax, halfphi, avgphi);
118 
119  // Negative thickness
120  BOOST_CHECK_THROW(CylinderVolumeBounds(cBounds, -1.), std::logic_error);
121 
122  // Wrong thickness
123  BOOST_CHECK_THROW(CylinderVolumeBounds(cBounds, 1000.), std::logic_error);
124 
125  // Test construction from RadialBounds and thickness
126  BOOST_CHECK_THROW(CylinderVolumeBounds(rBounds, -1), std::logic_error);
127 }
128 
129 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsAccess) {
130  double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
131  CylinderVolumeBounds cvBounds(rmin, rmax, halfz, halfphi, avgphi);
132 
133  // Test the accessors
134  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eMinR), rmin);
135  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eMaxR), rmax);
136  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eHalfLengthZ), halfz);
137  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eHalfPhiSector),
138  halfphi);
139  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eAveragePhi), avgphi);
140 }
141 
143 BOOST_DATA_TEST_CASE(CylinderVolumeBoundsOrientedSurfaces,
144  bdata::random(-M_PI, M_PI) ^ bdata::random(-M_PI, M_PI) ^
145  bdata::random(-M_PI, M_PI) ^ bdata::random(-10., 10.) ^
146  bdata::random(-10., 10.) ^ bdata::random(-10., 10.) ^
147  bdata::xrange(100),
148  alpha, beta, gamma, posX, posY, posZ, index) {
149  (void)index;
150 
151  // Create a test context
153 
154  // position of volume
155  const Vector3D pos(posX, posY, posZ);
156  // rotation around x axis
157  AngleAxis3D rotX(alpha, Vector3D(1., 0., 0.));
158  // rotation around y axis
159  AngleAxis3D rotY(beta, Vector3D(0., 1., 0.));
160  // rotation around z axis
161  AngleAxis3D rotZ(gamma, Vector3D(0., 0., 1.));
162 
163  // create the cylinder bounds
164  double rmin = 1.;
165  double rmax = 2.;
166  double halfz = 3.;
167  CylinderVolumeBounds cylBounds(rmin, rmax, halfz);
168  // create the transformation matrix
169  auto transform = Transform3D(Translation3D(pos));
170  transform *= rotZ;
171  transform *= rotY;
172  transform *= rotX;
173  // get the boundary surfaces
174  auto boundarySurfaces = cylBounds.orientedSurfaces(transform);
175  // Test
176 
177  // check if difference is halfZ - sign and direction independent
179  (pos - boundarySurfaces.at(0).first->center(tgContext)).norm(),
180  cylBounds.get(CylinderVolumeBounds::eHalfLengthZ), 1e-12);
182  (pos - boundarySurfaces.at(1).first->center(tgContext)).norm(),
183  cylBounds.get(CylinderVolumeBounds::eHalfLengthZ), 1e-12);
184  // transform to local
185  double posDiscPosZ =
186  (transform.inverse() * boundarySurfaces.at(1).first->center(tgContext))
187  .z();
188  double centerPosZ = (transform.inverse() * pos).z();
189  double negDiscPosZ =
190  (transform.inverse() * boundarySurfaces.at(0).first->center(tgContext))
191  .z();
192  // check if center of disc boundaries lies in the middle in z
193  BOOST_CHECK_LT(centerPosZ, posDiscPosZ);
194  BOOST_CHECK_GT(centerPosZ, negDiscPosZ);
195  // check positions of disc boundarysurfaces
196  // checks for zero value. double precision value is not exact.
198  negDiscPosZ + cylBounds.get(CylinderVolumeBounds::eHalfLengthZ),
199  centerPosZ, 1e-12);
201  posDiscPosZ - cylBounds.get(CylinderVolumeBounds::eHalfLengthZ),
202  centerPosZ, 1e-12);
203  // orientation of disc surfaces
204  // positive disc durface should point in positive direction in the frame of
205  // the volume
207  transform.rotation().col(2).dot(boundarySurfaces.at(1).first->normal(
208  tgContext, Acts::Vector2D(0., 0.))),
209  1., 1e-12);
210  // negative disc durface should point in positive direction in the frame of
211  // the volume
213  transform.rotation().col(2).dot(boundarySurfaces.at(0).first->normal(
214  tgContext, Acts::Vector2D(0., 0.))),
215  1., 1e-12);
216  // test in r
217  CHECK_CLOSE_REL(boundarySurfaces.at(3).first->center(tgContext), pos, 1e-12);
218  CHECK_CLOSE_REL(boundarySurfaces.at(2).first->center(tgContext), pos, 1e-12);
219 }
220 
221 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsBoundingBox) {
223 
224  float tol = 1e-4;
225 
226  CylinderVolumeBounds cvb(0., 5, 10);
227  auto bb = cvb.boundingBox();
228 
229  Transform3D rot;
230  rot = AngleAxis3D(M_PI / 2., Vector3D::UnitX());
231 
232  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
233  BOOST_CHECK_EQUAL(bb.max(), Vector3D(5, 5, 10));
234  BOOST_CHECK_EQUAL(bb.min(), Vector3D(-5, -5, -10));
235 
236  bb = cvb.boundingBox(&rot);
237  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
238  CHECK_CLOSE_ABS(bb.max(), Vector3D(5, 10, 5), tol);
239  CHECK_CLOSE_ABS(bb.min(), Vector3D(-5, -10, -5), tol);
240 
241  cvb = CylinderVolumeBounds(5, 8, 12);
242  bb = cvb.boundingBox();
243  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
244  BOOST_CHECK_EQUAL(bb.max(), Vector3D(8, 8, 12));
245  BOOST_CHECK_EQUAL(bb.min(), Vector3D(-8, -8, -12));
246 
247  double angle = M_PI / 8.;
248  cvb = CylinderVolumeBounds(5, 8, 13, angle);
249  bb = cvb.boundingBox();
250  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
251  CHECK_CLOSE_ABS(bb.max(), Vector3D(8, 8 * std::sin(angle), 13), tol);
253  bb.min(), Vector3D(5 * std::cos(angle), -8 * std::sin(angle), -13), tol);
254 
255  rot = AngleAxis3D(M_PI / 2., Vector3D::UnitZ());
256  bb = cvb.boundingBox(&rot);
257  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
258  CHECK_CLOSE_ABS(bb.max(), Vector3D(8 * std::sin(angle), 8, 13), tol);
260  bb.min(), Vector3D(-8 * std::sin(angle), 5 * std::cos(angle), -13), tol);
261 
262  rot = AngleAxis3D(M_PI / 2., Vector3D(-2, 4, 5).normalized());
263  bb = cvb.boundingBox(&rot);
264  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
265  CHECK_CLOSE_ABS(bb.max(), Vector3D(8.40007, 15.2828, 3.88911), tol);
266  CHECK_CLOSE_ABS(bb.min(), Vector3D(-7.27834, -8.12028, -14.2182), tol);
267 }
268 
269 BOOST_AUTO_TEST_CASE(CylinderVolumeOrientedBoundaries) {
271 
272  CylinderVolumeBounds cvb(5, 10, 20);
273 
274  auto cvbOrientedSurfaces = cvb.orientedSurfaces(Transform3D::Identity());
275  BOOST_CHECK_EQUAL(cvbOrientedSurfaces.size(), 4);
276 
277  auto geoCtx = GeometryContext();
278  Vector3D xaxis(1., 0., 0.);
279  Vector3D yaxis(0., 1., 0.);
280  Vector3D zaxis(0., 0., 1.);
281 
282  for (auto& os : cvbOrientedSurfaces) {
283  auto onSurface = os.first->binningPosition(geoCtx, binR);
284  auto osNormal = os.first->normal(geoCtx, onSurface);
285  double nDir = (double)os.second;
286  // Check if you step inside the volume with the oriented normal
287  auto insideCvb = onSurface + nDir * osNormal;
288  auto outsideCvb = onSurface - nDir * osNormal;
289 
290  BOOST_CHECK(cvb.inside(insideCvb));
291  BOOST_CHECK(!cvb.inside(outsideCvb));
292 
293  // Test the orientation of the boundary surfaces
294  auto rot = os.first->transform(geoCtx).rotation();
295  BOOST_CHECK(rot.col(0).isApprox(xaxis));
296  BOOST_CHECK(rot.col(1).isApprox(yaxis));
297  BOOST_CHECK(rot.col(2).isApprox(zaxis));
298  }
299 }
300 
301 BOOST_AUTO_TEST_SUITE_END()
302 
303 } // namespace Test
304 
305 } // namespace Acts