File indexing completed on 2025-12-16 09:23:42
0001
0002
0003
0004
0005
0006
0007
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
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
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
0089
0090
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;
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
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
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
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
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
0232
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 }