Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-25 07:33:41

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 #pragma once
0010 
0011 #include "Acts/Utilities/OstreamFormatter.hpp"
0012 
0013 #include <cstdint>
0014 #include <functional>
0015 #include <iosfwd>
0016 #include <stdexcept>
0017 
0018 namespace Acts {
0019 
0020 class Surface;
0021 
0022 /// Identifier for geometry nodes within the geometry hierarchy.
0023 ///
0024 /// An identifier can be split into the following components. They define
0025 /// a hierarchy of objects starting from the high-level volumes:
0026 ///
0027 /// - Volume
0028 /// - Boundary surfaces (for a volume)
0029 /// - Layers (confined within a volume)
0030 /// - Approach surfaces (for a layer)
0031 /// - Sensitive surfaces (confined to a layer, also called modules)
0032 ///
0033 class GeometryIdentifier {
0034  public:
0035   /// Type alias for underlying value type (64-bit unsigned integer)
0036   using Value = std::uint64_t;
0037 
0038   /// Construct from an already encoded value.
0039   /// @param encoded The encoded geometry identifier value
0040   explicit constexpr GeometryIdentifier(Value encoded) : m_value(encoded) {}
0041   /// Construct default GeometryIdentifier with all values set to zero.
0042   GeometryIdentifier() = default;
0043   /// Move constructor
0044   GeometryIdentifier(GeometryIdentifier&&) = default;
0045   /// Copy constructor
0046   GeometryIdentifier(const GeometryIdentifier&) = default;
0047   ~GeometryIdentifier() = default;
0048   /// Move assignment operator
0049   /// @return Reference to this GeometryIdentifier after moving
0050   GeometryIdentifier& operator=(GeometryIdentifier&&) = default;
0051   /// Copy assignment operator
0052   /// @return Reference to this GeometryIdentifier after copying
0053   GeometryIdentifier& operator=(const GeometryIdentifier&) = default;
0054 
0055   /// Return the encoded value.
0056   /// @return The full encoded 64-bit geometry identifier value
0057   constexpr Value value() const { return m_value; }
0058 
0059   /// Return the volume identifier.
0060   /// @return The volume identifier component
0061   constexpr Value volume() const { return getBits(kVolumeMask); }
0062 
0063   /// Return the boundary identifier.
0064   /// @return The boundary identifier component
0065   constexpr Value boundary() const { return getBits(kBoundaryMask); }
0066 
0067   /// Return the layer identifier.
0068   /// @return The layer identifier component
0069   constexpr Value layer() const { return getBits(kLayerMask); }
0070 
0071   /// Return the approach identifier.
0072   /// @return The approach identifier component
0073   constexpr Value approach() const { return getBits(kApproachMask); }
0074 
0075   /// Return the passive identifier.
0076   /// @return The passive identifier component (shares bit field with approach)
0077   constexpr Value passive() const { return getBits(kApproachMask); }
0078 
0079   /// Return the sensitive identifier.
0080   /// @return The sensitive identifier component
0081   constexpr Value sensitive() const { return getBits(kSensitiveMask); }
0082 
0083   /// Return the extra identifier
0084   /// Usage can be experiment-specific, like tagging which kind of detector a
0085   /// surface object corresponds to, or which subsystem it belongs to
0086   /// @return The extra identifier component for experiment-specific use
0087   constexpr Value extra() const { return getBits(kExtraMask); }
0088 
0089   /// Return a new identifier with the volume set to @p volume
0090   /// @param volume the new volume identifier
0091   /// @return a new identifier with the volume set to @p volume
0092   [[nodiscard]]
0093   constexpr GeometryIdentifier withVolume(Value volume) const {
0094     GeometryIdentifier id = *this;
0095     id.setBits(kVolumeMask, volume);
0096     return id;
0097   }
0098 
0099   /// Return a new identifier with the boundary set to @p boundary
0100   /// @param boundary the new boundary identifier
0101   /// @return a new identifier with the boundary set to @p boundary
0102   [[nodiscard]]
0103   constexpr GeometryIdentifier withBoundary(Value boundary) const {
0104     GeometryIdentifier id = *this;
0105     id.setBits(kBoundaryMask, boundary);
0106     return id;
0107   }
0108 
0109   /// Return a new identifier with the layer set to @p layer
0110   /// @param layer the new layer identifier
0111   /// @return a new identifier with the layer set to @p layer
0112   [[nodiscard]]
0113   constexpr GeometryIdentifier withLayer(Value layer) const {
0114     GeometryIdentifier id = *this;
0115     id.setBits(kLayerMask, layer);
0116     return id;
0117   }
0118 
0119   /// Return a new identifier with the approach set to @p approach
0120   /// @param approach the new approach identifier
0121   /// @return a new identifier with the approach set to @p approach
0122   [[nodiscard]]
0123   constexpr GeometryIdentifier withApproach(Value approach) const {
0124     GeometryIdentifier id = *this;
0125     id.setBits(kApproachMask, approach);
0126     return id;
0127   }
0128 
0129   /// Return a new identifier with the passive set to @p passive
0130   /// @param passive the new passive identifier
0131   /// @return a new identifier with the passive set to @p passive
0132   [[nodiscard]]
0133   constexpr GeometryIdentifier withPassive(Value passive) const {
0134     GeometryIdentifier id = *this;
0135     id.setBits(kApproachMask, passive);
0136     return id;
0137   }
0138 
0139   /// Return a new identifier with the sensitive set to @p sensitive
0140   /// @param sensitive the new sensitive identifier
0141   /// @return a new identifier with the sensitive set to @p sensitive
0142   [[nodiscard]]
0143   constexpr GeometryIdentifier withSensitive(Value sensitive) const {
0144     GeometryIdentifier id = *this;
0145     id.setBits(kSensitiveMask, sensitive);
0146     return id;
0147   }
0148 
0149   /// Return a new identifier with the extra set to @p extra
0150   /// @param extra the new extra identifier
0151   /// @return a new identifier with the extra set to @p extra
0152   [[nodiscard]]
0153   constexpr GeometryIdentifier withExtra(Value extra) const {
0154     GeometryIdentifier id = *this;
0155     id.setBits(kExtraMask, extra);
0156     return id;
0157   }
0158 
0159   /// Get the maximum value for the volume identifier.
0160   /// @return the maximum value for the volume identifier
0161   static constexpr Value getMaxVolume() { return getMaxValue(kVolumeMask); }
0162 
0163   /// Get the maximum value for the boundary identifier.
0164   /// @return the maximum value for the boundary identifier
0165   static constexpr Value getMaxBoundary() { return getMaxValue(kBoundaryMask); }
0166 
0167   /// Get the maximum value for the layer identifier.
0168   /// @return the maximum value for the layer identifier
0169   static constexpr Value getMaxLayer() { return getMaxValue(kLayerMask); }
0170 
0171   /// Get the maximum value for the approach identifier.
0172   /// @return the maximum value for the approach identifier
0173   static constexpr Value getMaxApproach() { return getMaxValue(kApproachMask); }
0174 
0175   /// Get the maximum value for the sensitive identifier.
0176   /// @return the maximum value for the sensitive identifier
0177   static constexpr Value getMaxSensitive() {
0178     return getMaxValue(kSensitiveMask);
0179   }
0180 
0181   /// Get the maximum value for the extra identifier.
0182   /// @return the maximum value for the extra identifier
0183   static constexpr Value getMaxExtra() { return getMaxValue(kExtraMask); }
0184 
0185  private:
0186   // clang-format off
0187   /// (2^8)-1 = 255 volumes
0188   static constexpr Value kVolumeMask    = 0xff00000000000000;
0189   /// (2^8)-1 = 255 boundaries
0190   static constexpr Value kBoundaryMask  = 0x00ff000000000000;
0191   /// (2^12)-1 = 4095 layers
0192   static constexpr Value kLayerMask     = 0x0000fff000000000;
0193   /// (2^8)-1 = 255 approach surfaces
0194   static constexpr Value kApproachMask  = 0x0000000ff0000000;
0195   /// (2^20)-1 = 1048575 sensitive surfaces
0196   static constexpr Value kSensitiveMask = 0x000000000fffff00;
0197   /// (2^8)-1 = 255 extra values
0198   static constexpr Value kExtraMask     = 0x00000000000000ff;
0199   // clang-format on
0200 
0201   Value m_value = 0;
0202 
0203   /// Extract the bit shift necessary to access the masked values.
0204   static constexpr int extractShift(Value mask) {
0205     // use compiler builtin to extract the number of trailing bits from the
0206     // mask. the builtin should be available on all supported compilers.
0207     // need unsigned long long version (...ll) to ensure std::uint64_t
0208     // compatibility.
0209     // WARNING undefined behaviour for mask == 0 which we should not have.
0210     return __builtin_ctzll(mask);
0211   }
0212 
0213   constexpr static Value getMaxValue(Value mask) {
0214     return mask >> extractShift(mask);
0215   }
0216 
0217   /// Extract the masked bits from the encoded value.
0218   constexpr Value getBits(Value mask) const {
0219     return (m_value & mask) >> extractShift(mask);
0220   }
0221   /// Set the masked bits to id in the encoded value.
0222   constexpr GeometryIdentifier& setBits(Value mask, Value id) {
0223     if (id > getMaxValue(mask)) {
0224       throw std::invalid_argument(
0225           "Value " + std::to_string(id) + " exceeds maximum value " +
0226           std::to_string(getMaxValue(mask)) + " for this field");
0227     }
0228 
0229     m_value = (m_value & ~mask) | ((id << extractShift(mask)) & mask);
0230     // return *this here that we need to write fewer lines in the setXXX
0231     // methods
0232     return *this;
0233   }
0234 
0235   friend constexpr bool operator==(GeometryIdentifier lhs,
0236                                    GeometryIdentifier rhs) {
0237     return lhs.m_value == rhs.m_value;
0238   }
0239 
0240   friend constexpr bool operator<(GeometryIdentifier lhs,
0241                                   GeometryIdentifier rhs) {
0242     return lhs.m_value < rhs.m_value;
0243   }
0244 };
0245 
0246 /// Stream operator for GeometryIdentifier
0247 /// @param os Output stream
0248 /// @param id GeometryIdentifier to output
0249 /// @return Reference to output stream
0250 std::ostream& operator<<(std::ostream& os, GeometryIdentifier id);
0251 
0252 /// Base class for hooks that can be used to modify the Geometry Identifier
0253 /// during construction. Most common use case is setting the extra bit fields.
0254 struct GeometryIdentifierHook {
0255   virtual ~GeometryIdentifierHook() = default;
0256   /// Decorate a geometry identifier with additional information from a surface
0257   /// @param identifier Base geometry identifier to decorate
0258   /// @param surface Surface providing additional context for decoration
0259   /// @return Decorated geometry identifier with surface-specific information
0260   virtual Acts::GeometryIdentifier decorateIdentifier(
0261       Acts::GeometryIdentifier identifier, const Acts::Surface& surface) const;
0262 };
0263 
0264 }  // namespace Acts
0265 
0266 // specialize std::hash so GeometryIdentifier can be used e.g. in an
0267 // unordered_map
0268 namespace std {
0269 template <>
0270 struct hash<Acts::GeometryIdentifier> {
0271   auto operator()(Acts::GeometryIdentifier gid) const noexcept {
0272     return std::hash<Acts::GeometryIdentifier::Value>()(gid.value());
0273   }
0274 };
0275 }  // namespace std
0276 
0277 // specialize std::formatter so GeometryIdentifier can be used with std::format
0278 ACTS_OSTREAM_FORMATTER(Acts::GeometryIdentifier);