Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:12:32

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Detector/Detector.hpp"
0013 #include "Acts/Detector/DetectorComponents.hpp"
0014 #include "Acts/Detector/DetectorVolume.hpp"
0015 #include "Acts/Detector/GeometryIdGenerator.hpp"
0016 #include "Acts/Detector/PortalGenerators.hpp"
0017 #include "Acts/Detector/detail/CylindricalDetectorHelper.hpp"
0018 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0019 #include "Acts/Geometry/CutoutCylinderVolumeBounds.hpp"
0020 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0021 #include "Acts/Geometry/GeometryContext.hpp"
0022 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0023 #include "Acts/Navigation/InternalNavigation.hpp"
0024 #include "Acts/Utilities/Enumerate.hpp"
0025 #include "Acts/Utilities/Logger.hpp"
0026 
0027 #include <algorithm>
0028 #include <array>
0029 #include <cmath>
0030 #include <iterator>
0031 #include <map>
0032 #include <memory>
0033 #include <numbers>
0034 #include <ostream>
0035 #include <stdexcept>
0036 #include <string>
0037 #include <utility>
0038 #include <vector>
0039 
0040 namespace Acts::Experimental {
0041 class Portal;
0042 }  // namespace Acts::Experimental
0043 
0044 using namespace Acts;
0045 using namespace Experimental;
0046 using namespace Experimental::detail;
0047 using namespace Experimental::detail::CylindricalDetectorHelper;
0048 
0049 Logging::Level logLevel = Logging::VERBOSE;
0050 
0051 GeometryContext tContext;
0052 std::vector<std::shared_ptr<DetectorVolume>> eVolumes = {};
0053 
0054 auto portalGenerator = defaultPortalGenerator();
0055 
0056 BOOST_AUTO_TEST_SUITE(Experimental)
0057 
0058 BOOST_AUTO_TEST_CASE(ConnectVolumeExceptions) {
0059   ACTS_LOCAL_LOGGER(getDefaultLogger("Faulty setups", logLevel));
0060 
0061   auto cBounds0 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
0062   auto volume0 = DetectorVolumeFactory::construct(
0063       portalGenerator, tContext, "Volume0", Transform3::Identity(),
0064       std::move(cBounds0), tryAllPortals());
0065 
0066   auto cBounds1 =
0067       std::make_unique<CylinderVolumeBounds>(0., 100., 100, 0.2, 1.);
0068   auto volume1 = DetectorVolumeFactory::construct(
0069       portalGenerator, tContext, "Volume0", Transform3::Identity(),
0070       std::move(cBounds1), tryAllPortals());
0071 
0072   ACTS_INFO("*** Test: nullptr in the list of volumes");
0073 
0074   // Invalid arguments: nullptr
0075   std::vector<std::shared_ptr<DetectorVolume>> volumesWithNullptr = {
0076       volume0, nullptr, volume1};
0077   BOOST_CHECK_THROW(connectInR(tContext, volumesWithNullptr, {}, logLevel),
0078                     std::invalid_argument);
0079 
0080   ACTS_INFO("*** Test: non-cylinder in the list of volumes");
0081 
0082   auto cubeBounds = std::make_unique<CuboidVolumeBounds>(100., 100., 100);
0083   auto cube = DetectorVolumeFactory::construct(
0084       portalGenerator, tContext, "Cube", Transform3::Identity(),
0085       std::move(cubeBounds), tryAllPortals());
0086 
0087   // Invalid arguments: cube
0088   std::vector<std::shared_ptr<DetectorVolume>> volumesWithCube = {
0089       volume0, volume1, cube};
0090   BOOST_CHECK_THROW(connectInR(tContext, volumesWithCube, {}, logLevel),
0091                     std::invalid_argument);
0092 
0093   ACTS_INFO("*** Test: non-aligned volume in the list of volumes");
0094   Transform3 rotated = Transform3::Identity();
0095   AngleAxis3 rotX(0.1234, Vector3::UnitX());
0096   rotated *= rotX;
0097 
0098   auto cBounds2 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
0099   auto volume2 = DetectorVolumeFactory::construct(
0100       portalGenerator, tContext, "Volume2", rotated, std::move(cBounds2),
0101       tryAllPortals());
0102 
0103   // Invalid arguments: non-aligned
0104   std::vector<std::shared_ptr<DetectorVolume>> volumesWithNonaligned = {
0105       volume0, volume1, volume2};
0106   BOOST_CHECK_THROW(connectInR(tContext, volumesWithNonaligned, {}, logLevel),
0107                     std::invalid_argument);
0108 }
0109 
0110 BOOST_AUTO_TEST_CASE(ConnectInR) {
0111   ACTS_LOCAL_LOGGER(getDefaultLogger("Connect: R", logLevel));
0112   ACTS_INFO("*** Test: connect DetectorVolumes in R, create proto container");
0113   // Test with different opening angles
0114   std::vector<double> testOpenings = {std::numbers::pi, std::numbers::pi / 2.};
0115 
0116   std::vector<double> radii = {0., 10., 100., 200.};
0117   double halfZ = 100.;
0118 
0119   // This should work for full cylinder and sector openings
0120   for (auto [io, opening] : enumerate(testOpenings)) {
0121     ACTS_INFO("    -> test  with phi opening: " << opening);
0122     std::string opStr = "opening_" + std::to_string(io);
0123     std::vector<std::shared_ptr<DetectorVolume>> rVolumes = {};
0124     // Create the voluems
0125     for (auto [i, r] : enumerate(radii)) {
0126       if (i > 0) {
0127         auto cBounds = std::make_unique<CylinderVolumeBounds>(
0128             radii[i - 1u], r, halfZ, opening, 0.);
0129         rVolumes.push_back(DetectorVolumeFactory::construct(
0130             portalGenerator, tContext, "Cylinder_r" + std::to_string(i),
0131             Transform3::Identity(), std::move(cBounds), tryAllPortals()));
0132       }
0133     }
0134 
0135     auto protoContainer = connectInR(tContext, rVolumes, {}, logLevel);
0136     // Check the portal setup
0137     BOOST_CHECK_EQUAL(rVolumes[0u]->portalPtrs()[2u],
0138                       rVolumes[1u]->portalPtrs()[3u]);
0139     BOOST_CHECK_EQUAL(rVolumes[1u]->portalPtrs()[2u],
0140                       rVolumes[2u]->portalPtrs()[3u]);
0141     BOOST_CHECK_EQUAL(rVolumes[0u]->portalPtrs()[0u],
0142                       rVolumes[1u]->portalPtrs()[0u]);
0143     BOOST_CHECK_EQUAL(rVolumes[1u]->portalPtrs()[0u],
0144                       rVolumes[2u]->portalPtrs()[0u]);
0145     BOOST_CHECK_EQUAL(rVolumes[0u]->portalPtrs()[1u],
0146                       rVolumes[1u]->portalPtrs()[1u]);
0147     BOOST_CHECK_EQUAL(rVolumes[1u]->portalPtrs()[1u],
0148                       rVolumes[2u]->portalPtrs()[1u]);
0149     BOOST_CHECK_EQUAL(rVolumes[0u]->portalPtrs()[0u], protoContainer[0u]);
0150     BOOST_CHECK_EQUAL(rVolumes[0u]->portalPtrs()[1u], protoContainer[1u]);
0151 
0152     // Assign geometry ids to the volumes
0153     Acts::Experimental::GeometryIdGenerator::Config generatorConfig;
0154     GeometryIdGenerator generator(
0155         generatorConfig, Acts::getDefaultLogger("SequentialIdGenerator",
0156                                                 Acts::Logging::VERBOSE));
0157     auto cache = generator.generateCache();
0158     for (auto& vol : rVolumes) {
0159       generator.assignGeometryId(cache, *vol);
0160     }
0161 
0162     // A detector construction that should work
0163     auto detector =
0164         Detector::makeShared("DetectorInR", rVolumes, tryRootVolumes());
0165 
0166     // Make a rzphi grid
0167     const auto& volumes = detector->volumes();
0168     auto boundaries = rzphiBoundaries(tContext, volumes);
0169     const auto& rBoundaries = boundaries[0u];
0170     const auto& zBoundaries = boundaries[1u];
0171 
0172     // Check the radii
0173     std::vector<double> zvalues = {-halfZ, halfZ};
0174     BOOST_CHECK(radii == rBoundaries);
0175     BOOST_CHECK(zvalues == zBoundaries);
0176   }
0177 
0178   // Invalid arguments
0179   ACTS_INFO("*** Test: faulty empty vector");
0180   BOOST_CHECK_THROW(connectInR(tContext, eVolumes, {}, logLevel),
0181                     std::invalid_argument);
0182 
0183   // Faulty setups, not matchint in R
0184   ACTS_INFO("*** Test: volumes are not matching in R");
0185 
0186   auto cBounds00 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
0187   auto volume00 = DetectorVolumeFactory::construct(
0188       portalGenerator, tContext, "Volume00", Transform3::Identity(),
0189       std::move(cBounds00), tryAllPortals());
0190 
0191   auto cBounds01 = std::make_unique<CylinderVolumeBounds>(101., 200., 100);
0192   auto volume01 = DetectorVolumeFactory::construct(
0193       portalGenerator, tContext, "Volume01", Transform3::Identity(),
0194       std::move(cBounds01), tryAllPortals());
0195 
0196   std::vector<std::shared_ptr<DetectorVolume>> volumesNotMatching = {volume00,
0197                                                                      volume01};
0198   BOOST_CHECK_THROW(connectInR(tContext, volumesNotMatching, {}, logLevel),
0199                     std::runtime_error);
0200 
0201   ACTS_INFO("*** Test: volume bounds are not aligned");
0202   Transform3 shifted = Transform3::Identity();
0203   shifted.pretranslate(Vector3(0., 0., 10.));
0204 
0205   auto cBounds10 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
0206   auto volume10 = DetectorVolumeFactory::construct(
0207       portalGenerator, tContext, "Volume10", shifted, std::move(cBounds10),
0208       tryAllPortals());
0209 
0210   auto cBounds11 = std::make_unique<CylinderVolumeBounds>(100., 200., 90);
0211   auto volume11 = DetectorVolumeFactory::construct(
0212       portalGenerator, tContext, "Volume11", shifted, std::move(cBounds11),
0213       tryAllPortals());
0214 
0215   std::vector<std::shared_ptr<DetectorVolume>> volumesNotAligned = {volume10,
0216                                                                     volume11};
0217   BOOST_CHECK_THROW(connectInR(tContext, volumesNotAligned, {}, logLevel),
0218                     std::runtime_error);
0219 }
0220 
0221 BOOST_AUTO_TEST_CASE(ConnectInZ) {
0222   ACTS_LOCAL_LOGGER(getDefaultLogger("Connect: Z", logLevel));
0223   ACTS_INFO("*** Test: connect DetectorVolumes in Z, create proto container");
0224 
0225   // @TODO: test with different transforms, this should work in, not used yet
0226   std::vector<Transform3> transforms = {Transform3::Identity()};
0227   std::vector<std::array<double, 2>> radii = {{0., 100.}, {20., 120.}};
0228   std::vector<double> zValues = {-100., -20, 10., 100., 200.};
0229 
0230   for (auto [it, t] : enumerate(transforms)) {
0231     ACTS_INFO("    -> test series with transform id " << it);
0232 
0233     std::string trfStr = "_transform_" + std::to_string(it);
0234     for (auto [ir, r] : enumerate(radii)) {
0235       ACTS_INFO("        -> test series with radii setup "
0236                 << radii[ir][0u] << ", " << radii[ir][1u]);
0237 
0238       std::string radStr = "_radii_" + std::to_string(ir);
0239       std::vector<std::shared_ptr<DetectorVolume>> zVolumes = {};
0240       for (auto [i, z] : enumerate(zValues)) {
0241         if (i > 0) {
0242           auto cBounds = std::make_unique<CylinderVolumeBounds>(
0243               r[0], r[1], 0.5 * (z - zValues[i - 1u]));
0244           // z center
0245           double zCenter = 0.5 * (z + zValues[i - 1u]);
0246           Transform3 ti = Transform3::Identity();
0247           ti.pretranslate(t.translation() +
0248                           zCenter * t.rotation().matrix().col(2));
0249           ti.prerotate(t.rotation());
0250           // create the volume
0251           zVolumes.push_back(DetectorVolumeFactory::construct(
0252               portalGenerator, tContext,
0253               "Cylinder_z" + std::to_string(i) + trfStr + radStr, ti,
0254               std::move(cBounds), tryAllPortals()));
0255         }
0256       }
0257       // Now call the connector
0258       auto protoContainer = connectInZ(tContext, zVolumes, {}, logLevel);
0259 
0260       // Check the portal setup.
0261       // Glued, remainders are outside skin
0262       BOOST_CHECK_EQUAL(zVolumes[0u]->portalPtrs()[1u],
0263                         zVolumes[1u]->portalPtrs()[0u]);
0264       BOOST_CHECK_EQUAL(zVolumes[1u]->portalPtrs()[1u],
0265                         zVolumes[2u]->portalPtrs()[0u]);
0266       BOOST_CHECK_EQUAL(zVolumes[2u]->portalPtrs()[1u],
0267                         zVolumes[3u]->portalPtrs()[0u]);
0268       BOOST_CHECK_EQUAL(protoContainer[0u], zVolumes[0u]->portalPtrs()[0u]);
0269       BOOST_CHECK_EQUAL(protoContainer[1u], zVolumes[3u]->portalPtrs()[1u]);
0270 
0271       // Covered with the same surface, shich is the outside skin
0272       std::vector<unsigned int> checkShared = {2u};
0273       if (radii[ir][0u] > 0.) {
0274         checkShared.push_back(3u);
0275       }
0276 
0277       for (const auto& ip : checkShared) {
0278         BOOST_CHECK_EQUAL(zVolumes[0u]->portalPtrs()[ip],
0279                           zVolumes[1u]->portalPtrs()[ip]);
0280         BOOST_CHECK_EQUAL(zVolumes[1u]->portalPtrs()[ip],
0281                           zVolumes[2u]->portalPtrs()[ip]);
0282         BOOST_CHECK_EQUAL(zVolumes[2u]->portalPtrs()[ip],
0283                           zVolumes[3u]->portalPtrs()[ip]);
0284         BOOST_CHECK_EQUAL(protoContainer[ip], zVolumes[0u]->portalPtrs()[ip]);
0285       }
0286 
0287       // Assign geometry ids to the volumes
0288       Acts::Experimental::GeometryIdGenerator::Config generatorConfig;
0289       GeometryIdGenerator generator(
0290           generatorConfig, Acts::getDefaultLogger("SequentialIdGenerator",
0291                                                   Acts::Logging::VERBOSE));
0292       auto cache = generator.generateCache();
0293       for (auto& vol : zVolumes) {
0294         generator.assignGeometryId(cache, *vol);
0295       }
0296 
0297       auto detector =
0298           Detector::makeShared("DetectorInZ", zVolumes, tryRootVolumes());
0299     }
0300   }
0301 
0302   // Invalid arguments
0303   BOOST_CHECK_THROW(connectInZ(tContext, eVolumes, {}, logLevel),
0304                     std::invalid_argument);
0305 
0306   // Volumes have different radii - other bounds will be the same
0307   auto cBounds00 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
0308   auto volume00 = DetectorVolumeFactory::construct(
0309       portalGenerator, tContext, "Volume00",
0310       Transform3::Identity() * Translation3(0., 0., -100.),
0311       std::move(cBounds00), tryAllPortals());
0312 
0313   auto cBounds01 = std::make_unique<CylinderVolumeBounds>(0., 105., 100);
0314   auto volume01 = DetectorVolumeFactory::construct(
0315       portalGenerator, tContext, "Volume01",
0316       Transform3::Identity() * Translation3(0., 0., 100.), std::move(cBounds01),
0317       tryAllPortals());
0318 
0319   std::vector<std::shared_ptr<DetectorVolume>> volumesNonalignedBounds = {
0320       volume00, volume01};
0321   BOOST_CHECK_THROW(connectInZ(tContext, volumesNonalignedBounds, {}, logLevel),
0322                     std::runtime_error);
0323 
0324   // Volumes are not attached
0325   auto cBounds10 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
0326   auto volume10 = DetectorVolumeFactory::construct(
0327       portalGenerator, tContext, "Volume00",
0328       Transform3::Identity() * Translation3(0., 0., -105.),
0329       std::move(cBounds10), tryAllPortals());
0330 
0331   auto cBounds11 = std::make_unique<CylinderVolumeBounds>(0., 100., 100);
0332   auto volume11 = DetectorVolumeFactory::construct(
0333       portalGenerator, tContext, "Volume01",
0334       Transform3::Identity() * Translation3(0., 0., 100.), std::move(cBounds11),
0335       tryAllPortals());
0336 
0337   std::vector<std::shared_ptr<DetectorVolume>> volumesNotAttached = {volume10,
0338                                                                      volume11};
0339   BOOST_CHECK_THROW(connectInZ(tContext, volumesNotAttached, {}, logLevel),
0340                     std::runtime_error);
0341 }
0342 
0343 BOOST_AUTO_TEST_CASE(ConnectInPhi) {
0344   ACTS_LOCAL_LOGGER(getDefaultLogger("Connect: Phi", logLevel));
0345   ACTS_INFO("*** Test: connect DetectorVolumes in Phi, create proto container");
0346 
0347   std::vector<Transform3> transforms = {Transform3::Identity()};
0348   unsigned int phiSectors = 5;
0349   double phiHalfSector = std::numbers::pi / phiSectors;
0350 
0351   for (auto [it, t] : enumerate(transforms)) {
0352     ACTS_INFO("    -> test series with transform id " << it);
0353 
0354     std::vector<std::shared_ptr<DetectorVolume>> phiVolumes = {};
0355     for (unsigned int i = 0; i < phiSectors; ++i) {
0356       auto cBounds = std::make_unique<CylinderVolumeBounds>(
0357           10., 100., 100., phiHalfSector,
0358           -std::numbers::pi + (2u * i + 1u) * phiHalfSector);
0359 
0360       // create the volume
0361       phiVolumes.push_back(DetectorVolumeFactory::construct(
0362           portalGenerator, tContext, "Cylinder_phi" + std::to_string(i), t,
0363           std::move(cBounds), tryAllPortals()));
0364     }
0365 
0366     auto protoContainer = connectInPhi(tContext, phiVolumes, {}, logLevel);
0367 
0368     // All phiVolumes share : inner tube, outer cover, negative & positive disc
0369     std::vector<unsigned int> checkShared = {0u, 1u, 2u, 3u};
0370     for (auto [iv, v] : enumerate(phiVolumes)) {
0371       if (iv > 0u) {
0372         auto current = v;
0373         auto last = phiVolumes[iv - 1u];
0374         for (const auto& ch : checkShared) {
0375           BOOST_CHECK_EQUAL(current->portalPtrs()[ch], last->portalPtrs()[ch]);
0376         }
0377       }
0378     }
0379 
0380     // Assign geometry ids to the volumes
0381     Acts::Experimental::GeometryIdGenerator::Config generatorConfig;
0382     GeometryIdGenerator generator(
0383         generatorConfig, Acts::getDefaultLogger("SequentialIdGenerator",
0384                                                 Acts::Logging::VERBOSE));
0385     auto cache = generator.generateCache();
0386     for (auto& vol : phiVolumes) {
0387       generator.assignGeometryId(cache, *vol);
0388     }
0389 
0390     auto detector =
0391         Detector::makeShared("DetectorInPhi", phiVolumes, tryRootVolumes());
0392   }
0393 
0394   // Invalid arguments
0395   BOOST_CHECK_THROW(connectInPhi(tContext, eVolumes, {}, logLevel),
0396                     std::invalid_argument);
0397 }
0398 
0399 BOOST_AUTO_TEST_CASE(WrapVolumeinRZ) {
0400   ACTS_LOCAL_LOGGER(getDefaultLogger("Wrap: Z-R", logLevel));
0401   ACTS_INFO(
0402       "*** Test: wrap volume in Z-R with CutoutCylinderVolume, create proto "
0403       "container");
0404 
0405   // @TODO: test with different transforms, this should work in, not used yet
0406   std::vector<Transform3> transforms = {Transform3::Identity()};
0407 
0408   // Test with different inner radii
0409   std::vector<std::array<double, 3u>> radii = {{0., 100., 500.},
0410                                                {20., 120., 500.}};
0411 
0412   double innerHalfZ = 150.;
0413   double outerHalfZ = 175.;
0414 
0415   // Set up all the different tests
0416   for (auto [it, tf] : enumerate(transforms)) {
0417     ACTS_INFO("    Test series with transform id " << it);
0418 
0419     std::string trfStr = "_transform_" + std::to_string(it);
0420     for (auto [ir, r] : enumerate(radii)) {
0421       ACTS_INFO("    -> test series with radii setup " << radii[ir][0u] << ", "
0422                                                        << radii[ir][1u]);
0423 
0424       std::vector<std::shared_ptr<DetectorVolume>> volumes = {};
0425 
0426       std::string radStr = "_radii_" + std::to_string(ir);
0427       // Create the inner bounds
0428       auto iBounds = std::make_unique<CylinderVolumeBounds>(
0429           radii[ir][0u], radii[ir][1u], innerHalfZ);
0430       volumes.push_back(DetectorVolumeFactory::construct(
0431           portalGenerator, tContext, "InnerCylinder" + radStr + trfStr, tf,
0432           std::move(iBounds), tryAllPortals()));
0433 
0434       // Create the wrapping bounds
0435       auto wBounds = std::make_unique<CutoutCylinderVolumeBounds>(
0436           radii[ir][0u], radii[ir][1u], radii[ir][2u], outerHalfZ, innerHalfZ);
0437 
0438       volumes.push_back(DetectorVolumeFactory::construct(
0439           portalGenerator, tContext, "WrappingCylinder" + radStr + trfStr, tf,
0440           std::move(wBounds), tryAllPortals()));
0441 
0442       wrapInZR(tContext, volumes, logLevel);
0443     }
0444   }
0445 
0446   // Invalid arguments
0447   BOOST_CHECK_THROW(wrapInZR(tContext, eVolumes, logLevel),
0448                     std::invalid_argument);
0449 }
0450 
0451 BOOST_AUTO_TEST_CASE(ProtoContainerZR) {
0452   ACTS_LOCAL_LOGGER(getDefaultLogger("Container: Z-R", logLevel));
0453   ACTS_INFO("*** Test: create a container in Z-R.");
0454 
0455   auto transform = Transform3::Identity();
0456 
0457   std::vector<double> innerMostRadii = {0., 2.};
0458 
0459   for (auto [ir, imr] : enumerate(innerMostRadii)) {
0460     ACTS_INFO("    -> test series innermost radius setup "
0461               << innerMostRadii[ir]);
0462 
0463     // A container in R
0464     std::vector<double> radii = {25., 100., 200.};
0465     double halfZ = 200;
0466 
0467     // An innermost Pipe
0468     auto bBounds =
0469         std::make_unique<CylinderVolumeBounds>(imr, radii[0u], halfZ);
0470 
0471     auto innerPipe = DetectorVolumeFactory::construct(
0472         portalGenerator, tContext, "InnerPipe", transform, std::move(bBounds),
0473         tryAllPortals());
0474 
0475     // Make a container representation out of it
0476     std::map<unsigned int, std::shared_ptr<Portal>> ipContainer;
0477     for (auto [ip, p] : enumerate(innerPipe->portalPtrs())) {
0478       ipContainer[ip] = p;
0479     }
0480 
0481     // Create the r - sorted volumes
0482     std::vector<std::shared_ptr<DetectorVolume>> rVolumes = {};
0483     // Create the voluems
0484     for (auto [i, r] : enumerate(radii)) {
0485       if (i > 0) {
0486         auto cBounds =
0487             std::make_unique<CylinderVolumeBounds>(radii[i - 1u], r, halfZ);
0488         rVolumes.push_back(DetectorVolumeFactory::construct(
0489             portalGenerator, tContext, "Cylinder_r" + std::to_string(i),
0490             transform, std::move(cBounds), tryAllPortals()));
0491       }
0492     }
0493 
0494     auto protoContainerInR = connectInR(tContext, rVolumes, {}, logLevel);
0495 
0496     std::vector<double> zValues = {-200., -120, 10., 100., 200.};
0497     std::vector<std::shared_ptr<DetectorVolume>> zVolumes = {};
0498     for (auto [i, z] : enumerate(zValues)) {
0499       if (i > 0) {
0500         auto cBounds = std::make_unique<CylinderVolumeBounds>(
0501             200., 300., 0.5 * (z - zValues[i - 1u]));
0502         // z center
0503         double zCenter = 0.5 * (z + zValues[i - 1u]);
0504         Transform3 ti = transform;
0505         ti.pretranslate(transform.translation() +
0506                         zCenter * transform.rotation().matrix().col(2));
0507 
0508         // create the volume
0509         zVolumes.push_back(DetectorVolumeFactory::construct(
0510             portalGenerator, tContext, "Cylinder_z" + std::to_string(i), ti,
0511             std::move(cBounds), tryAllPortals()));
0512       }
0513     }
0514     // Now call the connector
0515     auto protoContainerInZ = connectInZ(tContext, zVolumes, {}, logLevel);
0516     auto centralContainer = connectInR(
0517         tContext, {ipContainer, protoContainerInR, protoContainerInZ}, {},
0518         logLevel);
0519 
0520     // Let's make two endcaps
0521     // Nec
0522     auto necBounds = std::make_unique<CylinderVolumeBounds>(imr, 300., 50.);
0523 
0524     auto necTransform = Transform3::Identity();
0525     necTransform.pretranslate(Vector3(0., 0., -250));
0526     auto necVolume = DetectorVolumeFactory::construct(
0527         portalGenerator, tContext, "Nec", necTransform, std::move(necBounds),
0528         tryAllPortals());
0529 
0530     std::map<unsigned int, std::shared_ptr<Portal>> necContainer;
0531     for (auto [ip, p] : enumerate(necVolume->portalPtrs())) {
0532       necContainer[ip] = p;
0533     }
0534 
0535     // Pec container
0536     auto pecInnerBounds =
0537         std::make_unique<CylinderVolumeBounds>(imr, 175., 100.);
0538 
0539     auto pecOuterBounds =
0540         std::make_unique<CylinderVolumeBounds>(175., 300., 100.);
0541 
0542     auto pecTransform = Transform3::Identity();
0543     pecTransform.pretranslate(Vector3(0., 0., 300));
0544     auto pecInner = DetectorVolumeFactory::construct(
0545         portalGenerator, tContext, "PecInner", pecTransform,
0546         std::move(pecInnerBounds), tryAllPortals());
0547     auto pecOuter = DetectorVolumeFactory::construct(
0548         portalGenerator, tContext, "PecOuter", pecTransform,
0549         std::move(pecOuterBounds), tryAllPortals());
0550 
0551     std::vector<std::shared_ptr<DetectorVolume>> pecVolumes = {pecInner,
0552                                                                pecOuter};
0553     auto pecContainer = connectInR(tContext, pecVolumes, {}, logLevel);
0554 
0555     auto overallContainer = connectInZ(
0556         tContext, {necContainer, centralContainer, pecContainer}, {}, logLevel);
0557 
0558     //  Add them together
0559     std::vector<std::shared_ptr<DetectorVolume>> dVolumes;
0560     dVolumes.push_back(innerPipe);
0561     dVolumes.push_back(necVolume);
0562     dVolumes.insert(dVolumes.end(), rVolumes.begin(), rVolumes.end());
0563     dVolumes.insert(dVolumes.end(), zVolumes.begin(), zVolumes.end());
0564     dVolumes.push_back(pecInner);
0565     dVolumes.push_back(pecOuter);
0566 
0567     // Assign geometry ids to the volumes
0568     Acts::Experimental::GeometryIdGenerator::Config generatorConfig;
0569     GeometryIdGenerator generator(
0570         generatorConfig, Acts::getDefaultLogger("SequentialIdGenerator",
0571                                                 Acts::Logging::VERBOSE));
0572     auto cache = generator.generateCache();
0573     for (auto& vol : dVolumes) {
0574       generator.assignGeometryId(cache, *vol);
0575     }
0576 
0577     auto detector = Detector::makeShared("DetectorFromProtoContainer", dVolumes,
0578                                          tryRootVolumes());
0579   }  // test with different innermost radii
0580 }
0581 
0582 BOOST_AUTO_TEST_CASE(WrapContainernRZ) {
0583   ACTS_LOCAL_LOGGER(getDefaultLogger("Container: Wrap", logLevel));
0584   ACTS_INFO("*** Test: create a container in Z-R by wrapping.");
0585 
0586   // Test with different inner radii
0587   std::vector<std::array<double, 3u>> radii = {{0., 100., 500.},
0588                                                {20., 120., 500.}};
0589 
0590   double innerHalfZ = 150.;
0591   double innerBarrelHalfZ = 75.;
0592   double innerEndcapHalfZ = 0.5 * (innerHalfZ - innerBarrelHalfZ);
0593   double outerHalfZ = 175.;
0594 
0595   Transform3 tf = Transform3::Identity();
0596 
0597   // Set up all the different tests
0598   for (auto [ir, r] : enumerate(radii)) {
0599     std::string radStr = "_radii_" + std::to_string(ir);
0600     ACTS_INFO("    -> test series innermost radius setup " << radii[ir][0u]);
0601 
0602     // Let's create the inner container first
0603     std::vector<std::shared_ptr<DetectorVolume>> iVolumes = {};
0604 
0605     auto iNecBounds = std::make_unique<CylinderVolumeBounds>(
0606         radii[ir][0u], radii[ir][1u], innerEndcapHalfZ);
0607     Transform3 ntf = tf;
0608     ntf.pretranslate(Vector3(0., 0., -innerBarrelHalfZ - innerEndcapHalfZ));
0609     iVolumes.push_back(DetectorVolumeFactory::construct(
0610         portalGenerator, tContext, "InnerNec" + radStr, ntf,
0611         std::move(iNecBounds), tryAllPortals()));
0612 
0613     auto iBarrelBounds = std::make_unique<CylinderVolumeBounds>(
0614         radii[ir][0u], radii[ir][1u], innerBarrelHalfZ);
0615     iVolumes.push_back(DetectorVolumeFactory::construct(
0616         portalGenerator, tContext, "InnerBarrel" + radStr, tf,
0617         std::move(iBarrelBounds), tryAllPortals()));
0618 
0619     auto iPecBounds = std::make_unique<CylinderVolumeBounds>(
0620         radii[ir][0u], radii[ir][1u], innerEndcapHalfZ);
0621     Transform3 ptf = tf;
0622     ptf.pretranslate(Vector3(0., 0., innerBarrelHalfZ + innerEndcapHalfZ));
0623     iVolumes.push_back(DetectorVolumeFactory::construct(
0624         portalGenerator, tContext, "InnerPec" + radStr, ptf,
0625         std::move(iPecBounds), tryAllPortals()));
0626 
0627     auto innerContainer = connectInZ(tContext, iVolumes, {}, logLevel);
0628 
0629     // Create the wrapping volume
0630     auto wBounds = std::make_unique<CutoutCylinderVolumeBounds>(
0631         radii[ir][0u], radii[ir][1u], radii[ir][2u], outerHalfZ, innerHalfZ);
0632     auto wVolume = DetectorVolumeFactory::construct(
0633         portalGenerator, tContext, "WrappingVolume" + radStr, tf,
0634         std::move(wBounds), tryAllPortals());
0635 
0636     std::vector<DetectorComponent::PortalContainer> containers;
0637     containers.push_back(innerContainer);
0638 
0639     DetectorComponent::PortalContainer outerContainer;
0640     for (auto [ip, p] : enumerate(wVolume->portalPtrs())) {
0641       outerContainer[ip] = p;
0642     }
0643     containers.push_back(outerContainer);
0644 
0645     auto detector = wrapInZR(tContext, containers, logLevel);
0646   }
0647 }
0648 
0649 BOOST_AUTO_TEST_CASE(RZPhiBoundaries) {
0650   auto portalGenerator = defaultPortalGenerator();
0651 
0652   auto innerB = std::make_unique<CylinderVolumeBounds>(0., 20., 100);
0653   auto innerV = DetectorVolumeFactory::construct(
0654       portalGenerator, tContext, "Inner", Transform3::Identity(),
0655       std::move(innerB), tryAllPortals());
0656 
0657   auto middleLB = std::make_unique<CylinderVolumeBounds>(20., 60., 5);
0658   auto middleLT = Transform3::Identity();
0659   middleLT.pretranslate(Vector3(0., 0., -95));
0660   auto middleLV = DetectorVolumeFactory::construct(
0661       portalGenerator, tContext, "MiddleLeft", middleLT, std::move(middleLB),
0662       tryAllPortals());
0663 
0664   auto middleDB = std::make_unique<CylinderVolumeBounds>(20., 40., 90);
0665   auto middleDV = DetectorVolumeFactory::construct(
0666       portalGenerator, tContext, "MiddleDown", Transform3::Identity(),
0667       std::move(middleDB), tryAllPortals());
0668 
0669   auto middleUB = std::make_unique<CylinderVolumeBounds>(40., 60., 90);
0670   auto middleUV = DetectorVolumeFactory::construct(
0671       portalGenerator, tContext, "MiddleUp", Transform3::Identity(),
0672       std::move(middleUB), tryAllPortals());
0673 
0674   auto middleRB = std::make_unique<CylinderVolumeBounds>(20., 60., 5);
0675   auto middleRT = Transform3::Identity();
0676   middleRT.pretranslate(Vector3(0., 0., 95));
0677   auto middleRV = DetectorVolumeFactory::construct(
0678       portalGenerator, tContext, "middleRight", middleRT, std::move(middleRB),
0679       tryAllPortals());
0680 
0681   auto outerB = std::make_unique<CylinderVolumeBounds>(60., 120., 100);
0682   auto outerV = DetectorVolumeFactory::construct(
0683       portalGenerator, tContext, "Outer", Transform3::Identity(),
0684       std::move(outerB), tryAllPortals());
0685 
0686   std::vector<std::shared_ptr<DetectorVolume>> volumes = {
0687       innerV, middleLV, middleDV, middleUV, middleRV, outerV};
0688 
0689   auto boundaries =
0690       rzphiBoundaries(tContext, volumes, 0., Acts::Logging::VERBOSE);
0691   BOOST_CHECK_EQUAL(boundaries.size(), 3u);
0692   // Check the r boundaries
0693   std::vector<double> rBoundaries = {0., 20., 40., 60., 120.};
0694   BOOST_CHECK(boundaries[0u] == rBoundaries);
0695   // Check the z boundaries
0696   std::vector<double> zBoundaries = {-100., -90., 90., 100.};
0697   BOOST_CHECK(boundaries[1u] == zBoundaries);
0698   BOOST_CHECK_EQUAL(boundaries[2u].size(), 2u);
0699 }
0700 
0701 BOOST_AUTO_TEST_CASE(RZPhiBoundariesWithTolerance) {
0702   auto innerB = std::make_unique<CylinderVolumeBounds>(0., 20., 100);
0703   auto innerV = DetectorVolumeFactory::construct(
0704       portalGenerator, tContext, "Inner", Transform3::Identity(),
0705       std::move(innerB), tryAllPortals());
0706 
0707   auto outerB = std::make_unique<CylinderVolumeBounds>(20.001, 100., 100);
0708   auto outerV = DetectorVolumeFactory::construct(
0709       portalGenerator, tContext, "Inner", Transform3::Identity(),
0710       std::move(outerB), tryAllPortals());
0711 
0712   std::vector<std::shared_ptr<DetectorVolume>> volumes = {innerV, outerV};
0713 
0714   auto boundariesWoTol =
0715       rzphiBoundaries(tContext, volumes, 0., Acts::Logging::VERBOSE);
0716   BOOST_CHECK_EQUAL(boundariesWoTol[0u].size(), 4u);
0717 
0718   auto boundariesWTol =
0719       rzphiBoundaries(tContext, volumes, 0.01, Acts::Logging::VERBOSE);
0720   BOOST_CHECK_EQUAL(boundariesWTol[0u].size(), 3u);
0721 }
0722 
0723 BOOST_AUTO_TEST_SUITE_END()