Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:23:42

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 "ActsExamples/GeoModelDetector/GeoModelMuonMockupBuilder.hpp"
0010 
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Geometry/Blueprint.hpp"
0013 #include "Acts/Geometry/ContainerBlueprintNode.hpp"
0014 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0015 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0016 #include "Acts/Geometry/GeometryContext.hpp"
0017 #include "Acts/Geometry/MultiWireVolumeBuilder.hpp"
0018 #include "Acts/Geometry/TrackingVolume.hpp"
0019 #include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
0020 #include "Acts/Geometry/VolumeAttachmentStrategy.hpp"
0021 #include "Acts/Geometry/VolumeBounds.hpp"
0022 #include "Acts/Geometry/detail/TrackingGeometryPrintVisitor.hpp"
0023 #include "Acts/Surfaces/LineBounds.hpp"
0024 #include "Acts/Utilities/AxisDefinitions.hpp"
0025 #include "Acts/Utilities/MathHelpers.hpp"
0026 
0027 #include <format>
0028 #include <typeinfo>
0029 using namespace Acts::UnitLiterals;
0030 using namespace Acts::Experimental;
0031 
0032 namespace ActsExamples {
0033 
0034 GeoModelMuonMockupBuilder::GeoModelMuonMockupBuilder(
0035     const Config& cfg, std::unique_ptr<const Acts::Logger> logger)
0036     : m_cfg(cfg), m_logger(std::move(logger)) {}
0037 
0038 std::unique_ptr<const Acts::TrackingGeometry>
0039 GeoModelMuonMockupBuilder::trackingGeometry(
0040     const Acts::GeometryContext& gctx) const {
0041   ConvertedVolList_t boundingBoxes = m_cfg.volumeBoxFPVs;
0042 
0043   // Blue print construction for the tracking geometry
0044   Acts::Experimental::Blueprint::Config bpCfg;
0045   bpCfg.envelope[Acts::AxisDirection::AxisZ] = {20_mm, 20_mm};
0046   bpCfg.envelope[Acts::AxisDirection::AxisR] = {5008.87000_mm, 12_mm};
0047   Acts::Experimental::Blueprint root{bpCfg};
0048   auto& cyl = root.addCylinderContainer("MuonMockupBarrelContainer",
0049                                         Acts::AxisDirection::AxisR);
0050   cyl.setAttachmentStrategy(Acts::VolumeAttachmentStrategy::Gap);
0051   cyl.setResizeStrategy(Acts::VolumeResizeStrategy::Gap);
0052 
0053   if (boundingBoxes.empty()) {
0054     throw std::invalid_argument(
0055         "GeoModelMuonMockupBuilder() -- No converted bounding boxes in the "
0056         "configuration - provide volumes "
0057         "(e.g from the GeModelDetectorObjectFactory) ");
0058   }
0059 
0060   // Add the station nodes as static cylidner nodes
0061   std::size_t layerId = 1;
0062 
0063   for (const auto& str : m_cfg.stationNames) {
0064     auto geoIdNode = Acts::GeometryIdentifier().withLayer(layerId);
0065     ++layerId;
0066     auto node = buildBarrelNode(boundingBoxes, str, *m_cfg.volumeBoundFactory,
0067                                 geoIdNode);
0068     cyl.addChild(std::move(node));
0069   }
0070 
0071   auto trackingGeometry = root.construct({}, gctx, *m_logger);
0072   if (logger().doPrint(Acts::Logging::Level::DEBUG)) {
0073     Acts::detail::TrackingGeometryPrintVisitor trkGeoPrinter{gctx};
0074     trackingGeometry->apply(trkGeoPrinter);
0075     ACTS_DEBUG(std::endl << trkGeoPrinter.stream().str());
0076   }
0077 
0078   return trackingGeometry;
0079 }
0080 
0081 std::shared_ptr<Acts::Experimental::StaticBlueprintNode>
0082 GeoModelMuonMockupBuilder::buildBarrelNode(
0083     const ConvertedVolList_t& boundingBoxes, const std::string& name,
0084     Acts::VolumeBoundFactory& boundFactory,
0085     const Acts::GeometryIdentifier& geoId) const {
0086   using enum Acts::CuboidVolumeBounds::BoundValues;
0087 
0088   /** Assume a station paradigm. MDT multilayers and complementary strip
0089    * detectors are residing under a common parent node representing a muon
0090    * station envelope. Group the passed boxes under by their parent */
0091   std::map<const GeoVPhysVol*, ConvertedVolList_t> commonStations{};
0092   for (const auto& box : boundingBoxes) {
0093     ACTS_VERBOSE("Test whether " << box.name << " contains '" << name
0094                                  << "' as substring");
0095     if (box.name.find(name) == std::string::npos) {
0096       continue;  // skip boxes that do not match the station name
0097     }
0098     auto parent = box.fullPhysVol->getParent().get();
0099 
0100     if (parent == nullptr) {
0101       throw std::domain_error("buildBarrelNode() No parent found for " + name);
0102     }
0103     commonStations[parent].push_back(box);
0104   }
0105   // Create a vector to hold the chambers and inner volumes
0106   std::vector<std::unique_ptr<Acts::TrackingVolume>> volChambers;
0107   std::vector<
0108       std::vector<std::shared_ptr<Acts::Experimental::StaticBlueprintNode>>>
0109       innerVolumesNodes;
0110   innerVolumesNodes.resize(commonStations.size());
0111 
0112   if (commonStations.empty()) {
0113     throw std::invalid_argument("No barrel stations could be found.");
0114   }
0115   volChambers.reserve(commonStations.size());
0116   std::size_t stationNum = 1;
0117   double maxZ = std::numeric_limits<double>::lowest();
0118   for (const auto& [parentPhysVol, childrenTrkVols] : commonStations) {
0119     std::shared_ptr<Acts::Volume> parentVolume =
0120         ActsPlugins::GeoModel::convertVolume(
0121             ActsPlugins::GeoModel::volumePosInSpace(parentPhysVol),
0122             parentPhysVol->getLogVol()->getShape(), boundFactory);
0123 
0124     auto chamberVolume = std::make_unique<Acts::TrackingVolume>(
0125         *parentVolume, std::format("{:}_Chamber_{:d}", name, stationNum));
0126     chamberVolume->assignGeometryId(geoId.withVolume(stationNum));
0127 
0128     ACTS_VERBOSE("Boundaries of the chamber volume: "
0129                  << chamberVolume->boundarySurfaces().size());
0130 
0131     std::size_t childVol = 1;
0132     auto chamberId = chamberVolume->geometryId();
0133 
0134     for (auto& child : childrenTrkVols) {
0135       std::unique_ptr<Acts::TrackingVolume> trVol{nullptr};
0136 
0137       // use dedicated builder for MDT multilayers
0138       if (child.name.find("MDT") != std::string::npos) {
0139         MultiWireVolumeBuilder::Config mwCfg;
0140         auto vb = child.volume->volumeBoundsPtr();
0141         double halfY{0};
0142         double halfZ{0};
0143         using LineBounds = Acts::LineBounds::BoundValues;
0144 
0145         if (vb->type() == Acts::VolumeBounds::eTrapezoid) {
0146           using BoundVal = Acts::TrapezoidVolumeBounds::BoundValues;
0147 
0148           auto tzb = std::dynamic_pointer_cast<Acts::TrapezoidVolumeBounds>(vb);
0149           mwCfg.bounds = boundFactory.insert(tzb);
0150           halfY = tzb->get(BoundVal::eHalfLengthY);
0151           halfZ = tzb->get(BoundVal::eHalfLengthZ);
0152 
0153         } else if (vb->type() == Acts::VolumeBounds::eCuboid) {
0154           using BoundVal = Acts::CuboidVolumeBounds::BoundValues;
0155 
0156           auto cbb = std::dynamic_pointer_cast<Acts::CuboidVolumeBounds>(vb);
0157           mwCfg.bounds = boundFactory.insert(cbb);
0158 
0159           halfY = cbb->get(BoundVal::eHalfLengthY);
0160           halfZ = cbb->get(BoundVal::eHalfLengthZ);
0161 
0162         } else {
0163           throw std::runtime_error(
0164               "GeoModelMuonMockupBuilder::buildBarrelNode() - Not a trapezoid "
0165               "or cuboid volume bounds");
0166         }
0167 
0168         mwCfg.name = child.name;
0169         mwCfg.mlSurfaces = child.surfaces;
0170         mwCfg.transform = child.volume->transform();
0171         auto& sb = child.surfaces.front()->bounds();
0172         auto lineBounds = dynamic_cast<const Acts::LineBounds*>(&sb);
0173         if (lineBounds == nullptr) {
0174           throw std::runtime_error(
0175               "This MDT does not have tubes, what does it have?");
0176         }
0177         double tubeR = lineBounds->get(LineBounds::eR);
0178         mwCfg.binning = {
0179             {{Acts::AxisDirection::AxisY, Acts::AxisBoundaryType::Bound, -halfY,
0180               halfY, static_cast<std::size_t>(std::lround(1. * halfY / tubeR))},
0181              2},
0182             {{Acts::AxisDirection::AxisZ, Acts::AxisBoundaryType::Bound, -halfZ,
0183               halfZ, static_cast<std::size_t>(std::lround(1. * halfZ / tubeR))},
0184              1}};
0185 
0186         MultiWireVolumeBuilder mdtBuilder{mwCfg};
0187         trVol = mdtBuilder.buildVolume();
0188 
0189       } else {
0190         trVol =
0191             std::make_unique<Acts::TrackingVolume>(*child.volume, child.name);
0192         trVol->assignGeometryId(chamberId.withExtra(childVol));
0193 
0194         // add the sensitives (tubes) in the constructed tracking volume
0195         for (const auto& surface : child.surfaces) {
0196           trVol->addSurface(surface);
0197         }
0198       }
0199 
0200       trVol->assignGeometryId(chamberId.withExtra(childVol));
0201       ++childVol;
0202 
0203       auto innerNode =
0204           std::make_shared<Acts::Experimental::StaticBlueprintNode>(
0205               std::move(trVol));
0206 
0207       innerVolumesNodes[stationNum - 1].push_back(std::move(innerNode));
0208     }
0209     volChambers.push_back(std::move(chamberVolume));
0210     maxZ = std::max(
0211         maxZ, std::abs(volChambers.back()->center().z()) +
0212                   volChambers.back()->volumeBounds().values()[eHalfLengthY]);
0213     ++stationNum;
0214   }
0215 
0216   const Acts::Vector3& cent{volChambers.front()->center()};
0217   double rmincyl = Acts::fastHypot(cent.x(), cent.y()) -
0218                    volChambers.front()->volumeBounds().values()[eHalfLengthZ];
0219   double rmaxcyl = Acts::fastHypot(
0220       rmincyl + 2 * volChambers.front()->volumeBounds().values()[eHalfLengthZ],
0221       volChambers.front()->volumeBounds().values()[eHalfLengthX]);
0222   double halfZ = maxZ;
0223 
0224   // Create the barrel node with the attached cylinder volume
0225   auto barrelNode = std::make_shared<Acts::Experimental::StaticBlueprintNode>(
0226       std::make_unique<Acts::TrackingVolume>(
0227           Acts::Transform3::Identity(),
0228           std::make_shared<Acts::CylinderVolumeBounds>(rmincyl, rmaxcyl, halfZ),
0229           std::format("{:}_Barrel", name)));
0230 
0231   // create the bluprint nodes for the chambers and add them as children to the
0232   // cylinder barrel node
0233   for (std::size_t chamberNum = 0; chamberNum < volChambers.size();
0234        ++chamberNum) {
0235     auto chamberNode =
0236         std::make_shared<Acts::Experimental::StaticBlueprintNode>(
0237             std::move(volChambers[chamberNum]));
0238 
0239     for (auto& innerVolNode : innerVolumesNodes[chamberNum]) {
0240       chamberNode->addChild(std::move(innerVolNode));
0241     }
0242 
0243     barrelNode->addChild(std::move(chamberNode));
0244   }
0245 
0246   return barrelNode;
0247 }
0248 
0249 }  // namespace ActsExamples