Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-18 08:22:23

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