Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CylindricalDetectorHelperTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CylindricalDetectorHelperTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2023 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 
25 
26 #include <algorithm>
27 #include <array>
28 #include <cmath>
29 #include <iterator>
30 #include <map>
31 #include <memory>
32 #include <ostream>
33 #include <stdexcept>
34 #include <string>
35 #include <utility>
36 #include <vector>
37 
38 namespace Acts {
39 namespace Experimental {
40 class Portal;
41 } // namespace Experimental
42 } // namespace Acts
43 
44 using namespace Acts;
45 using namespace Experimental;
46 using namespace Experimental::detail;
47 using namespace Experimental::detail::CylindricalDetectorHelper;
48 
50 
52 std::vector<std::shared_ptr<DetectorVolume>> eVolumes = {};
53 
55 
56 BOOST_AUTO_TEST_SUITE(Experimental)
57 
58 BOOST_AUTO_TEST_CASE(ConnectVolumeExceptions) {
59  ACTS_LOCAL_LOGGER(getDefaultLogger("Faulty setups", logLevel));
60 
61  auto cBounds0 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
62  auto volume0 = DetectorVolumeFactory::construct(
63  portalGenerator, tContext, "Volume0", Transform3::Identity(),
64  std::move(cBounds0), tryAllPortals());
65 
66  auto cBounds1 =
67  std::make_unique<CylinderVolumeBounds>(0., 100., 100, 0.2, 1.);
68  auto volume1 = DetectorVolumeFactory::construct(
69  portalGenerator, tContext, "Volume0", Transform3::Identity(),
70  std::move(cBounds1), tryAllPortals());
71 
72  ACTS_INFO("*** Test: nullptr in the list of volumes");
73 
74  // Invalid arguments: nullptr
75  std::vector<std::shared_ptr<DetectorVolume>> volumesWithNullptr = {
76  volume0, nullptr, volume1};
77  BOOST_CHECK_THROW(connectInR(tContext, volumesWithNullptr, {}, logLevel),
78  std::invalid_argument);
79 
80  ACTS_INFO("*** Test: non-cylinder in the list of volumes");
81 
82  auto cubeBounds = std::make_unique<CuboidVolumeBounds>(100., 100., 100);
84  portalGenerator, tContext, "Cube", Transform3::Identity(),
85  std::move(cubeBounds), tryAllPortals());
86 
87  // Invalid arguments: cube
88  std::vector<std::shared_ptr<DetectorVolume>> volumesWithCube = {
89  volume0, volume1, cube};
90  BOOST_CHECK_THROW(connectInR(tContext, volumesWithCube, {}, logLevel),
91  std::invalid_argument);
92 
93  ACTS_INFO("*** Test: non-aligned volume in the list of volumes");
94  Transform3 rotated = Transform3::Identity();
95  AngleAxis3 rotX(0.1234, Vector3::UnitX());
96  rotated *= rotX;
97 
98  auto cBounds2 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
99  auto volume2 = DetectorVolumeFactory::construct(
100  portalGenerator, tContext, "Volume2", rotated, std::move(cBounds2),
101  tryAllPortals());
102 
103  // Invalid arguments: non-aligned
104  std::vector<std::shared_ptr<DetectorVolume>> volumesWithNonaligned = {
105  volume0, volume1, volume2};
106  BOOST_CHECK_THROW(connectInR(tContext, volumesWithNonaligned, {}, logLevel),
107  std::invalid_argument);
108 }
109 
110 BOOST_AUTO_TEST_CASE(ConnectInR) {
112  ACTS_INFO("*** Test: connect DetectorVolumes in R, create proto container");
113  // Test with different opening angles
114  std::vector<ActsScalar> testOpenings = {M_PI, 0.5 * M_PI};
115 
116  std::vector<ActsScalar> radii = {0., 10., 100., 200.};
117  ActsScalar halfZ = 100.;
118 
119  // This should work for full cylinder and sector openings
120  for (auto [io, opening] : enumerate(testOpenings)) {
121  ACTS_INFO(" -> test with phi opening: " << opening);
122  std::string opStr = "opening_" + std::to_string(io);
123  std::vector<std::shared_ptr<DetectorVolume>> rVolumes = {};
124  // Create the voluems
125  for (auto [i, r] : enumerate(radii)) {
126  if (i > 0) {
127  auto cBounds = std::make_unique<CylinderVolumeBounds>(
128  radii[i - 1u], r, halfZ, opening, 0.);
129  rVolumes.push_back(DetectorVolumeFactory::construct(
130  portalGenerator, tContext, "Cylinder_r" + std::to_string(i),
131  Transform3::Identity(), std::move(cBounds), tryAllPortals()));
132  }
133  }
134 
135  auto protoContainer = connectInR(tContext, rVolumes, {}, logLevel);
136  // Check the portal setup
137  BOOST_CHECK(rVolumes[0u]->portalPtrs()[2u] ==
138  rVolumes[1u]->portalPtrs()[3u]);
139  BOOST_CHECK(rVolumes[1u]->portalPtrs()[2u] ==
140  rVolumes[2u]->portalPtrs()[3u]);
141  BOOST_CHECK(rVolumes[0u]->portalPtrs()[0u] ==
142  rVolumes[1u]->portalPtrs()[0u]);
143  BOOST_CHECK(rVolumes[1u]->portalPtrs()[0u] ==
144  rVolumes[2u]->portalPtrs()[0u]);
145  BOOST_CHECK(rVolumes[0u]->portalPtrs()[1u] ==
146  rVolumes[1u]->portalPtrs()[1u]);
147  BOOST_CHECK(rVolumes[1u]->portalPtrs()[1u] ==
148  rVolumes[2u]->portalPtrs()[1u]);
149  BOOST_CHECK(rVolumes[0u]->portalPtrs()[0u] == protoContainer[0u]);
150  BOOST_CHECK(rVolumes[0u]->portalPtrs()[1u] == protoContainer[1u]);
151 
152  // A detector construction that should work
153  auto detector =
154  Detector::makeShared("DetectorInR", rVolumes, tryRootVolumes());
155 
156  // Make a rzphi grid
157  const auto& volumes = detector->volumes();
158  auto boundaries = rzphiBoundaries(tContext, volumes);
159  const auto& rBoundaries = boundaries[0u];
160  const auto& zBoundaries = boundaries[1u];
161 
162  // Check the radii
163  std::vector<ActsScalar> zvalues = {-halfZ, halfZ};
164  BOOST_CHECK(radii == rBoundaries);
165  BOOST_CHECK(zvalues == zBoundaries);
166  }
167 
168  // Invalid arguments
169  ACTS_INFO("*** Test: faulty empty vector");
170  BOOST_CHECK_THROW(connectInR(tContext, eVolumes, {}, logLevel),
171  std::invalid_argument);
172 
173  // Faulty setups, not matchint in R
174  ACTS_INFO("*** Test: volumes are not matching in R");
175 
176  auto cBounds00 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
177  auto volume00 = DetectorVolumeFactory::construct(
178  portalGenerator, tContext, "Volume00", Transform3::Identity(),
179  std::move(cBounds00), tryAllPortals());
180 
181  auto cBounds01 = std::make_unique<CylinderVolumeBounds>(101., 200., 100);
182  auto volume01 = DetectorVolumeFactory::construct(
183  portalGenerator, tContext, "Volume01", Transform3::Identity(),
184  std::move(cBounds01), tryAllPortals());
185 
186  std::vector<std::shared_ptr<DetectorVolume>> volumesNotMatching = {volume00,
187  volume01};
188  BOOST_CHECK_THROW(connectInR(tContext, volumesNotMatching, {}, logLevel),
189  std::runtime_error);
190 
191  ACTS_INFO("*** Test: volume bounds are not aligned");
192  Transform3 shifted = Transform3::Identity();
193  shifted.pretranslate(Vector3(0., 0., 10.));
194 
195  auto cBounds10 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
196  auto volume10 = DetectorVolumeFactory::construct(
197  portalGenerator, tContext, "Volume10", shifted, std::move(cBounds10),
198  tryAllPortals());
199 
200  auto cBounds11 = std::make_unique<CylinderVolumeBounds>(100., 200., 90);
201  auto volume11 = DetectorVolumeFactory::construct(
202  portalGenerator, tContext, "Volume11", shifted, std::move(cBounds11),
203  tryAllPortals());
204 
205  std::vector<std::shared_ptr<DetectorVolume>> volumesNotAligned = {volume10,
206  volume11};
207  BOOST_CHECK_THROW(connectInR(tContext, volumesNotAligned, {}, logLevel),
208  std::runtime_error);
209 }
210 
211 BOOST_AUTO_TEST_CASE(ConnectInZ) {
213  ACTS_INFO("*** Test: connect DetectorVolumes in Z, create proto container");
214 
215  // @TODO: test with different transforms, this should work in, not used yet
216  std::vector<Transform3> transforms = {Transform3::Identity()};
217  std::vector<std::array<ActsScalar, 2>> radii = {{0., 100.}, {20., 120.}};
218  std::vector<ActsScalar> zValues = {-100., -20, 10., 100., 200.};
219 
220  for (auto [it, t] : enumerate(transforms)) {
221  ACTS_INFO(" -> test series with transform id " << it);
222 
223  std::string trfStr = "_transform_" + std::to_string(it);
224  for (auto [ir, r] : enumerate(radii)) {
225  ACTS_INFO(" -> test series with radii setup "
226  << radii[ir][0u] << ", " << radii[ir][1u]);
227 
228  std::string radStr = "_radii_" + std::to_string(ir);
229  std::vector<std::shared_ptr<DetectorVolume>> zVolumes = {};
230  for (auto [i, z] : enumerate(zValues)) {
231  if (i > 0) {
232  auto cBounds = std::make_unique<CylinderVolumeBounds>(
233  r[0], r[1], 0.5 * (z - zValues[i - 1u]));
234  // z center
235  ActsScalar zCenter = 0.5 * (z + zValues[i - 1u]);
236  Transform3 ti = Transform3::Identity();
237  ti.pretranslate(t.translation() +
238  zCenter * t.rotation().matrix().col(2));
239  ti.prerotate(t.rotation());
240  // create the volume
241  zVolumes.push_back(DetectorVolumeFactory::construct(
243  "Cylinder_z" + std::to_string(i) + trfStr + radStr, ti,
244  std::move(cBounds), tryAllPortals()));
245  }
246  }
247  // Now call the connector
248  auto protoContainer = connectInZ(tContext, zVolumes, {}, logLevel);
249 
250  // Check the portal setup.
251  // Glued, remainders are outside skin
252  BOOST_CHECK(zVolumes[0u]->portalPtrs()[1u] ==
253  zVolumes[1u]->portalPtrs()[0u]);
254  BOOST_CHECK(zVolumes[1u]->portalPtrs()[1u] ==
255  zVolumes[2u]->portalPtrs()[0u]);
256  BOOST_CHECK(zVolumes[2u]->portalPtrs()[1u] ==
257  zVolumes[3u]->portalPtrs()[0u]);
258  BOOST_CHECK(protoContainer[0u] == zVolumes[0u]->portalPtrs()[0u]);
259  BOOST_CHECK(protoContainer[1u] == zVolumes[3u]->portalPtrs()[1u]);
260 
261  // Covered with the same surface, shich is the outside skin
262  std::vector<unsigned int> checkShared = {2u};
263  if (radii[ir][0u] > 0.) {
264  checkShared.push_back(3u);
265  }
266 
267  for (const auto& ip : checkShared) {
268  BOOST_CHECK(zVolumes[0u]->portalPtrs()[ip] ==
269  zVolumes[1u]->portalPtrs()[ip]);
270  BOOST_CHECK(zVolumes[1u]->portalPtrs()[ip] ==
271  zVolumes[2u]->portalPtrs()[ip]);
272  BOOST_CHECK(zVolumes[2u]->portalPtrs()[ip] ==
273  zVolumes[3u]->portalPtrs()[ip]);
274  BOOST_CHECK(protoContainer[ip] == zVolumes[0u]->portalPtrs()[ip]);
275  }
276 
277  auto detector =
278  Detector::makeShared("DetectorInZ", zVolumes, tryRootVolumes());
279  }
280  }
281 
282  // Invalid arguments
283  BOOST_CHECK_THROW(connectInZ(tContext, eVolumes, {}, logLevel),
284  std::invalid_argument);
285 
286  // Volumes have different radii - other bounds will be the same
287  auto cBounds00 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
288  auto volume00 = DetectorVolumeFactory::construct(
289  portalGenerator, tContext, "Volume00",
290  Transform3::Identity() * Translation3(0., 0., -100.),
291  std::move(cBounds00), tryAllPortals());
292 
293  auto cBounds01 = std::make_unique<CylinderVolumeBounds>(0., 105., 100);
294  auto volume01 = DetectorVolumeFactory::construct(
295  portalGenerator, tContext, "Volume01",
296  Transform3::Identity() * Translation3(0., 0., 100.), std::move(cBounds01),
297  tryAllPortals());
298 
299  std::vector<std::shared_ptr<DetectorVolume>> volumesNonalignedBounds = {
300  volume00, volume01};
301  BOOST_CHECK_THROW(connectInZ(tContext, volumesNonalignedBounds, {}, logLevel),
302  std::runtime_error);
303 
304  // Volumes are not attached
305  auto cBounds10 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
306  auto volume10 = DetectorVolumeFactory::construct(
307  portalGenerator, tContext, "Volume00",
308  Transform3::Identity() * Translation3(0., 0., -105.),
309  std::move(cBounds10), tryAllPortals());
310 
311  auto cBounds11 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
312  auto volume11 = DetectorVolumeFactory::construct(
313  portalGenerator, tContext, "Volume01",
314  Transform3::Identity() * Translation3(0., 0., 100.), std::move(cBounds11),
315  tryAllPortals());
316 
317  std::vector<std::shared_ptr<DetectorVolume>> volumesNotAttached = {volume10,
318  volume11};
319  BOOST_CHECK_THROW(connectInZ(tContext, volumesNotAttached, {}, logLevel),
320  std::runtime_error);
321 }
322 
323 BOOST_AUTO_TEST_CASE(ConnectInPhi) {
324  ACTS_LOCAL_LOGGER(getDefaultLogger("Connect: Phi", logLevel));
325  ACTS_INFO("*** Test: connect DetectorVolumes in Phi, create proto container");
326 
327  std::vector<Transform3> transforms = {Transform3::Identity()};
328  unsigned int phiSectors = 5;
329  ActsScalar phiHalfSector = M_PI / phiSectors;
330 
331  for (auto [it, t] : enumerate(transforms)) {
332  ACTS_INFO(" -> test series with transform id " << it);
333 
334  std::vector<std::shared_ptr<DetectorVolume>> phiVolumes = {};
335  for (unsigned int i = 0; i < phiSectors; ++i) {
336  auto cBounds = std::make_unique<CylinderVolumeBounds>(
337  10., 100., 100., phiHalfSector,
338  -M_PI + (2u * i + 1u) * phiHalfSector);
339 
340  // create the volume
341  phiVolumes.push_back(DetectorVolumeFactory::construct(
342  portalGenerator, tContext, "Cylinder_phi" + std::to_string(i), t,
343  std::move(cBounds), tryAllPortals()));
344  }
345 
346  auto protoContainer = connectInPhi(tContext, phiVolumes, {}, logLevel);
347 
348  // All phiVolumes share : inner tube, outer cover, negative & positive disc
349  std::vector<unsigned int> checkShared = {0u, 1u, 2u, 3u};
350  for (auto [iv, v] : enumerate(phiVolumes)) {
351  if (iv > 0u) {
352  auto current = v;
353  auto last = phiVolumes[iv - 1u];
354  for (const auto& ch : checkShared) {
355  BOOST_CHECK(current->portalPtrs()[ch] == last->portalPtrs()[ch]);
356  }
357  }
358  }
359 
360  auto detector =
361  Detector::makeShared("DetectorInPhi", phiVolumes, tryRootVolumes());
362  }
363 
364  // Invalid arguments
365  BOOST_CHECK_THROW(connectInPhi(tContext, eVolumes, {}, logLevel),
366  std::invalid_argument);
367 }
368 
369 BOOST_AUTO_TEST_CASE(WrapVolumeinRZ) {
371  ACTS_INFO(
372  "*** Test: wrap volume in Z-R with CutoutCylinderVolume, create proto "
373  "container");
374 
375  // @TODO: test with different transforms, this should work in, not used yet
376  std::vector<Transform3> transforms = {Transform3::Identity()};
377 
378  // Test with different inner radii
379  std::vector<std::array<ActsScalar, 3u>> radii = {{0., 100., 500.},
380  {20., 120., 500.}};
381 
382  ActsScalar innerHalfZ = 150.;
383  ActsScalar outerHalfZ = 175.;
384 
385  // Set up all the different tests
386  for (auto [it, tf] : enumerate(transforms)) {
387  ACTS_INFO(" Test series with transform id " << it);
388 
389  std::string trfStr = "_transform_" + std::to_string(it);
390  for (auto [ir, r] : enumerate(radii)) {
391  ACTS_INFO(" -> test series with radii setup " << radii[ir][0u] << ", "
392  << radii[ir][1u]);
393 
394  std::vector<std::shared_ptr<DetectorVolume>> volumes = {};
395 
396  std::string radStr = "_radii_" + std::to_string(ir);
397  // Create the inner bounds
398  auto iBounds = std::make_unique<CylinderVolumeBounds>(
399  radii[ir][0u], radii[ir][1u], innerHalfZ);
400  volumes.push_back(DetectorVolumeFactory::construct(
401  portalGenerator, tContext, "InnerCylinder" + radStr + trfStr, tf,
402  std::move(iBounds), tryAllPortals()));
403 
404  // Create the wrapping bounds
405  auto wBounds = std::make_unique<CutoutCylinderVolumeBounds>(
406  radii[ir][0u], radii[ir][1u], radii[ir][2u], outerHalfZ, innerHalfZ);
407 
408  volumes.push_back(DetectorVolumeFactory::construct(
409  portalGenerator, tContext, "WrappingCylinder" + radStr + trfStr, tf,
410  std::move(wBounds), tryAllPortals()));
411 
412  wrapInZR(tContext, volumes, logLevel);
413  }
414  }
415 
416  // Invalid arguments
417  BOOST_CHECK_THROW(wrapInZR(tContext, eVolumes, logLevel),
418  std::invalid_argument);
419 }
420 
421 BOOST_AUTO_TEST_CASE(ProtoContainerZR) {
422  ACTS_LOCAL_LOGGER(getDefaultLogger("Container: Z-R", logLevel));
423  ACTS_INFO("*** Test: create a container in Z-R.");
424 
425  auto transform = Transform3::Identity();
426 
427  std::vector<ActsScalar> innerMostRadii = {0., 2.};
428 
429  for (auto [ir, imr] : enumerate(innerMostRadii)) {
430  ACTS_INFO(" -> test series innermost radius setup "
431  << innerMostRadii[ir]);
432 
433  // A container in R
434  std::vector<ActsScalar> radii = {25., 100., 200.};
435  ActsScalar halfZ = 200;
436 
437  // An innermost Pipe
438  auto bBounds =
439  std::make_unique<CylinderVolumeBounds>(imr, radii[0u], halfZ);
440 
441  auto innerPipe = DetectorVolumeFactory::construct(
442  portalGenerator, tContext, "InnerPipe", transform, std::move(bBounds),
443  tryAllPortals());
444 
445  // Make a container representation out of it
446  std::map<unsigned int, std::shared_ptr<Portal>> ipContainer;
447  for (auto [ip, p] : enumerate(innerPipe->portalPtrs())) {
448  ipContainer[ip] = p;
449  }
450 
451  // Create the r - sorted volumes
452  std::vector<std::shared_ptr<DetectorVolume>> rVolumes = {};
453  // Create the voluems
454  for (auto [i, r] : enumerate(radii)) {
455  if (i > 0) {
456  auto cBounds =
457  std::make_unique<CylinderVolumeBounds>(radii[i - 1u], r, halfZ);
458  rVolumes.push_back(DetectorVolumeFactory::construct(
459  portalGenerator, tContext, "Cylinder_r" + std::to_string(i),
460  transform, std::move(cBounds), tryAllPortals()));
461  }
462  }
463 
464  auto protoContainerInR = connectInR(tContext, rVolumes, {}, logLevel);
465 
466  std::vector<ActsScalar> zValues = {-200., -120, 10., 100., 200.};
467  std::vector<std::shared_ptr<DetectorVolume>> zVolumes = {};
468  for (auto [i, z] : enumerate(zValues)) {
469  if (i > 0) {
470  auto cBounds = std::make_unique<CylinderVolumeBounds>(
471  200., 300., 0.5 * (z - zValues[i - 1u]));
472  // z center
473  ActsScalar zCenter = 0.5 * (z + zValues[i - 1u]);
474  Transform3 ti = transform;
475  ti.pretranslate(transform.translation() +
476  zCenter * transform.rotation().matrix().col(2));
477 
478  // create the volume
479  zVolumes.push_back(DetectorVolumeFactory::construct(
480  portalGenerator, tContext, "Cylinder_z" + std::to_string(i), ti,
481  std::move(cBounds), tryAllPortals()));
482  }
483  }
484  // Now call the connector
485  auto protoContainerInZ = connectInZ(tContext, zVolumes, {}, logLevel);
486  auto centralContainer = connectInR(
487  tContext, {ipContainer, protoContainerInR, protoContainerInZ}, {},
488  logLevel);
489 
490  // Let's make two endcaps
491  // Nec
492  auto necBounds = std::make_unique<CylinderVolumeBounds>(imr, 300., 50.);
493 
494  auto necTransform = Transform3::Identity();
495  necTransform.pretranslate(Vector3(0., 0., -250));
496  auto necVolume = DetectorVolumeFactory::construct(
497  portalGenerator, tContext, "Nec", necTransform, std::move(necBounds),
498  tryAllPortals());
499 
500  std::map<unsigned int, std::shared_ptr<Portal>> necContainer;
501  for (auto [ip, p] : enumerate(necVolume->portalPtrs())) {
502  necContainer[ip] = p;
503  }
504 
505  // Pec container
506  auto pecInnerBounds =
507  std::make_unique<CylinderVolumeBounds>(imr, 175., 100.);
508 
509  auto pecOuterBounds =
510  std::make_unique<CylinderVolumeBounds>(175., 300., 100.);
511 
512  auto pecTransform = Transform3::Identity();
513  pecTransform.pretranslate(Vector3(0., 0., 300));
514  auto pecInner = DetectorVolumeFactory::construct(
515  portalGenerator, tContext, "PecInner", pecTransform,
516  std::move(pecInnerBounds), tryAllPortals());
517  auto pecOuter = DetectorVolumeFactory::construct(
518  portalGenerator, tContext, "PecOuter", pecTransform,
519  std::move(pecOuterBounds), tryAllPortals());
520 
521  std::vector<std::shared_ptr<DetectorVolume>> pecVolumes = {pecInner,
522  pecOuter};
523  auto pecContainer = connectInR(tContext, pecVolumes, {}, logLevel);
524 
525  auto overallContainer = connectInZ(
526  tContext, {necContainer, centralContainer, pecContainer}, {}, logLevel);
527 
528  // Add them together
529  std::vector<std::shared_ptr<DetectorVolume>> dVolumes;
530  dVolumes.push_back(innerPipe);
531  dVolumes.push_back(necVolume);
532  dVolumes.insert(dVolumes.end(), rVolumes.begin(), rVolumes.end());
533  dVolumes.insert(dVolumes.end(), zVolumes.begin(), zVolumes.end());
534  dVolumes.push_back(pecInner);
535  dVolumes.push_back(pecOuter);
536 
537  auto detector = Detector::makeShared("DetectorFromProtoContainer", dVolumes,
538  tryRootVolumes());
539  } // test with different innermost radii
540 }
541 
542 BOOST_AUTO_TEST_CASE(WrapContainernRZ) {
543  ACTS_LOCAL_LOGGER(getDefaultLogger("Container: Wrap", logLevel));
544  ACTS_INFO("*** Test: create a container in Z-R by wrapping.");
545 
546  // Test with different inner radii
547  std::vector<std::array<ActsScalar, 3u>> radii = {{0., 100., 500.},
548  {20., 120., 500.}};
549 
550  ActsScalar innerHalfZ = 150.;
551  ActsScalar innerBarrelHalfZ = 75.;
552  ActsScalar innerEndcapHalfZ = 0.5 * (innerHalfZ - innerBarrelHalfZ);
553  ActsScalar outerHalfZ = 175.;
554 
555  Transform3 tf = Transform3::Identity();
556 
557  // Set up all the different tests
558  for (auto [ir, r] : enumerate(radii)) {
559  std::string radStr = "_radii_" + std::to_string(ir);
560  ACTS_INFO(" -> test series innermost radius setup " << radii[ir][0u]);
561 
562  // Let's create the inner container first
563  std::vector<std::shared_ptr<DetectorVolume>> iVolumes = {};
564 
565  auto iNecBounds = std::make_unique<CylinderVolumeBounds>(
566  radii[ir][0u], radii[ir][1u], innerEndcapHalfZ);
567  Transform3 ntf = tf;
568  ntf.pretranslate(Vector3(0., 0., -innerBarrelHalfZ - innerEndcapHalfZ));
569  iVolumes.push_back(DetectorVolumeFactory::construct(
570  portalGenerator, tContext, "InnerNec" + radStr, ntf,
571  std::move(iNecBounds), tryAllPortals()));
572 
573  auto iBarrelBounds = std::make_unique<CylinderVolumeBounds>(
574  radii[ir][0u], radii[ir][1u], innerBarrelHalfZ);
575  iVolumes.push_back(DetectorVolumeFactory::construct(
576  portalGenerator, tContext, "InnerBarrel" + radStr, tf,
577  std::move(iBarrelBounds), tryAllPortals()));
578 
579  auto iPecBounds = std::make_unique<CylinderVolumeBounds>(
580  radii[ir][0u], radii[ir][1u], innerEndcapHalfZ);
581  Transform3 ptf = tf;
582  ptf.pretranslate(Vector3(0., 0., innerBarrelHalfZ + innerEndcapHalfZ));
583  iVolumes.push_back(DetectorVolumeFactory::construct(
584  portalGenerator, tContext, "InnerPec" + radStr, ptf,
585  std::move(iPecBounds), tryAllPortals()));
586 
587  auto innerContainer = connectInZ(tContext, iVolumes, {}, logLevel);
588 
589  // Create the wrapping volume
590  auto wBounds = std::make_unique<CutoutCylinderVolumeBounds>(
591  radii[ir][0u], radii[ir][1u], radii[ir][2u], outerHalfZ, innerHalfZ);
592  auto wVolume = DetectorVolumeFactory::construct(
593  portalGenerator, tContext, "WrappingVolume" + radStr, tf,
594  std::move(wBounds), tryAllPortals());
595 
596  std::vector<DetectorComponent::PortalContainer> containers;
597  containers.push_back(innerContainer);
598 
599  DetectorComponent::PortalContainer outerContainer;
600  for (auto [ip, p] : enumerate(wVolume->portalPtrs())) {
601  outerContainer[ip] = p;
602  }
603  containers.push_back(outerContainer);
604 
605  auto detector = wrapInZR(tContext, containers, logLevel);
606  }
607 }
608 
609 BOOST_AUTO_TEST_CASE(RZPhiBoundaries) {
611 
612  auto innerB = std::make_unique<CylinderVolumeBounds>(0., 20., 100);
613  auto innerV = DetectorVolumeFactory::construct(
614  portalGenerator, tContext, "Inner", Transform3::Identity(),
615  std::move(innerB), tryAllPortals());
616 
617  auto middleLB = std::make_unique<CylinderVolumeBounds>(20., 60., 5);
618  auto middleLT = Transform3::Identity();
619  middleLT.pretranslate(Vector3(0., 0., -95));
620  auto middleLV = DetectorVolumeFactory::construct(
621  portalGenerator, tContext, "MiddleLeft", middleLT, std::move(middleLB),
622  tryAllPortals());
623 
624  auto middleDB = std::make_unique<CylinderVolumeBounds>(20., 40., 90);
625  auto middleDV = DetectorVolumeFactory::construct(
626  portalGenerator, tContext, "MiddleDown", Transform3::Identity(),
627  std::move(middleDB), tryAllPortals());
628 
629  auto middleUB = std::make_unique<CylinderVolumeBounds>(40., 60., 90);
630  auto middleUV = DetectorVolumeFactory::construct(
631  portalGenerator, tContext, "MiddleUp", Transform3::Identity(),
632  std::move(middleUB), tryAllPortals());
633 
634  auto middleRB = std::make_unique<CylinderVolumeBounds>(20., 60., 5);
635  auto middleRT = Transform3::Identity();
636  middleRT.pretranslate(Vector3(0., 0., 95));
637  auto middleRV = DetectorVolumeFactory::construct(
638  portalGenerator, tContext, "middleRight", middleRT, std::move(middleRB),
639  tryAllPortals());
640 
641  auto outerB = std::make_unique<CylinderVolumeBounds>(60., 120., 100);
642  auto outerV = DetectorVolumeFactory::construct(
643  portalGenerator, tContext, "Outer", Transform3::Identity(),
644  std::move(outerB), tryAllPortals());
645 
646  std::vector<std::shared_ptr<DetectorVolume>> volumes = {
647  innerV, middleLV, middleDV, middleUV, middleRV, outerV};
648 
649  auto boundaries = rzphiBoundaries(tContext, volumes, Acts::Logging::VERBOSE);
650  BOOST_CHECK(boundaries.size() == 3u);
651  // Check the r boundaries
652  std::vector<ActsScalar> rBoundaries = {0., 20., 40., 60., 120.};
653  BOOST_CHECK(boundaries[0u] == rBoundaries);
654  // Check the z boundaries
655  std::vector<ActsScalar> zBoundaries = {-100., -90., 90., 100.};
656  BOOST_CHECK(boundaries[1u] == zBoundaries);
657  BOOST_CHECK(boundaries[2u].size() == 2u);
658 }
659 
660 BOOST_AUTO_TEST_SUITE_END()