File indexing completed on 2026-06-28 07:35:02
0001
0002
0003
0004
0005
0006
0007
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
0042 m_volumeID = GeometryIdentifier().withVolume(m_volumeID.volume() + 1);
0043
0044 m_iboundary = 0;
0045
0046 m_ilayer = 0;
0047
0048
0049 ACTS_VERBOSE("~> volumeID: " << m_volumeID);
0050 volume.assignGeometryId(m_volumeID);
0051
0052
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
0072 auto& bSurface = boundary.surfaceRepresentation();
0073
0074 m_iboundary += 1;
0075 auto boundaryID = GeometryIdentifier(m_volumeID).withBoundary(m_iboundary);
0076 ACTS_VERBOSE("~> boundaryID: " << boundaryID);
0077
0078 auto& mutableBSurface = *(const_cast<RegularSurface*>(&bSurface));
0079
0080
0081 ACTS_VERBOSE("~> assigning boundaryID: " << boundaryID);
0082 mutableBSurface.assignGeometryId(boundaryID);
0083
0084
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
0095 m_ilayer += 1;
0096 auto layerID = GeometryIdentifier(m_volumeID).withLayer(m_ilayer);
0097 ACTS_VERBOSE("~> layerID: " << layerID);
0098
0099
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
0174
0175
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
0199
0200
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 }
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 }