Back to home page

EIC code displayed by LXR

 
 

    


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

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/Detector/Blueprint.hpp"
0012 #include "Acts/Detector/CuboidalContainerBuilder.hpp"
0013 #include "Acts/Detector/DetectorBuilder.hpp"
0014 #include "Acts/Detector/DetectorComponents.hpp"
0015 #include "Acts/Detector/DetectorVolume.hpp"
0016 #include "Acts/Detector/GeometryIdGenerator.hpp"
0017 #include "Acts/Detector/IndexedRootVolumeFinderBuilder.hpp"
0018 #include "Acts/Detector/detail/BlueprintDrawer.hpp"
0019 #include "Acts/Detector/detail/BlueprintHelper.hpp"
0020 #include "Acts/Detector/interface/IInternalStructureBuilder.hpp"
0021 #include "Acts/Geometry/GeometryContext.hpp"
0022 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0023 #include "Acts/Navigation/InternalNavigation.hpp"
0024 #include "Acts/Surfaces/PlaneSurface.hpp"
0025 #include "Acts/Surfaces/RectangleBounds.hpp"
0026 #include "Acts/Surfaces/Surface.hpp"
0027 #include "Acts/Utilities/BinningData.hpp"
0028 
0029 #include <algorithm>
0030 #include <fstream>
0031 
0032 class SurfaceBuilder : public Acts::Experimental::IInternalStructureBuilder {
0033  public:
0034   SurfaceBuilder(const Acts::Transform3& transform,
0035                  const Acts::RectangleBounds& sBounds)
0036       : m_transform(transform), m_surfaceBounds(sBounds) {};
0037 
0038   /// Conrstruct and return the internal structure creation
0039   ///
0040   /// @param gctx the geometry context at the creation of the internal structure
0041   ///
0042   /// @return a consistent set of detector volume internals
0043   Acts::Experimental::InternalStructure construct(
0044       [[maybe_unused]] const Acts::GeometryContext& gctx) const final {
0045     auto surface = Acts::Surface::makeShared<Acts::PlaneSurface>(
0046         (m_transform),
0047         std::make_shared<Acts::RectangleBounds>(m_surfaceBounds));
0048 
0049     // Trivialities first: internal volumes
0050     std::vector<std::shared_ptr<Acts::Experimental::DetectorVolume>>
0051         internalVolumes = {};
0052     Acts::Experimental::ExternalNavigationDelegate internalVolumeUpdater =
0053         Acts::Experimental::tryNoVolumes();
0054 
0055     // Retrieve the layer surfaces
0056     Acts::Experimental::InternalNavigationDelegate internalCandidatesUpdater =
0057         Acts::Experimental::tryAllPortalsAndSurfaces();
0058 
0059     // Return the internal structure
0060     return Acts::Experimental::InternalStructure{
0061         {surface},
0062         internalVolumes,
0063         std::move(internalCandidatesUpdater),
0064         std::move(internalVolumeUpdater)};
0065   }
0066 
0067  private:
0068   Acts::Transform3 m_transform;
0069   Acts::RectangleBounds m_surfaceBounds;
0070 };
0071 
0072 BOOST_AUTO_TEST_SUITE(Detector)
0073 
0074 BOOST_AUTO_TEST_CASE(CuboidalDetectorFromBlueprintTest) {
0075   Acts::GeometryContext tContext;
0076 
0077   // This tests shows how to careate cuboidal detector from a detector
0078   // blueprint.
0079   //
0080   // In general, the blueprint (lines below) is generated through reading in
0081   // or by parsing the geometry model (DD4heo, TGeo, Geant4, etc.). For
0082   // testing purpose, let us create the blueprint manually.
0083   //
0084 
0085   // Blueprint starts here ----------------
0086 
0087   // Detector dimensions
0088   double detectorX = 100.;
0089   double detectorY = 100.;
0090   double detectorZ = 100.;
0091 
0092   // Pixel system
0093   double pixelX = 20;
0094   double pixelY = 100;
0095   double pixelZ = 10;
0096 
0097   // Create  root node
0098   std::vector<Acts::AxisDirection> detectorBins = {Acts::AxisDirection::AxisX};
0099   std::vector<double> detectorBounds = {detectorX, detectorY, detectorZ};
0100 
0101   // The root node - detector
0102   auto detectorBpr = std::make_unique<Acts::Experimental::Blueprint::Node>(
0103       "detector", Acts::Transform3::Identity(), Acts::VolumeBounds::eCuboid,
0104       detectorBounds, detectorBins);
0105 
0106   // Left arm
0107   std::vector<double> leftArmBounds = {detectorX * 0.5, detectorY, detectorZ};
0108 
0109   std::vector<Acts::AxisDirection> leftArmBins = {Acts::AxisDirection::AxisZ};
0110 
0111   Acts::Transform3 leftArmTransform =
0112       Acts::Transform3::Identity() *
0113       Acts::Translation3(-detectorX * 0.5, 0., 0);
0114 
0115   auto leftArm = std::make_unique<Acts::Experimental::Blueprint::Node>(
0116       "leftArm", leftArmTransform, Acts::VolumeBounds::eCuboid, leftArmBounds,
0117       leftArmBins);
0118 
0119   // Pixel layer L1
0120   std::vector<double> pixelL1Boundaries = {pixelX, pixelY, pixelZ};
0121 
0122   Acts::Transform3 pixelL1Transform =
0123       Acts::Transform3::Identity() *
0124       Acts::Translation3(-pixelX - 5, 0., -detectorZ + pixelZ + 5);
0125 
0126   auto pixelL1Structure = std::make_shared<SurfaceBuilder>(
0127       pixelL1Transform, Acts::RectangleBounds(pixelX * 0.8, pixelY * 0.8));
0128 
0129   auto pixelL1 = std::make_unique<Acts::Experimental::Blueprint::Node>(
0130       "pixelL1", pixelL1Transform, Acts::VolumeBounds::eCuboid,
0131       pixelL1Boundaries, pixelL1Structure);
0132 
0133   // Pixel layer L2
0134   std::vector<double> pixelL2Boundaries = {pixelX, pixelY, pixelZ};
0135 
0136   Acts::Transform3 pixelL2Transform =
0137       Acts::Transform3::Identity() *
0138       Acts::Translation3(-pixelX - 5, 0., -detectorZ + 2 * pixelZ + 5 * 5);
0139 
0140   auto pixelL2Structure = std::make_shared<SurfaceBuilder>(
0141       pixelL2Transform, Acts::RectangleBounds(pixelX * 0.8, pixelY * 0.8));
0142 
0143   auto pixelL2 = std::make_unique<Acts::Experimental::Blueprint::Node>(
0144       "pixelL2", pixelL2Transform, Acts::VolumeBounds::eCuboid,
0145       pixelL2Boundaries, pixelL2Structure);
0146 
0147   // Add pixel layers to left arm
0148   // and left arm to detector
0149   leftArm->add(std::move(pixelL1));
0150   leftArm->add(std::move(pixelL2));
0151   detectorBpr->add(std::move(leftArm));
0152 
0153   // Right arm
0154   std::vector<double> rightArmBounds = {detectorX * 0.5, detectorY, detectorZ};
0155 
0156   std::vector<Acts::AxisDirection> rightArmBins = {Acts::AxisDirection::AxisZ};
0157 
0158   Acts::Transform3 rightArmTransform =
0159       Acts::Transform3::Identity() * Acts::Translation3(detectorX * 0.5, 0., 0);
0160 
0161   auto rightArm = std::make_unique<Acts::Experimental::Blueprint::Node>(
0162       "rightArm", rightArmTransform, Acts::VolumeBounds::eCuboid,
0163       rightArmBounds, rightArmBins);
0164 
0165   // Pixel layer R1
0166   std::vector<double> pixelR1Boundaries = {pixelX, pixelY, pixelZ};
0167 
0168   Acts::Transform3 pixelR1Transform =
0169       Acts::Transform3::Identity() *
0170       Acts::Translation3(pixelX + 5, 0., -detectorZ + pixelZ + 5);
0171 
0172   auto pixelR1Structure = std::make_shared<SurfaceBuilder>(
0173       pixelR1Transform, Acts::RectangleBounds(pixelX * 0.8, pixelY * 0.8));
0174 
0175   auto pixelR1 = std::make_unique<Acts::Experimental::Blueprint::Node>(
0176       "pixelR1", pixelR1Transform, Acts::VolumeBounds::eCuboid,
0177       pixelR1Boundaries, pixelR1Structure);
0178 
0179   // Pixel layer R2
0180   std::vector<double> pixelR2Boundaries = {pixelX, pixelY, pixelZ};
0181 
0182   Acts::Transform3 pixelR2Transform =
0183       Acts::Transform3::Identity() *
0184       Acts::Translation3(pixelX + 5, 0., -detectorZ + 2 * pixelZ + 5 * 5);
0185 
0186   auto pixelR2Structure = std::make_shared<SurfaceBuilder>(
0187       pixelR2Transform, Acts::RectangleBounds(pixelX * 0.8, pixelY * 0.8));
0188 
0189   auto pixelR2 = std::make_unique<Acts::Experimental::Blueprint::Node>(
0190       "pixelR2", pixelR2Transform, Acts::VolumeBounds::eCuboid,
0191       pixelR2Boundaries, pixelR2Structure);
0192 
0193   // Add pixel layers to right arm
0194   // and right arm to detector
0195   rightArm->add(std::move(pixelR1));
0196   rightArm->add(std::move(pixelR2));
0197   detectorBpr->add(std::move(rightArm));
0198 
0199   // A geo ID generator
0200   detectorBpr->geoIdGenerator =
0201       std::make_shared<Acts::Experimental::GeometryIdGenerator>(
0202           Acts::Experimental::GeometryIdGenerator::Config{},
0203           Acts::getDefaultLogger("RecursiveIdGenerator",
0204                                  Acts::Logging::VERBOSE));
0205 
0206   std::cout << "Fill gaps ..." << std::endl;
0207   // Complete and fill gaps
0208   Acts::Experimental::detail::BlueprintHelper::fillGaps(*detectorBpr);
0209   std::cout << "Filled gaps ..." << std::endl;
0210 
0211   std::fstream fs("cylindrical_detector_blueprint.dot", std::ios::out);
0212   Acts::Experimental::detail::BlueprintDrawer::dotStream(fs, *detectorBpr);
0213   fs.close();
0214 
0215   // ----------------------------- end of blueprint
0216 
0217   // Create a Cuboidal detector builder from this blueprint
0218   auto detectorBuilder =
0219       std::make_shared<Acts::Experimental::CuboidalContainerBuilder>(
0220           *detectorBpr, Acts::Logging::VERBOSE);
0221 
0222   // Detector builder
0223   Acts::Experimental::DetectorBuilder::Config dCfg;
0224   dCfg.auxiliary = "*** Test : auto generated cuboidal detector builder  ***";
0225   dCfg.name = "Cuboidal detector from blueprint";
0226   dCfg.builder = detectorBuilder;
0227   dCfg.geoIdGenerator = detectorBpr->geoIdGenerator;
0228 
0229   auto detector = Acts::Experimental::DetectorBuilder(dCfg).construct(tContext);
0230 
0231   BOOST_REQUIRE_NE(detector, nullptr);
0232 
0233   // There should be 10 volumes, and they should be built in order
0234   // leftArm_gap_0
0235   // pixelL1
0236   // leftArm_gap_1
0237   // pixelL2
0238   // leftArm_gap_2
0239   // rightArm_gap_0
0240   // pixelR1
0241   // rightArm_gap_1
0242   // pixelR2
0243   // rightArm_gap_2
0244   BOOST_CHECK_EQUAL(detector->volumes().size(), 10u);
0245   BOOST_CHECK_EQUAL(detector->volumes()[0]->name(), "leftArm_gap_0");
0246   BOOST_CHECK_EQUAL(detector->volumes()[1]->name(), "pixelL1");
0247   BOOST_CHECK_EQUAL(detector->volumes()[2]->name(), "leftArm_gap_1");
0248   BOOST_CHECK_EQUAL(detector->volumes()[3]->name(), "pixelL2");
0249   BOOST_CHECK_EQUAL(detector->volumes()[4]->name(), "leftArm_gap_2");
0250   BOOST_CHECK_EQUAL(detector->volumes()[5]->name(), "rightArm_gap_0");
0251   BOOST_CHECK_EQUAL(detector->volumes()[6]->name(), "pixelR1");
0252   BOOST_CHECK_EQUAL(detector->volumes()[7]->name(), "rightArm_gap_1");
0253   BOOST_CHECK_EQUAL(detector->volumes()[8]->name(), "pixelR2");
0254   BOOST_CHECK_EQUAL(detector->volumes()[9]->name(), "rightArm_gap_2");
0255 
0256   // Volumes have to be contained within the
0257   // initial detector bounds
0258   double internalStretchLeftZ =
0259       detector->volumes()[0]
0260           ->volumeBounds()
0261           .values()[toUnderlying(Acts::AxisDirection::AxisZ)] +
0262       detector->volumes()[1]
0263           ->volumeBounds()
0264           .values()[toUnderlying(Acts::AxisDirection::AxisZ)] +
0265       detector->volumes()[2]
0266           ->volumeBounds()
0267           .values()[toUnderlying(Acts::AxisDirection::AxisZ)] +
0268       detector->volumes()[3]
0269           ->volumeBounds()
0270           .values()[toUnderlying(Acts::AxisDirection::AxisZ)] +
0271       detector->volumes()[4]
0272           ->volumeBounds()
0273           .values()[toUnderlying(Acts::AxisDirection::AxisZ)];
0274 
0275   double internalStretchRightZ =
0276       detector->volumes()[5]
0277           ->volumeBounds()
0278           .values()[toUnderlying(Acts::AxisDirection::AxisZ)] +
0279       detector->volumes()[6]
0280           ->volumeBounds()
0281           .values()[toUnderlying(Acts::AxisDirection::AxisZ)] +
0282       detector->volumes()[7]
0283           ->volumeBounds()
0284           .values()[toUnderlying(Acts::AxisDirection::AxisZ)] +
0285       detector->volumes()[8]
0286           ->volumeBounds()
0287           .values()[toUnderlying(Acts::AxisDirection::AxisZ)] +
0288       detector->volumes()[9]
0289           ->volumeBounds()
0290           .values()[toUnderlying(Acts::AxisDirection::AxisZ)];
0291 
0292   double internalStretchX1 =
0293       detector->volumes()[0]
0294           ->volumeBounds()
0295           .values()[toUnderlying(Acts::AxisDirection::AxisX)] +
0296       detector->volumes()[5]
0297           ->volumeBounds()
0298           .values()[toUnderlying(Acts::AxisDirection::AxisX)];
0299 
0300   double internalStretchX2 =
0301       detector->volumes()[1]
0302           ->volumeBounds()
0303           .values()[toUnderlying(Acts::AxisDirection::AxisX)] +
0304       detector->volumes()[6]
0305           ->volumeBounds()
0306           .values()[toUnderlying(Acts::AxisDirection::AxisX)];
0307 
0308   double internalStretchX3 =
0309       detector->volumes()[2]
0310           ->volumeBounds()
0311           .values()[toUnderlying(Acts::AxisDirection::AxisX)] +
0312       detector->volumes()[7]
0313           ->volumeBounds()
0314           .values()[toUnderlying(Acts::AxisDirection::AxisX)];
0315 
0316   double internalStretchX4 =
0317       detector->volumes()[3]
0318           ->volumeBounds()
0319           .values()[toUnderlying(Acts::AxisDirection::AxisX)] +
0320       detector->volumes()[8]
0321           ->volumeBounds()
0322           .values()[toUnderlying(Acts::AxisDirection::AxisX)];
0323 
0324   double internalStretchX5 =
0325       detector->volumes()[4]
0326           ->volumeBounds()
0327           .values()[toUnderlying(Acts::AxisDirection::AxisX)] +
0328       detector->volumes()[9]
0329           ->volumeBounds()
0330           .values()[toUnderlying(Acts::AxisDirection::AxisX)];
0331 
0332   BOOST_CHECK_EQUAL(internalStretchLeftZ, detectorZ);
0333   BOOST_CHECK_EQUAL(internalStretchRightZ, detectorZ);
0334   BOOST_CHECK_EQUAL(internalStretchX1, detectorX);
0335   BOOST_CHECK_EQUAL(internalStretchX2, detectorX);
0336   BOOST_CHECK_EQUAL(internalStretchX3, detectorX);
0337   BOOST_CHECK_EQUAL(internalStretchX4, detectorX);
0338   BOOST_CHECK_EQUAL(internalStretchX5, detectorX);
0339 
0340   for (auto& volume : detector->volumes()) {
0341     BOOST_CHECK_EQUAL(volume->volumeBounds()
0342                           .values()[toUnderlying(Acts::AxisDirection::AxisY)],
0343                       detectorY);
0344   }
0345 
0346   // There should be surfaces inside the pixel
0347   // volumes
0348   BOOST_CHECK_EQUAL(detector->volumes()[1]->surfaces().size(), 1u);
0349   BOOST_CHECK_EQUAL(detector->volumes()[3]->surfaces().size(), 1u);
0350   BOOST_CHECK_EQUAL(detector->volumes()[6]->surfaces().size(), 1u);
0351   BOOST_CHECK_EQUAL(detector->volumes()[8]->surfaces().size(), 1u);
0352 
0353   // There should be 8 Z-portals from
0354   // connecting the arms, 4 outside Z-portals,
0355   // 3 X-portals from fusing the containers, and
0356   // 2+2 Y-portals that were replaced when connecting
0357   // in Z, but didn't get renewed when connecting in X
0358   // 8+4+3+2+2 = 19 in total
0359   std::vector<const Acts::Experimental::Portal*> portals;
0360   for (auto& volume : detector->volumes()) {
0361     portals.insert(portals.end(), volume->portals().begin(),
0362                    volume->portals().end());
0363   }
0364   std::ranges::sort(portals);
0365   auto last = std::unique(portals.begin(), portals.end());
0366   portals.erase(last, portals.end());
0367   BOOST_CHECK_EQUAL(portals.size(), 19u);
0368 
0369   // Volumes should have the same Y-normal-direction portals
0370   // but only within the same arm. CuboidalDetectorHelper
0371   // does not yet connect the containers in a consistent way
0372   bool samePortalY1 = true, samePortalY2 = true;
0373   for (int i = 0; i < 4; i++) {
0374     samePortalY1 =
0375         samePortalY1 && (detector->volumes()[i]->portals().at(4) ==
0376                          detector->volumes()[i + 1]->portals().at(4));
0377     samePortalY2 =
0378         samePortalY2 && (detector->volumes()[5 + i]->portals().at(4) ==
0379                          detector->volumes()[5 + i + 1]->portals().at(4));
0380   }
0381   BOOST_CHECK_EQUAL(samePortalY1, true);
0382   BOOST_CHECK_EQUAL(samePortalY2, true);
0383   samePortalY1 = true, samePortalY2 = true;
0384   for (int i = 0; i < 4; i++) {
0385     samePortalY1 =
0386         samePortalY1 && (detector->volumes()[i]->portals().at(5) ==
0387                          detector->volumes()[i + 1]->portals().at(5));
0388     samePortalY2 =
0389         samePortalY2 && (detector->volumes()[5 + i]->portals().at(5) ==
0390                          detector->volumes()[5 + i + 1]->portals().at(5));
0391   }
0392   BOOST_CHECK_EQUAL(samePortalY1, true);
0393   BOOST_CHECK_EQUAL(samePortalY2, true);
0394 
0395   // Volumes should be connected in Z-direction
0396   for (int i = 0; i < 4; i++) {
0397     bool samePortalZ1 = (detector->volumes()[i]->portals().at(1) ==
0398                          detector->volumes()[i + 1]->portals().at(0));
0399     bool samePortalZ2 = (detector->volumes()[5 + i]->portals().at(1) ==
0400                          detector->volumes()[5 + i + 1]->portals().at(0));
0401 
0402     BOOST_CHECK_EQUAL(samePortalZ1, true);
0403     BOOST_CHECK_EQUAL(samePortalZ2, true);
0404   }
0405 
0406   // Volumes should be connected in X-direction
0407   for (int i = 0; i < 5; i++) {
0408     bool samePortalX = (detector->volumes()[i]->portals().at(3) ==
0409                         detector->volumes()[5 + i]->portals().at(2));
0410     BOOST_CHECK_EQUAL(samePortalX, true);
0411   }
0412 }
0413 
0414 BOOST_AUTO_TEST_SUITE_END()