Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CylinderSurfaceTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CylinderSurfaceTests.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/tools/output_test_stream.hpp>
11 #include <boost/test/unit_test.hpp>
12 
16 #include "Acts/Geometry/Extent.hpp"
28 
29 #include <algorithm>
30 #include <cmath>
31 #include <initializer_list>
32 #include <memory>
33 #include <ostream>
34 #include <string>
35 #include <utility>
36 
37 namespace Acts {
38 class AssertionFailureException;
39 } // namespace Acts
40 
41 namespace tt = boost::test_tools;
42 using boost::test_tools::output_test_stream;
43 namespace utf = boost::unit_test;
44 
45 namespace Acts {
46 
47 namespace Test {
48 
49 // Create a test context
51 
52 BOOST_AUTO_TEST_SUITE(CylinderSurfaces)
54 BOOST_AUTO_TEST_CASE(CylinderSurfaceConstruction) {
55  // CylinderSurface default constructor is deleted
56  //
58  double radius(1.0), halfZ(10.), halfPhiSector(M_PI / 8.);
59  Translation3 translation{0., 1., 2.};
60  auto pTransform = Transform3(translation);
61  BOOST_CHECK_EQUAL(
62  Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ)->type(),
64  //
66  BOOST_CHECK_EQUAL(Surface::makeShared<CylinderSurface>(pTransform, radius,
67  halfZ, halfPhiSector)
68  ->type(),
70 
72  auto pCylinderBounds = std::make_shared<const CylinderBounds>(radius, halfZ);
73  BOOST_CHECK_EQUAL(
74  Surface::makeShared<CylinderSurface>(pTransform, pCylinderBounds)->type(),
76  //
77  //
79  auto cylinderSurfaceObject =
80  Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
81  auto copiedCylinderSurface =
82  Surface::makeShared<CylinderSurface>(*cylinderSurfaceObject);
83  BOOST_CHECK_EQUAL(copiedCylinderSurface->type(), Surface::Cylinder);
84  BOOST_CHECK(*copiedCylinderSurface == *cylinderSurfaceObject);
85  //
87  auto copiedTransformedCylinderSurface = Surface::makeShared<CylinderSurface>(
88  testContext, *cylinderSurfaceObject, pTransform);
89  BOOST_CHECK_EQUAL(copiedTransformedCylinderSurface->type(),
91 
93  BOOST_CHECK_THROW(auto nullBounds = Surface::makeShared<CylinderSurface>(
94  Transform3::Identity(), nullptr),
96 }
97 //
99 BOOST_AUTO_TEST_CASE(CylinderSurfaceProperties) {
101  double radius(1.0), halfZ(10.);
102  Translation3 translation{0., 1., 2.};
103  auto pTransform = Transform3(translation);
104  auto cylinderSurfaceObject =
105  Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
106  //
108  BOOST_CHECK_EQUAL(cylinderSurfaceObject->type(), Surface::Cylinder);
109  //
111  Vector3 binningPosition{0., 1., 2.};
113  cylinderSurfaceObject->binningPosition(testContext, BinningValue::binPhi),
114  binningPosition, 1e-9);
115  //
117  double rootHalf = std::sqrt(0.5);
118  Vector3 globalPosition{rootHalf, 1. - rootHalf, 0.};
119  Vector3 globalPositionZ{rootHalf, 1. - rootHalf, 2.0};
120  Vector3 momentum{15., 15., 15.};
121  Vector3 momentum2{6.6, -3., 2.};
122  RotationMatrix3 expectedFrame;
123  expectedFrame << rootHalf, 0., rootHalf, rootHalf, 0., -rootHalf, 0., 1., 0.;
124  // check without shift
125  CHECK_CLOSE_OR_SMALL(cylinderSurfaceObject->referenceFrame(
126  testContext, globalPosition, momentum),
127  expectedFrame, 1e-6, 1e-9);
128  // check with shift and different momentum
129  CHECK_CLOSE_OR_SMALL(cylinderSurfaceObject->referenceFrame(
130  testContext, globalPositionZ, momentum2),
131  expectedFrame, 1e-6, 1e-9);
132  //
134  Vector3 origin{0., 0., 0.};
135  Vector3 normal3D = {0., -1., 0.};
136  CHECK_CLOSE_ABS(cylinderSurfaceObject->normal(testContext, origin), normal3D,
137  1e-9);
138 
139  Vector3 pos45deg = {rootHalf, 1 + rootHalf, 0.};
140  Vector3 pos45degZ = {rootHalf, 1 + rootHalf, 4.};
141  Vector3 normal45deg = {rootHalf, rootHalf, 0.};
142  // test the normal vector
143  CHECK_CLOSE_ABS(cylinderSurfaceObject->normal(testContext, pos45deg),
144  normal45deg, 1e-6 * rootHalf);
145  // test that the normal vector is independent of z coordinate
146  CHECK_CLOSE_ABS(cylinderSurfaceObject->normal(testContext, pos45degZ),
147  normal45deg, 1e-6 * rootHalf);
148  //
150  Vector2 positionPiBy2(1.0, 0.);
151  Vector3 normalAtPiBy2{std::cos(1.), std::sin(1.), 0.};
152  CHECK_CLOSE_ABS(cylinderSurfaceObject->normal(testContext, positionPiBy2),
153  normalAtPiBy2, 1e-9);
154 
155  //
157  Vector3 symmetryAxis{0., 0., 1.};
158  CHECK_CLOSE_ABS(cylinderSurfaceObject->rotSymmetryAxis(testContext),
159  symmetryAxis, 1e-9);
160  //
162  BOOST_CHECK_EQUAL(cylinderSurfaceObject->bounds().type(),
164  //
166  Vector2 localPosition{0., 0.};
167  globalPosition = cylinderSurfaceObject->localToGlobal(
168  testContext, localPosition, momentum);
169  Vector3 expectedPosition{1, 1, 2};
170  BOOST_CHECK_EQUAL(globalPosition, expectedPosition);
171  //
173  localPosition = cylinderSurfaceObject
174  ->globalToLocal(testContext, globalPosition, momentum)
175  .value();
176  Vector2 expectedLocalPosition{0., 0.};
177  BOOST_CHECK_EQUAL(localPosition, expectedLocalPosition);
178  //
180  Vector3 offSurface{100, 1, 2};
181  BOOST_CHECK(cylinderSurfaceObject->isOnSurface(testContext, globalPosition,
182  momentum, true));
183  BOOST_CHECK(!cylinderSurfaceObject->isOnSurface(testContext, offSurface,
184  momentum, true));
185  //
187  Vector3 direction{-1., 0, 0};
188  auto sfIntersection = cylinderSurfaceObject->intersect(
189  testContext, offSurface, direction, false);
190  Intersection3D expectedIntersect{Vector3{1, 1, 2}, 99.,
191  Intersection3D::Status::reachable};
192  BOOST_CHECK(sfIntersection[0]);
193  CHECK_CLOSE_ABS(sfIntersection[0].position(), expectedIntersect.position(),
194  1e-9);
195  CHECK_CLOSE_ABS(sfIntersection[0].pathLength(),
196  expectedIntersect.pathLength(), 1e-9);
197  // there is a second solution & and it should be valid
198  BOOST_CHECK(sfIntersection[1]);
199  // And it's path should be further away then the primary solution
200  double pn = sfIntersection[0].pathLength();
201  double pa = sfIntersection[1].pathLength();
202  BOOST_CHECK(std::abs(pn) < std::abs(pa));
203  BOOST_CHECK_EQUAL(sfIntersection.object(), cylinderSurfaceObject.get());
204 
205  //
207  CHECK_CLOSE_REL(cylinderSurfaceObject->pathCorrection(testContext, offSurface,
208  momentum.normalized()),
209  std::sqrt(3.), 0.01);
210  //
212  BOOST_CHECK_EQUAL(cylinderSurfaceObject->name(),
213  std::string("Acts::CylinderSurface"));
214  //
216  boost::test_tools::output_test_stream dumpOuput;
217  cylinderSurfaceObject->toStream(testContext, dumpOuput);
218  BOOST_CHECK(
219  dumpOuput.is_equal("Acts::CylinderSurface\n\
220  Center position (x, y, z) = (0.0000, 1.0000, 2.0000)\n\
221  Rotation: colX = (1.000000, 0.000000, 0.000000)\n\
222  colY = (0.000000, 1.000000, 0.000000)\n\
223  colZ = (0.000000, 0.000000, 1.000000)\n\
224  Bounds : Acts::CylinderBounds: (radius, halfLengthZ, halfPhiSector, averagePhi, bevelMinZ, bevelMaxZ) = (1.0000000, 10.0000000, 3.1415927, 0.0000000, 0.0000000, 0.0000000)"));
225 }
226 
227 BOOST_AUTO_TEST_CASE(CylinderSurfaceEqualityOperators) {
228  double radius(1.0), halfZ(10.);
229  Translation3 translation{0., 1., 2.};
230  auto pTransform = Transform3(translation);
231  auto cylinderSurfaceObject =
232  Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
233  //
234  auto cylinderSurfaceObject2 =
235  Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
236  //
238  BOOST_CHECK(*cylinderSurfaceObject == *cylinderSurfaceObject2);
239  //
240  BOOST_TEST_CHECKPOINT(
241  "Create and then assign a CylinderSurface object to the existing one");
243  auto assignedCylinderSurface =
244  Surface::makeShared<CylinderSurface>(Transform3::Identity(), 6.6, 5.4);
245  *assignedCylinderSurface = *cylinderSurfaceObject;
247  BOOST_CHECK(*assignedCylinderSurface == *cylinderSurfaceObject);
248 }
249 
251 BOOST_AUTO_TEST_CASE(CylinderSurfaceExtent) {
252  // Some radius and half length
253  double radius(1.0), halfZ(10.);
254  Translation3 translation{0., 0., 2.};
255  auto pTransform = Transform3(translation);
256  auto cylinderSurface =
257  Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
258  // The Extent, let's measure it
259  auto cylinderExtent =
260  cylinderSurface->polyhedronRepresentation(testContext, 1).extent();
261 
262  CHECK_CLOSE_ABS(-8, cylinderExtent.min(binZ), s_onSurfaceTolerance);
263  CHECK_CLOSE_ABS(12, cylinderExtent.max(binZ), s_onSurfaceTolerance);
264  CHECK_CLOSE_ABS(radius, cylinderExtent.min(binR), s_onSurfaceTolerance);
265  CHECK_CLOSE_ABS(radius, cylinderExtent.max(binR), s_onSurfaceTolerance);
266  CHECK_CLOSE_ABS(-radius, cylinderExtent.min(binX), s_onSurfaceTolerance);
267  CHECK_CLOSE_ABS(radius, cylinderExtent.max(binX), s_onSurfaceTolerance);
268  CHECK_CLOSE_ABS(-radius, cylinderExtent.min(binY), s_onSurfaceTolerance);
269  CHECK_CLOSE_ABS(radius, cylinderExtent.max(binY), s_onSurfaceTolerance);
270 }
271 
273 BOOST_AUTO_TEST_CASE(CylinderSurfaceAlignment) {
274  double radius(1.0), halfZ(10.);
275  Translation3 translation{0., 1., 2.};
276  auto pTransform = Transform3(translation);
277  auto cylinderSurfaceObject =
278  Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
279 
280  const auto& rotation = pTransform.rotation();
281  // The local frame z axis
282  const Vector3 localZAxis = rotation.col(2);
283  // Check the local z axis is aligned to global z axis
284  CHECK_CLOSE_ABS(localZAxis, Vector3(0., 0., 1.), 1e-15);
285 
287  Vector3 globalPosition{0, 2, 2};
288 
289  // Test the derivative of bound track parameters local position w.r.t.
290  // position in local 3D Cartesian coordinates
291  const auto& loc3DToLocBound =
292  cylinderSurfaceObject->localCartesianToBoundLocalDerivative(
293  testContext, globalPosition);
294  // Check if the result is as expected
295  ActsMatrix<2, 3> expLoc3DToLocBound = ActsMatrix<2, 3>::Zero();
296  expLoc3DToLocBound << -1, 0, 0, 0, 0, 1;
297  CHECK_CLOSE_ABS(loc3DToLocBound, expLoc3DToLocBound, 1e-10);
298 }
299 
300 BOOST_AUTO_TEST_CASE(CylinderSurfaceBinningPosition) {
301  using namespace Acts::UnitLiterals;
302  Vector3 s{5_mm, 7_mm, 10_cm};
303  Transform3 trf;
304  trf = Translation3(s) * AngleAxis3{0.5, Vector3::UnitZ()};
305 
306  double r = 300;
307  double halfZ = 330;
308  double averagePhi = 0.1;
309 
310  auto bounds =
311  std::make_shared<CylinderBounds>(r, halfZ, M_PI / 8, averagePhi);
312  auto cylinder = Acts::Surface::makeShared<CylinderSurface>(trf, bounds);
313 
314  Vector3 exp = Vector3{r * std::cos(averagePhi), r * std::sin(averagePhi), 0};
315  exp = trf * exp;
316 
317  Vector3 bp = cylinder->binningPosition(testContext, binR);
318  CHECK_CLOSE_ABS(bp, exp, 1e-10);
319  CHECK_CLOSE_ABS(cylinder->binningPositionValue(testContext, binR),
320  VectorHelpers::perp(exp), 1e-10);
321 
322  bp = cylinder->binningPosition(testContext, binRPhi);
323  CHECK_CLOSE_ABS(bp, exp, 1e-10);
324  CHECK_CLOSE_ABS(cylinder->binningPositionValue(testContext, binRPhi),
325  VectorHelpers::phi(exp) * VectorHelpers::perp(exp), 1e-10);
326 
327  for (auto b : {binX, binY, binZ, binEta, binH, binMag}) {
328  BOOST_TEST_CONTEXT("binValue: " << b) {
329  BOOST_CHECK_EQUAL(cylinder->binningPosition(testContext, b),
330  cylinder->center(testContext));
331  }
332  }
333 }
334 
335 BOOST_AUTO_TEST_SUITE_END()
336 
337 } // namespace Test
338 
339 } // namespace Acts