Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-26 07:54:35

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