Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:11:16

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