Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DetectorVolumeTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file DetectorVolumeTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022 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/unit_test.hpp>
10 
13 #include "Acts/Detector/Portal.hpp"
17 #include "Acts/Geometry/Extent.hpp"
27 
28 #include <cstddef>
29 #include <memory>
30 #include <stdexcept>
31 #include <utility>
32 #include <vector>
33 
41 template <typename referenced_type>
42 std::shared_ptr<referenced_type> unpackToShared(referenced_type& rt) {
43  return rt.getSharedPtr();
44 }
45 
46 using namespace Acts::Experimental;
47 
49 
50 BOOST_AUTO_TEST_SUITE(Detector)
51 
52 BOOST_AUTO_TEST_CASE(CylindricalDetectorVolumePortals) {
53  Acts::ActsScalar rInner = 10.;
54  Acts::ActsScalar rOuter = 100.;
55  Acts::ActsScalar zHalfL = 200.;
56 
57  Acts::Transform3 nominal = Acts::Transform3::Identity();
58 
59  auto fullCylinderBounds =
60  std::make_unique<Acts::CylinderVolumeBounds>(0., rOuter, zHalfL);
61 
63 
64  // Misconfigured - null pointer for bounds
65  BOOST_CHECK_THROW(
67  "MisconfiguredFullCylinderVolume",
68  nominal, nullptr, tryAllPortals()),
69  std::invalid_argument);
70 
71  // Misconfigured - portal generator not connected
72  PortalGenerator unconnected;
73  BOOST_CHECK_THROW(
75  "MisconfiguredFullCylinderVolume",
76  nominal, nullptr, tryAllPortals()),
77  std::invalid_argument);
78 
79  // A full cylinder
80  auto fullCylinderVolume = DetectorVolumeFactory::construct(
81  portalGenerator, tContext, "FullCylinderVolume", nominal,
82  std::move(fullCylinderBounds), tryAllPortals());
83 
84  BOOST_CHECK(fullCylinderVolume ==
85  unpackToShared<DetectorVolume>(*fullCylinderVolume));
86  BOOST_CHECK(fullCylinderVolume ==
87  unpackToShared<const DetectorVolume>(*fullCylinderVolume));
88 
89  BOOST_CHECK(fullCylinderVolume->surfaces().empty());
90  BOOST_CHECK(fullCylinderVolume->volumes().empty());
91  BOOST_CHECK(fullCylinderVolume->portals().size() == 3u);
92 
93  // A tube cylinder
94  auto tubeCylinderBounds =
95  std::make_unique<Acts::CylinderVolumeBounds>(rInner, rOuter, zHalfL);
96 
97  auto tubeCylinderVolume = DetectorVolumeFactory::construct(
98  portalGenerator, tContext, "TubeCylinderVolume", nominal,
99  std::move(tubeCylinderBounds), tryAllPortals());
100 
101  BOOST_CHECK(tubeCylinderVolume->surfaces().empty());
102  BOOST_CHECK(tubeCylinderVolume->volumes().empty());
103  BOOST_CHECK(tubeCylinderVolume->portals().size() == 4u);
104 
105  // Let's test the resizing, first inside test: OK
106  BOOST_CHECK(tubeCylinderVolume->inside(tContext, Acts::Vector3(50., 0., 0.)));
107  // Outside
108  BOOST_CHECK(
109  not tubeCylinderVolume->inside(tContext, Acts::Vector3(150., 0., 0.)));
110 
111  // Check the extent
112  auto volumeExtent = tubeCylinderVolume->extent(tContext, 1);
113  CHECK_CLOSE_ABS(volumeExtent.min(Acts::binR), 10., 10e-5);
114  CHECK_CLOSE_ABS(volumeExtent.max(Acts::binR), 100., 10e-5);
115  CHECK_CLOSE_ABS(volumeExtent.min(Acts::binZ), -200., 10e-5);
116  CHECK_CLOSE_ABS(volumeExtent.max(Acts::binZ), 200., 10e-5);
117 }
118 
119 BOOST_AUTO_TEST_CASE(UpdatePortal) {
120  Acts::Transform3 nominal = Acts::Transform3::Identity();
121 
122  auto fullCylinderBounds =
123  std::make_unique<Acts::CylinderVolumeBounds>(0., 10., 100.);
124 
126 
127  auto fullCylinderVolume = DetectorVolumeFactory::construct(
128  portalGenerator, tContext, "FullCylinderVolume", nominal,
129  std::move(fullCylinderBounds), tryAllPortals());
130 
131  auto cylinderSurface =
132  Acts::Surface::makeShared<Acts::CylinderSurface>(nominal, 10., 100.);
133 
134  auto cylinderPortal = Acts::Experimental::Portal::makeShared(cylinderSurface);
135 
136  fullCylinderVolume->updatePortal(cylinderPortal, 2u);
137 
138  BOOST_CHECK(fullCylinderVolume->portals()[2u] == cylinderPortal.get());
139 }
140 
141 BOOST_AUTO_TEST_CASE(CuboidWithCuboid) {
142  Acts::ActsScalar bigBox = 100.;
143  Acts::ActsScalar smallBox = 10.;
144 
145  Acts::Transform3 nominal = Acts::Transform3::Identity();
146 
147  auto bigBoxBounds =
148  std::make_unique<Acts::CuboidVolumeBounds>(bigBox, bigBox, bigBox);
149 
150  auto smallBoxBounds =
151  std::make_unique<Acts::CuboidVolumeBounds>(smallBox, smallBox, smallBox);
152 
153  auto portals = defaultPortalGenerator();
155 
156  // Create the inner box
157  auto innerBox = DetectorVolumeFactory::construct(
158  portals, tContext, "InnerBox", nominal, std::move(smallBoxBounds),
159  tryAllPortals());
160 
161  std::vector<std::shared_ptr<Acts::Surface>> surfaces = {};
162  std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>> volumes = {
163  innerBox};
164 
165  // Create the outer box and insert the inner box, use a portal generator
166  // with sub portal registration
167  auto outerBox = DetectorVolumeFactory::construct(
168  generatePortalsUpdateInternals, tContext, "OuterBox", nominal,
169  std::move(bigBoxBounds), surfaces, volumes, tryAllSubVolumes(),
170  tryAllPortals());
171 
172  // Check that we are within the outer box
174  nState.position = Acts::Vector3(-50., 5., 0.);
175  nState.direction = Acts::Vector3(1., 0., 0.);
176 
177  BOOST_CHECK(outerBox->inside(tContext, nState.position));
178  nState.currentVolume = outerBox.get();
179 
180  outerBox->updateNavigationState(tContext, nState);
181 
182  // We should have 12 candidates, 6 inner, 6 outer portals
183  BOOST_CHECK(nState.surfaceCandidates.size() == 12u);
184 }
185 
186 BOOST_AUTO_TEST_CASE(CylinderWithSurfacesTestExtractors) {
188 
189  std::vector<Acts::ActsScalar> radii = {100, 102, 104, 106, 108, 110};
190  auto cylinderVoumeBounds =
191  std::make_unique<Acts::CylinderVolumeBounds>(80, 130, 200);
192  std::vector<std::shared_ptr<Acts::Surface>> surfaces = {};
193  for (const auto& r : radii) {
194  surfaces.push_back(Acts::Surface::makeShared<Acts::CylinderSurface>(
195  Acts::Transform3::Identity(),
196  std::make_shared<Acts::CylinderBounds>(r, 190)));
197  }
198 
199  // A full cylinder
200  auto cylinderVolume = DetectorVolumeFactory::construct(
201  portalGenerator, tContext, "CylinderVolume", Acts::Transform3::Identity(),
202  std::move(cylinderVoumeBounds), surfaces, {}, tryNoVolumes(),
204 
205  // The navigation state
207  AllPortalsExtractor allPortals;
208  AllSurfacesExtractor allSurfaces;
209  IndexedSurfacesExtractor indexedSurfaces;
210 
211  // First check exception behaviour
212  BOOST_CHECK_THROW(allPortals.extract(tContext, nState), std::runtime_error);
213  BOOST_CHECK_THROW(allSurfaces.extract(tContext, nState), std::runtime_error);
214  BOOST_CHECK_THROW(indexedSurfaces.extract(tContext, nState, {0u, 1u}),
215  std::runtime_error);
216 
217  // A volume needs to be set
218  nState.currentVolume = cylinderVolume.get();
219 
220  // This extracts all portals as candidates
221  auto eportals = allPortals.extract(tContext, nState);
222  BOOST_CHECK(eportals.size() == 4u);
223 
224  auto esurfaces = allSurfaces.extract(tContext, nState);
225  BOOST_CHECK(esurfaces.size() == 6u);
226 
227  esurfaces = indexedSurfaces.extract(tContext, nState, {2u, 4u});
228  BOOST_CHECK(esurfaces.size() == 2u);
229  BOOST_CHECK(esurfaces[0u] == surfaces[2u].get());
230  BOOST_CHECK(esurfaces[1u] == surfaces[4u].get());
231 }
232 
233 BOOST_AUTO_TEST_SUITE_END()