ECCE @ 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 
21 
22 namespace bdata = boost::unit_test::data;
23 namespace tt = boost::test_tools;
24 
25 namespace Acts {
26 
27 namespace Test {
28 
29 BOOST_AUTO_TEST_SUITE(Geometry)
30 
31 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsConstruction) {
32  double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
33 
34  // Test different construciton modes: solid
35  CylinderVolumeBounds solidCylinder(0., rmax, halfz);
36  BOOST_CHECK_EQUAL(solidCylinder.decomposeToSurfaces().size(), 3);
37 
38  // Test different construciton modes: sectoral solid
39  CylinderVolumeBounds solidCylinderSector(0., rmax, halfz, halfphi);
40  BOOST_CHECK_EQUAL(solidCylinderSector.decomposeToSurfaces().size(), 5);
41 
42  // Test different construciton modes: tube
43  CylinderVolumeBounds tubeCylinder(rmin, rmax, halfz);
44  BOOST_CHECK_EQUAL(tubeCylinder.decomposeToSurfaces().size(), 4);
45 
46  // Test different construciton modes: sectoral tube
47  CylinderVolumeBounds tubeCylinderSector(rmin, rmax, halfz, halfphi);
48  BOOST_CHECK_EQUAL(tubeCylinderSector.decomposeToSurfaces().size(), 6);
49 
50  CylinderVolumeBounds original(rmin, rmax, halfz, halfphi, avgphi);
51 
52  // Test construction from CylinderBounds and thickness
53  double rmed = 0.5 * (rmin + rmax);
54  double rthickness = (rmax - rmin);
55  CylinderBounds cBounds(rmed, halfz, halfphi, avgphi);
56  CylinderVolumeBounds fromCylinder(cBounds, rthickness);
57  BOOST_CHECK_EQUAL(original, fromCylinder);
58 
59  // Test construction from RadialBounds and thickness
60  RadialBounds rBounds(rmin, rmax, halfphi, avgphi);
61  CylinderVolumeBounds fromDisc(rBounds, 2 * halfz);
62  BOOST_CHECK_EQUAL(original, fromDisc);
63 
64  // Test the copy construction
65  CylinderVolumeBounds copied(original);
66  BOOST_CHECK_EQUAL(original, copied);
67 
68  // Test the assignment
69  CylinderVolumeBounds assigned = original;
70  BOOST_CHECK_EQUAL(original, assigned);
71 }
72 
73 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsRecreation) {
74  double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
75 
76  CylinderVolumeBounds original(rmin, rmax, halfz, halfphi, avgphi);
77  std::array<double, CylinderVolumeBounds::eSize> values;
78  std::vector<double> valvector = original.values();
79  std::copy_n(valvector.begin(), CylinderVolumeBounds::eSize, values.begin());
80  CylinderVolumeBounds recreated(values);
81  BOOST_CHECK_EQUAL(original, recreated);
82 }
83 
84 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsExceptions) {
85  double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
86 
87  // Negative inner radius
88  BOOST_CHECK_THROW(CylinderVolumeBounds(-rmin, rmax, halfz, halfphi, avgphi),
89  std::logic_error);
90 
91  // Negative outer radius
92  BOOST_CHECK_THROW(CylinderVolumeBounds(rmin, -rmax, halfz, halfphi, avgphi),
93  std::logic_error);
94 
95  // Swapped radii
96  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, halfphi, avgphi),
97  std::logic_error);
98 
99  // Zero half length
100  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, 0., halfphi, avgphi),
101  std::logic_error);
102 
103  // Negative half length
104  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, -halfz, halfphi, avgphi),
105  std::logic_error);
106 
107  // Out of bounds half phi
108  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, -4., avgphi),
109  std::logic_error);
110 
111  // Wrong positioning phi
112  BOOST_CHECK_THROW(CylinderVolumeBounds(rmax, rmin, halfz, halfphi, 4.),
113  std::logic_error);
114 
115  // Test construction from CylinderBounds and thickness
116  double rmed = 0.5 * (rmin + rmax);
117  CylinderBounds cBounds(rmed, halfz, halfphi, avgphi);
118  RadialBounds rBounds(rmin, rmax, halfphi, avgphi);
119 
120  // Negative thickness
121  BOOST_CHECK_THROW(CylinderVolumeBounds(cBounds, -1.), std::logic_error);
122 
123  // Wrong thickness
124  BOOST_CHECK_THROW(CylinderVolumeBounds(cBounds, 1000.), std::logic_error);
125 
126  // Test construction from RadialBounds and thickness
127  BOOST_CHECK_THROW(CylinderVolumeBounds(rBounds, -1), std::logic_error);
128 }
129 
130 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsAccess) {
131  double rmin{10.}, rmax{20.}, halfz{30.}, halfphi{M_PI / 4}, avgphi{0.};
132  CylinderVolumeBounds cvBounds(rmin, rmax, halfz, halfphi, avgphi);
133 
134  // Test the accessors
135  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eMinR), rmin);
136  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eMaxR), rmax);
137  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eHalfLengthZ), halfz);
138  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eHalfPhiSector),
139  halfphi);
140  BOOST_CHECK_EQUAL(cvBounds.get(CylinderVolumeBounds::eAveragePhi), avgphi);
141 }
142 
144 BOOST_DATA_TEST_CASE(CylinderVolumeBoundsDecomposeToSurfaces,
145  bdata::random(-M_PI, M_PI) ^ bdata::random(-M_PI, M_PI) ^
146  bdata::random(-M_PI, M_PI) ^ bdata::random(-10., 10.) ^
147  bdata::random(-10., 10.) ^ bdata::random(-10., 10.) ^
148  bdata::xrange(100),
149  alpha, beta, gamma, posX, posY, posZ, index) {
150  (void)index;
151 
152  // Create a test context
154 
155  // position of volume
156  const Vector3D pos(posX, posY, posZ);
157  // rotation around x axis
158  AngleAxis3D rotX(alpha, Vector3D(1., 0., 0.));
159  // rotation around y axis
160  AngleAxis3D rotY(beta, Vector3D(0., 1., 0.));
161  // rotation around z axis
162  AngleAxis3D rotZ(gamma, Vector3D(0., 0., 1.));
163 
164  // create the cylinder bounds
165  double rmin = 1.;
166  double rmax = 2.;
167  double halfz = 3.;
168  CylinderVolumeBounds cylBounds(rmin, rmax, halfz);
169  // create the transformation matrix
170  auto mutableTransformPtr = std::make_shared<Transform3D>(Translation3D(pos));
171  (*mutableTransformPtr) *= rotZ;
172  (*mutableTransformPtr) *= rotY;
173  (*mutableTransformPtr) *= rotX;
174  auto transformPtr =
175  std::const_pointer_cast<const Transform3D>(mutableTransformPtr);
176  // get the boundary surfaces
177  std::vector<std::shared_ptr<const Acts::Surface>> boundarySurfaces =
178  cylBounds.decomposeToSurfaces(transformPtr.get());
179  // Test
180 
181  // check if difference is halfZ - sign and direction independent
182  CHECK_CLOSE_REL((pos - boundarySurfaces.at(0)->center(tgContext)).norm(),
183  cylBounds.get(CylinderVolumeBounds::eHalfLengthZ), 1e-12);
184  CHECK_CLOSE_REL((pos - boundarySurfaces.at(1)->center(tgContext)).norm(),
185  cylBounds.get(CylinderVolumeBounds::eHalfLengthZ), 1e-12);
186  // transform to local
187  double posDiscPosZ =
188  (transformPtr->inverse() * boundarySurfaces.at(1)->center(tgContext)).z();
189  double centerPosZ = (transformPtr->inverse() * pos).z();
190  double negDiscPosZ =
191  (transformPtr->inverse() * boundarySurfaces.at(0)->center(tgContext)).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  transformPtr->rotation().col(2).dot(
208  boundarySurfaces.at(1)->normal(tgContext, Acts::Vector2D(0., 0.))),
209  1., 1e-12);
210  // negative disc durface should point in negative direction in the frame of
211  // the volume
213  transformPtr->rotation().col(2).dot(
214  boundarySurfaces.at(0)->normal(tgContext, Acts::Vector2D(0., 0.))),
215  -1., 1e-12);
216  // test in r
217  CHECK_CLOSE_REL(boundarySurfaces.at(3)->center(tgContext), pos, 1e-12);
218  CHECK_CLOSE_REL(boundarySurfaces.at(2)->center(tgContext), pos, 1e-12);
219 }
220 
221 BOOST_AUTO_TEST_CASE(CylinderVolumeBoundsBoundingBox) {
223  std::vector<IdentifiedPolyderon> tPolyhedrons;
224 
225  auto combineAndDecompose = [&](const SurfacePtrVector& surfaces,
226  const std::string& name) -> void {
227  std::string writeBase = std::string("CylinderVolumeBounds_") + name;
228 
229  Polyhedron phCombined;
230  size_t is = 0;
231  for (const auto& sf : surfaces) {
232  Polyhedron phComponent = sf->polyhedronRepresentation(tgContext, 72);
233  phCombined.merge(phComponent);
234  tPolyhedrons.push_back(
235  {writeBase + std::string("_comp_") + std::to_string(is++), false,
236  phComponent});
237  }
238  tPolyhedrons.push_back({writeBase, false, phCombined});
239  };
240 
241  float tol = 1e-4;
242 
243  CylinderVolumeBounds cvb(0., 5, 10);
244  auto cvbSurfaces = cvb.decomposeToSurfaces();
245  combineAndDecompose(cvbSurfaces, "Solid");
246  auto bb = cvb.boundingBox();
247  ObjTestWriter::writeObj("CylinderVolumeBounds_Solid_BB", bb);
248 
249  Transform3D rot;
250  rot = AngleAxis3D(M_PI / 2., Vector3D::UnitX());
251 
252  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
253  BOOST_CHECK_EQUAL(bb.max(), Vector3D(5, 5, 10));
254  BOOST_CHECK_EQUAL(bb.min(), Vector3D(-5, -5, -10));
255 
256  bb = cvb.boundingBox(&rot);
257  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
258  CHECK_CLOSE_ABS(bb.max(), Vector3D(5, 10, 5), tol);
259  CHECK_CLOSE_ABS(bb.min(), Vector3D(-5, -10, -5), tol);
260 
261  cvb = CylinderVolumeBounds(5, 8, 12);
262  bb = cvb.boundingBox();
263  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
264  BOOST_CHECK_EQUAL(bb.max(), Vector3D(8, 8, 12));
265  BOOST_CHECK_EQUAL(bb.min(), Vector3D(-8, -8, -12));
266  cvbSurfaces = cvb.decomposeToSurfaces();
267  combineAndDecompose(cvbSurfaces, "Tube");
268  ObjTestWriter::writeObj("CylinderVolumeBounds_Tube_BB", bb);
269 
270  double angle = M_PI / 8.;
271  cvb = CylinderVolumeBounds(5, 8, 13, angle);
272  bb = cvb.boundingBox();
273  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
274  CHECK_CLOSE_ABS(bb.max(), Vector3D(8, 8 * std::sin(angle), 13), tol);
276  bb.min(), Vector3D(5 * std::cos(angle), -8 * std::sin(angle), -13), tol);
277  cvbSurfaces = cvb.decomposeToSurfaces();
278  combineAndDecompose(cvbSurfaces, "TubeSector");
279  ObjTestWriter::writeObj("CylinderVolumeBounds_TubeSector_BB", bb);
280 
281  rot = AngleAxis3D(M_PI / 2., Vector3D::UnitZ());
282  bb = cvb.boundingBox(&rot);
283  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
284  CHECK_CLOSE_ABS(bb.max(), Vector3D(8 * std::sin(angle), 8, 13), tol);
286  bb.min(), Vector3D(-8 * std::sin(angle), 5 * std::cos(angle), -13), tol);
287 
288  rot = AngleAxis3D(M_PI / 2., Vector3D(-2, 4, 5).normalized());
289  bb = cvb.boundingBox(&rot);
290  BOOST_CHECK_EQUAL(bb.entity(), nullptr);
291  CHECK_CLOSE_ABS(bb.max(), Vector3D(8.40007, 15.2828, 3.88911), tol);
292  CHECK_CLOSE_ABS(bb.min(), Vector3D(-7.27834, -8.12028, -14.2182), tol);
293  ObjTestWriter::writeObj(tPolyhedrons);
294 }
295 
296 BOOST_AUTO_TEST_SUITE_END()
297 
298 } // namespace Test
299 
300 } // namespace Acts