Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-28 07:35:02

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 "Acts/Geometry/TrackingGeometry.hpp"
0010 
0011 #include "Acts/Definitions/Tolerance.hpp"
0012 #include "Acts/Geometry/GeometryContext.hpp"
0013 #include "Acts/Geometry/GeometryIdentifier.hpp"
0014 #include "Acts/Geometry/GeometryObject.hpp"
0015 #include "Acts/Geometry/Portal.hpp"
0016 #include "Acts/Geometry/TrackingGeometryVisitor.hpp"
0017 #include "Acts/Geometry/TrackingVolume.hpp"
0018 #include "Acts/Material/ProtoVolumeMaterial.hpp"
0019 #include "Acts/Surfaces/Surface.hpp"
0020 
0021 #include <cstddef>
0022 
0023 namespace Acts {
0024 
0025 class Gen1GeometryClosureVisitor : public TrackingGeometryMutableVisitor {
0026  public:
0027   Gen1GeometryClosureVisitor(const Logger& logger,
0028                              const IMaterialDecorator* materialDecorator,
0029                              const GeometryIdentifierHook& hook)
0030       : m_logger(&logger),
0031         m_materialDecorator(materialDecorator),
0032         m_hook(&hook) {
0033     ACTS_VERBOSE("Creating Gen1GeometryClosureVisitor");
0034   }
0035 
0036   const Logger& logger() const { return *m_logger; }
0037 
0038   void visitVolume(TrackingVolume& volume) override {
0039     ACTS_DEBUG("Volume: " << volume.volumeName());
0040 
0041     // Increment the volume ID for this volume
0042     m_volumeID = GeometryIdentifier().withVolume(m_volumeID.volume() + 1);
0043     // Reset boundary id for this volume
0044     m_iboundary = 0;
0045     // Reset layer id for this volume
0046     m_ilayer = 0;
0047 
0048     // assign the Volume ID to the volume itself
0049     ACTS_VERBOSE("~> volumeID: " << m_volumeID);
0050     volume.assignGeometryId(m_volumeID);
0051 
0052     // assign the material if you have a decorator
0053     if (m_materialDecorator != nullptr) {
0054       ACTS_VERBOSE("Decorating volume " << volume.volumeName()
0055                                         << " with material");
0056       m_materialDecorator->decorate(volume);
0057     }
0058     if (!volume.hasMaterial() && volume.motherVolume() != nullptr &&
0059         volume.motherVolume()->hasMaterial()) {
0060       auto protoMaterial = dynamic_cast<const ProtoVolumeMaterial*>(
0061           volume.motherVolume()->volumeMaterial());
0062       if (protoMaterial == nullptr) {
0063         volume.assignVolumeMaterial(volume.motherVolume()->volumeMaterialPtr());
0064       }
0065     }
0066   }
0067 
0068   void visitBoundarySurface(
0069       BoundarySurfaceT<TrackingVolume>& boundary) override {
0070     ACTS_DEBUG("BoundarySurface: " << boundary.surfaceRepresentation().name());
0071     // get the intersection solution
0072     auto& bSurface = boundary.surfaceRepresentation();
0073     // create the boundary surface id
0074     m_iboundary += 1;
0075     auto boundaryID = GeometryIdentifier(m_volumeID).withBoundary(m_iboundary);
0076     ACTS_VERBOSE("~> boundaryID: " << boundaryID);
0077     // now assign to the boundary surface
0078     auto& mutableBSurface = *(const_cast<RegularSurface*>(&bSurface));
0079 
0080     // assign the boundary ID to the surface
0081     ACTS_VERBOSE("~> assigning boundaryID: " << boundaryID);
0082     mutableBSurface.assignGeometryId(boundaryID);
0083 
0084     // Assign material if you have a decorator
0085     if (m_materialDecorator != nullptr) {
0086       ACTS_VERBOSE("Decorating boundary surface " << bSurface.name()
0087                                                   << " with material");
0088       m_materialDecorator->decorate(mutableBSurface);
0089     }
0090   }
0091 
0092   void visitLayer(Layer& layer) override {
0093     ACTS_DEBUG("Close Layer");
0094     // create the layer identification
0095     m_ilayer += 1;
0096     auto layerID = GeometryIdentifier(m_volumeID).withLayer(m_ilayer);
0097     ACTS_VERBOSE("~> layerID: " << layerID);
0098 
0099     // now close the geometry
0100     layer.closeGeometry(m_materialDecorator, layerID, *m_hook, *m_logger);
0101   }
0102 
0103   const Logger* m_logger;
0104   GeometryIdentifier m_volumeID;
0105   GeometryIdentifier::Value m_iboundary = 0;
0106   GeometryIdentifier::Value m_ilayer = 0;
0107   const IMaterialDecorator* m_materialDecorator = nullptr;
0108   const GeometryIdentifierHook* m_hook = nullptr;
0109 
0110   std::unordered_map<GeometryIdentifier, const TrackingVolume*> m_volumesById{};
0111   std::unordered_map<GeometryIdentifier, const Surface*> m_surfacesById{};
0112 };
0113 
0114 namespace {
0115 class GeometryIdMapVisitor : public TrackingGeometryVisitor {
0116  private:
0117   void checkIdentifier(const GeometryObject& obj, std::string_view type) {
0118     if (obj.geometryId() == GeometryIdentifier{}) {
0119       std::stringstream ss;
0120       ss << "Encountered " << type << " with no geometry ID";
0121       throw std::invalid_argument(ss.str());
0122     }
0123 
0124     ACTS_VERBOSE("Checking identifier for " << type << ": "
0125                                             << obj.geometryId());
0126 
0127     auto [it, inserted] = m_objectsById.emplace(obj.geometryId(), &obj);
0128 
0129     if (!inserted && it->second != &obj) {
0130       std::stringstream ss;
0131       ss << "Duplicate " << type << " ID: " << obj.geometryId() << ": & "
0132          << it->second << " != " << &obj;
0133       if (const auto* other = dynamic_cast<const TrackingVolume*>(it->second);
0134           other != nullptr) {
0135         ss << " (" << other->volumeName() << ")";
0136       }
0137       ACTS_ERROR(ss.str());
0138       throw std::invalid_argument(ss.str());
0139     } else {
0140       ACTS_VERBOSE("Inserted " << type << " ID: " << obj.geometryId()
0141                                << " pointing at " << &obj);
0142     }
0143   }
0144 
0145   const Logger& logger() const { return m_logger; }
0146   const Logger& m_logger;
0147 
0148  public:
0149   explicit GeometryIdMapVisitor(const Logger& logger) : m_logger(logger) {}
0150 
0151   void visitVolume(const TrackingVolume& volume) override {
0152     std::string label = "volume(" + volume.volumeName() + ")";
0153     checkIdentifier(volume, label);
0154 
0155     m_volumesById.emplace(volume.geometryId(), &volume);
0156   }
0157 
0158   void visitSurface(const Surface& surface) override {
0159     if (surface.geometryId() == GeometryIdentifier{}) {
0160       std::cout << "Surface has no geometry ID: "
0161                 << surface.toStream(
0162                        GeometryContext::dangerouslyDefaultConstruct())
0163                 << std::endl;
0164       throw std::invalid_argument("Surface has no geometry ID");
0165     }
0166 
0167     checkIdentifier(surface, "surface");
0168 
0169     m_surfacesById.emplace(surface.geometryId(), &surface);
0170   }
0171 
0172   void visitLayer(const Layer& layer) override {
0173     // Layers ARE also GeometryObjects and have IDs.
0174     // Let's check that the layer has the same ID as it's surface
0175     // representation. Uniqueness of the surface IDs is checked in the surface
0176     if (layer.geometryId() != layer.surfaceRepresentation().geometryId()) {
0177       ACTS_ERROR("Layer ID mismatch: "
0178                  << layer.geometryId()
0179                  << " != " << layer.surfaceRepresentation().geometryId());
0180       throw std::invalid_argument("Layer ID mismatch");
0181     }
0182   }
0183 
0184   void visitBoundarySurface(
0185       const BoundarySurfaceT<TrackingVolume>& boundary) override {
0186     const auto& surface = boundary.surfaceRepresentation();
0187     checkIdentifier(surface, "boundary surface");
0188     m_surfacesById.emplace(surface.geometryId(), &surface);
0189   }
0190 
0191   void visitPortal(const Portal& portal) override {
0192     const auto& surface = portal.surface();
0193     checkIdentifier(surface, "portal");
0194     m_surfacesById.emplace(surface.geometryId(), &surface);
0195 
0196     for (const auto& tag : portal.tags()) {
0197       auto [it, inserted] = m_portalsByTag.try_emplace(tag, &portal);
0198       // A fused/merged portal is shared between volumes, so it is visited once
0199       // per owning volume slot. Re-inserting the same tag for the *same* portal
0200       // is fine; a different portal claiming the same tag is a collision.
0201       if (!inserted && it->second != &portal) {
0202         std::stringstream ss;
0203         ss << "Duplicate portal tag: " << tag;
0204         ACTS_ERROR(ss.str());
0205         throw std::invalid_argument(ss.str());
0206       }
0207     }
0208   }
0209 
0210   std::unordered_map<GeometryIdentifier, const TrackingVolume*> m_volumesById{};
0211   std::unordered_map<GeometryIdentifier, const Surface*> m_surfacesById{};
0212   detail::PortalTagMap m_portalsByTag{};
0213 
0214   std::unordered_map<GeometryIdentifier, const GeometryObject*> m_objectsById{};
0215 };
0216 
0217 }  // namespace
0218 TrackingGeometry::TrackingGeometry(
0219     const MutableTrackingVolumePtr& highestVolume,
0220     const IMaterialDecorator* materialDecorator,
0221     const GeometryIdentifierHook& hook, const Logger& logger, bool close)
0222     : m_world(highestVolume) {
0223   if (close) {
0224     ACTS_DEBUG("Closing tracking geometry with Gen1 assignment");
0225     Gen1GeometryClosureVisitor visitor{logger, materialDecorator, hook};
0226     apply(visitor);
0227   }
0228 
0229   GeometryIdMapVisitor mapVisitor{logger};
0230   apply(mapVisitor);
0231   m_volumesById = std::move(mapVisitor.m_volumesById);
0232   m_surfacesById = std::move(mapVisitor.m_surfacesById);
0233   m_portalsByTag = std::move(mapVisitor.m_portalsByTag);
0234 
0235   ACTS_DEBUG("TrackingGeometry created with "
0236              << m_volumesById.size() << " volumes and " << m_surfacesById.size()
0237              << " surfaces");
0238 
0239   m_volumesById.rehash(0);
0240   m_surfacesById.rehash(0);
0241   m_portalsByTag.rehash(0);
0242 }
0243 
0244 TrackingGeometry::~TrackingGeometry() = default;
0245 
0246 const TrackingVolume* TrackingGeometry::lowestTrackingVolume(
0247     const GeometryContext& gctx, const Vector3& gp) const {
0248   return m_world->lowestTrackingVolume(gctx, gp, s_onSurfaceTolerance);
0249 }
0250 
0251 const TrackingVolume* TrackingGeometry::highestTrackingVolume() const {
0252   return m_world.get();
0253 }
0254 
0255 TrackingVolume* TrackingGeometry::highestTrackingVolume() {
0256   return m_world.get();
0257 }
0258 
0259 std::shared_ptr<const TrackingVolume>
0260 TrackingGeometry::highestTrackingVolumePtr() const {
0261   return m_world;
0262 }
0263 
0264 const Layer* TrackingGeometry::associatedLayer(const GeometryContext& gctx,
0265                                                const Vector3& gp) const {
0266   const TrackingVolume* lowestVol = lowestTrackingVolume(gctx, gp);
0267   if (lowestVol == nullptr) {
0268     return nullptr;
0269   }
0270   return lowestVol->associatedLayer(gctx, gp);
0271 }
0272 
0273 const TrackingVolume* TrackingGeometry::findVolume(
0274     GeometryIdentifier id) const {
0275   auto vol = m_volumesById.find(id);
0276   if (vol == m_volumesById.end()) {
0277     return nullptr;
0278   }
0279   return vol->second;
0280 }
0281 
0282 const Surface* TrackingGeometry::findSurface(GeometryIdentifier id) const {
0283   auto srf = m_surfacesById.find(id);
0284   if (srf == m_surfacesById.end()) {
0285     return nullptr;
0286   }
0287   return srf->second;
0288 }
0289 
0290 const Portal* TrackingGeometry::findPortal(std::string_view tag) const {
0291   auto it = m_portalsByTag.find(tag);
0292   if (it == m_portalsByTag.end()) {
0293     return nullptr;
0294   }
0295   return it->second;
0296 }
0297 
0298 const std::unordered_map<GeometryIdentifier, const Surface*>&
0299 TrackingGeometry::geoIdSurfaceMap() const {
0300   return m_surfacesById;
0301 }
0302 
0303 void TrackingGeometry::visualize(IVisualization3D& helper,
0304                                  const GeometryContext& gctx,
0305                                  const ViewConfig& viewConfig,
0306                                  const ViewConfig& portalViewConfig,
0307                                  const ViewConfig& sensitiveViewConfig) const {
0308   highestTrackingVolume()->visualize(helper, gctx, viewConfig, portalViewConfig,
0309                                      sensitiveViewConfig);
0310 }
0311 
0312 void TrackingGeometry::apply(TrackingGeometryVisitor& visitor) const {
0313   highestTrackingVolume()->apply(visitor);
0314 }
0315 
0316 void TrackingGeometry::apply(TrackingGeometryMutableVisitor& visitor) {
0317   highestTrackingVolume()->apply(visitor);
0318 }
0319 
0320 TrackingGeometry::GeometryVersion TrackingGeometry::geometryVersion() const {
0321   if (highestTrackingVolume()->portals().empty()) {
0322     return GeometryVersion::Gen1;
0323   } else {
0324     return GeometryVersion::Gen3;
0325   }
0326 }
0327 
0328 }  // namespace Acts