Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DiscSurfaceTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file DiscSurfaceTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2021 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 
18 #include "Acts/Geometry/Extent.hpp"
32 
33 #include <algorithm>
34 #include <cmath>
35 #include <initializer_list>
36 #include <memory>
37 #include <ostream>
38 #include <string>
39 #include <utility>
40 
41 namespace utf = boost::unit_test;
42 namespace tt = boost::test_tools;
43 
44 namespace Acts {
45 class AssertionFailureException;
46 
47 namespace Test {
48 // using boost::test_tools::output_test_stream;
49 // Create a test context
51 
52 BOOST_AUTO_TEST_SUITE(Surfaces)
54 BOOST_AUTO_TEST_CASE(DiscSurfaceConstruction) {
55  // default constructor is deleted
56  // scaffolding...
57  double rMin(1.0), rMax(5.0), halfPhiSector(M_PI / 8.);
58  //
60  BOOST_CHECK_NO_THROW(
61  Surface::makeShared<DiscSurface>(Transform3::Identity(), rMin, rMax));
62  //
64  Translation3 translation{0., 1., 2.};
65  auto pTransform = Transform3(translation);
66  BOOST_CHECK_NO_THROW(
67  Surface::makeShared<DiscSurface>(pTransform, rMin, rMax, halfPhiSector));
68  //
70  auto anotherDiscSurface =
71  Surface::makeShared<DiscSurface>(pTransform, rMin, rMax, halfPhiSector);
72  // N.B. Just using
73  // BOOST_CHECK_NO_THROW(Surface::makeShared<DiscSurface>(anotherDiscSurface))
74  // tries to call
75  // the (deleted) default constructor.
76  auto copiedSurface = Surface::makeShared<DiscSurface>(*anotherDiscSurface);
77  BOOST_TEST_MESSAGE("Copy constructed DiscSurface ok");
78  //
80  BOOST_CHECK_NO_THROW(Surface::makeShared<DiscSurface>(
81  tgContext, *anotherDiscSurface, pTransform));
82 
84  DetectorElementStub detElem;
85  BOOST_CHECK_THROW(
86  auto nullBounds = Surface::makeShared<DiscSurface>(nullptr, detElem),
88 }
89 
91 BOOST_AUTO_TEST_CASE(DiscSurfaceProperties) {
92  Vector3 origin3D{0, 0, 0};
93  double rMin(1.0), rMax(5.0), halfPhiSector(M_PI / 8.);
94  auto discSurfaceObject = Surface::makeShared<DiscSurface>(
95  Transform3::Identity(), rMin, rMax, halfPhiSector);
96  //
98  BOOST_CHECK_EQUAL(discSurfaceObject->type(), Surface::Disc);
99  //
101  Vector3 zAxis{0, 0, 1};
102  BOOST_CHECK_EQUAL(discSurfaceObject->normal(tgContext), zAxis);
103  //
105  Vector2 lpos(2.0, 0.05);
106  BOOST_CHECK_EQUAL(discSurfaceObject->normal(tgContext, lpos), zAxis);
107  //
109  // auto binningPosition=
110  // discSurfaceObject.binningPosition(BinningValue::binRPhi );
111  // std::cout<<binningPosition<<std::endl;
112  BOOST_CHECK_EQUAL(
113  discSurfaceObject->binningPosition(tgContext, BinningValue::binRPhi),
114  origin3D);
115  //
117  BOOST_CHECK_EQUAL(discSurfaceObject->bounds().type(), SurfaceBounds::eDisc);
118  //
119  Vector3 ignoredMomentum{0., 0., 0.};
121  Vector3 point3DNotInSector{0.0, 1.2, 0};
122  Vector3 point3DOnSurface{1.2, 0.0, 0};
123  BOOST_CHECK(!discSurfaceObject->isOnSurface(
124  tgContext, point3DNotInSector, ignoredMomentum, true)); // passes
125  BOOST_CHECK(discSurfaceObject->isOnSurface(tgContext, point3DOnSurface,
126  ignoredMomentum, true)); // passes
127  //
129  Vector3 returnedPosition{10.9, 8.7, 6.5};
130  Vector3 expectedPosition{1.2, 0, 0};
131  Vector2 rPhiOnDisc{1.2, 0.0};
132  Vector2 rPhiNotInSector{1.2, M_PI}; // outside sector at Phi=0, +/- pi/8
133  returnedPosition =
134  discSurfaceObject->localToGlobal(tgContext, rPhiOnDisc, ignoredMomentum);
135  CHECK_CLOSE_ABS(returnedPosition, expectedPosition, 1e-6);
136  //
137  returnedPosition = discSurfaceObject->localToGlobal(
138  tgContext, rPhiNotInSector, ignoredMomentum);
139  Vector3 expectedNonPosition{-1.2, 0, 0};
140  CHECK_CLOSE_ABS(returnedPosition, expectedNonPosition, 1e-6);
141  //
143  Vector2 returnedLocalPosition{33., 44.};
144  Vector2 expectedLocalPosition{1.2, 0.0};
145  returnedLocalPosition =
146  discSurfaceObject
147  ->globalToLocal(tgContext, point3DOnSurface, ignoredMomentum)
148  .value();
149  CHECK_CLOSE_ABS(returnedLocalPosition, expectedLocalPosition, 1e-6);
150 
151  // Global to local does not check inside bounds
152  returnedLocalPosition =
153  discSurfaceObject
154  ->globalToLocal(tgContext, point3DNotInSector, ignoredMomentum)
155  .value();
156  //
157  Vector3 pointOutsideR{0.0, 100., 0};
158  returnedLocalPosition =
159  discSurfaceObject
160  ->globalToLocal(tgContext, pointOutsideR, ignoredMomentum)
161  .value();
162  //
164  Vector2 rPhi1_1{std::sqrt(2.), M_PI / 4.};
165  Vector2 cartesian1_1{1., 1.};
166  CHECK_CLOSE_REL(discSurfaceObject->localPolarToCartesian(rPhi1_1),
167  cartesian1_1, 1e-6);
168  //
170  CHECK_CLOSE_REL(discSurfaceObject->localCartesianToPolar(cartesian1_1),
171  rPhi1_1, 1e-6);
172  //
174  CHECK_CLOSE_REL(discSurfaceObject->localPolarToLocalCartesian(rPhi1_1),
175  cartesian1_1, 1e-6);
176  //
178  Vector3 cartesian3D1_1{1., 1., 0.};
180  discSurfaceObject->localCartesianToGlobal(tgContext, cartesian1_1),
181  cartesian3D1_1, 1e-6);
182  //
185  discSurfaceObject->globalToLocalCartesian(tgContext, cartesian3D1_1),
186  cartesian1_1, 1e-6);
187  //
189  double projected3DMomentum = std::sqrt(3.) * 1.e6;
190  Vector3 momentum{projected3DMomentum, projected3DMomentum,
191  projected3DMomentum};
192  Vector3 ignoredPosition{1.1, 2.2, 3.3};
193  CHECK_CLOSE_REL(discSurfaceObject->pathCorrection(tgContext, ignoredPosition,
194  momentum.normalized()),
195  std::sqrt(3), 0.01);
196  //
198  Vector3 globalPosition{1.2, 0.0, -10.};
199  Vector3 direction{0., 0., 1.}; // must be normalised
200  Vector3 expected{1.2, 0.0, 0.0};
201 
202  // intersect is a struct of (Vector3) position, pathLength, distance and
203  // (bool) valid, it's contained in a Surface intersection
204  auto sfIntersection =
205  discSurfaceObject->intersect(tgContext, globalPosition, direction, false)
206  .closest();
207  Intersection3D expectedIntersect{Vector3{1.2, 0., 0.}, 10.,
208  Intersection3D::Status::reachable};
209  BOOST_CHECK(bool(sfIntersection));
210  CHECK_CLOSE_ABS(sfIntersection.position(), expectedIntersect.position(),
211  1e-9);
212  CHECK_CLOSE_ABS(sfIntersection.pathLength(), expectedIntersect.pathLength(),
213  1e-9);
214  BOOST_CHECK_EQUAL(sfIntersection.object(), discSurfaceObject.get());
215 
216  //
218  boost::test_tools::output_test_stream nameOuput;
219  nameOuput << discSurfaceObject->name();
220  BOOST_CHECK(nameOuput.is_equal("Acts::DiscSurface"));
221 }
222 //
224 BOOST_AUTO_TEST_CASE(DiscSurfaceAssignment) {
225  Vector3 origin3D{0, 0, 0};
226  double rMin(1.0), rMax(5.0), halfPhiSector(M_PI / 8.);
227  auto discSurfaceObject = Surface::makeShared<DiscSurface>(
228  Transform3::Identity(), rMin, rMax, halfPhiSector);
229  auto assignedDisc =
230  Surface::makeShared<DiscSurface>(Transform3::Identity(), 2.2, 4.4, 0.07);
231  //
232  BOOST_CHECK_NO_THROW(*assignedDisc = *discSurfaceObject);
233  BOOST_CHECK((*assignedDisc) == (*discSurfaceObject));
234 }
235 
237 BOOST_AUTO_TEST_CASE(DiscSurfaceExtent) {
238  double rMin(1.0), rMax(5.0);
239 
240  auto pDisc =
241  Surface::makeShared<DiscSurface>(Transform3::Identity(), 0., rMax);
242  auto pDiscExtent = pDisc->polyhedronRepresentation(tgContext, 1).extent();
243 
244  CHECK_CLOSE_ABS(0., pDiscExtent.min(binZ), s_onSurfaceTolerance);
245  CHECK_CLOSE_ABS(0., pDiscExtent.max(binZ), s_onSurfaceTolerance);
246  CHECK_CLOSE_ABS(0., pDiscExtent.min(binR), s_onSurfaceTolerance);
247  CHECK_CLOSE_ABS(rMax, pDiscExtent.max(binR), s_onSurfaceTolerance);
248  CHECK_CLOSE_ABS(-rMax, pDiscExtent.min(binX), s_onSurfaceTolerance);
249  CHECK_CLOSE_ABS(rMax, pDiscExtent.max(binX), s_onSurfaceTolerance);
250  CHECK_CLOSE_ABS(-rMax, pDiscExtent.min(binY), s_onSurfaceTolerance);
251  CHECK_CLOSE_ABS(rMax, pDiscExtent.max(binY), s_onSurfaceTolerance);
252  CHECK_CLOSE_ABS(-M_PI, pDiscExtent.min(binPhi), s_onSurfaceTolerance);
253  CHECK_CLOSE_ABS(M_PI, pDiscExtent.max(binPhi), s_onSurfaceTolerance);
254 
255  auto pRing =
256  Surface::makeShared<DiscSurface>(Transform3::Identity(), rMin, rMax);
257  auto pRingExtent = pRing->polyhedronRepresentation(tgContext, 1).extent();
258 
259  CHECK_CLOSE_ABS(0., pRingExtent.min(binZ), s_onSurfaceTolerance);
260  CHECK_CLOSE_ABS(0., pRingExtent.max(binZ), s_onSurfaceTolerance);
261  CHECK_CLOSE_ABS(rMin, pRingExtent.min(binR), s_onSurfaceTolerance);
262  CHECK_CLOSE_ABS(rMax, pRingExtent.max(binR), s_onSurfaceTolerance);
263  CHECK_CLOSE_ABS(-rMax, pRingExtent.min(binX), s_onSurfaceTolerance);
264  CHECK_CLOSE_ABS(rMax, pRingExtent.max(binX), s_onSurfaceTolerance);
265  CHECK_CLOSE_ABS(-rMax, pRingExtent.min(binY), s_onSurfaceTolerance);
266  CHECK_CLOSE_ABS(rMax, pRingExtent.max(binY), s_onSurfaceTolerance);
267 }
268 
270 BOOST_AUTO_TEST_CASE(DiscSurfaceAlignment) {
271  Translation3 translation{0., 1., 2.};
273  double rMin(1.0), rMax(5.0), halfPhiSector(M_PI / 8.);
274  auto discSurfaceObject =
275  Surface::makeShared<DiscSurface>(transform, rMin, rMax, halfPhiSector);
276 
277  const auto& rotation = transform.rotation();
278  // The local frame z axis
279  const Vector3 localZAxis = rotation.col(2);
280  // Check the local z axis is aligned to global z axis
281  CHECK_CLOSE_ABS(localZAxis, Vector3(0., 0., 1.), 1e-15);
282 
283  // Define the track (global) position and direction
284  Vector3 globalPosition{0, 4, 2};
285  Vector3 momentum{0, 0, 1};
286  Vector3 direction = momentum.normalized();
287  // Construct a free parameters
288  FreeVector parameters = FreeVector::Zero();
289  parameters.head<3>() = globalPosition;
290  parameters.segment<3>(eFreeDir0) = direction;
291 
292  // (a) Test the derivative of path length w.r.t. alignment parameters
293  const AlignmentToPathMatrix& alignToPath =
294  discSurfaceObject->alignmentToPathDerivative(tgContext, parameters);
295  // The expected results
296  AlignmentToPathMatrix expAlignToPath = AlignmentToPathMatrix::Zero();
297  expAlignToPath << 0, 0, 1, 3, 0, 0;
298  // Check if the calculated derivative is as expected
299  CHECK_CLOSE_ABS(alignToPath, expAlignToPath, 1e-10);
300 
301  // (b) Test the derivative of bound track parameters local position w.r.t.
302  // position in local 3D Cartesian coordinates
303  const auto& loc3DToLocBound =
304  discSurfaceObject->localCartesianToBoundLocalDerivative(tgContext,
305  globalPosition);
306  // Check if the result is as expected
307  ActsMatrix<2, 3> expLoc3DToLocBound = ActsMatrix<2, 3>::Zero();
308  expLoc3DToLocBound << 0, 1, 0, -1.0 / 3, 0, 0;
309  CHECK_CLOSE_ABS(loc3DToLocBound, expLoc3DToLocBound, 1e-10);
310 }
311 
312 BOOST_AUTO_TEST_CASE(DiscSurfaceBinningPosition) {
313  using namespace Acts::UnitLiterals;
314  Vector3 s{5_mm, 7_mm, 10_cm};
315  Transform3 trf;
316  trf = Translation3(s) * AngleAxis3{0.5, Vector3::UnitZ()};
317 
318  double minR = 300;
319  double maxR = 330;
320 
321  {
322  // Radial Bounds
323  auto bounds = std::make_shared<RadialBounds>(minR, maxR, M_PI / 8, 0.1);
324  auto disc = Acts::Surface::makeShared<Acts::DiscSurface>(trf, bounds);
325 
326  Vector3 bp = disc->binningPosition(tgContext, binR);
327  double r = (bounds->rMax() + bounds->rMin()) / 2.0;
328  double phi = bounds->get(RadialBounds::eAveragePhi);
329  Vector3 exp = Vector3{r * std::cos(phi), r * std::sin(phi), 0};
330  exp = trf * exp;
331 
332  BOOST_CHECK_EQUAL(bp, exp);
333  BOOST_CHECK_EQUAL(disc->binningPositionValue(tgContext, binR),
334  VectorHelpers::perp(exp));
335 
336  bp = disc->binningPosition(tgContext, binPhi);
337  BOOST_CHECK_EQUAL(bp, exp);
338  BOOST_CHECK_EQUAL(disc->binningPositionValue(tgContext, binPhi),
339  VectorHelpers::phi(exp));
340 
341  for (auto b : {binX, binY, binZ, binEta, binRPhi, binH, binMag}) {
342  BOOST_TEST_CONTEXT("binValue: " << b) {
343  BOOST_CHECK_EQUAL(disc->binningPosition(tgContext, b),
344  disc->center(tgContext));
345  }
346  }
347  }
348 
349  {
350  // Annulus Bounds
351  double minPhiRel = -0.3;
352  double maxPhiRel = 0.2;
353  Vector2 origin{5_mm, 5_mm};
354  auto bounds = std::make_shared<AnnulusBounds>(minR, maxR, minPhiRel,
355  maxPhiRel, origin);
356 
357  auto disc = Acts::Surface::makeShared<Acts::DiscSurface>(trf, bounds);
358 
359  Vector3 bp = disc->binningPosition(tgContext, binR);
360  double r = (bounds->rMax() + bounds->rMin()) / 2.0;
361  double phi = bounds->get(AnnulusBounds::eAveragePhi);
362  Vector3 exp = Vector3{r * std::cos(phi), r * std::sin(phi), 0};
363  exp = trf * exp;
364 
365  BOOST_CHECK_EQUAL(bp, exp);
366 
367  bp = disc->binningPosition(tgContext, binPhi);
368  BOOST_CHECK_EQUAL(bp, exp);
369 
370  for (auto b : {binX, binY, binZ, binEta, binRPhi, binH, binMag}) {
371  BOOST_TEST_CONTEXT("binValue: " << b) {
372  BOOST_CHECK_EQUAL(disc->binningPosition(tgContext, b),
373  disc->center(tgContext));
374  }
375  }
376  }
377 }
378 
379 BOOST_AUTO_TEST_SUITE_END()
380 
381 } // namespace Test
382 
383 } // namespace Acts