Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:22:23

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   /// Return a new identifier with the volume set to @p volume
0088   /// @param volume the new volume identifier
0089   /// @return a new identifier with the volume set to @p volume
0090   [[nodiscard]]
0091   constexpr GeometryIdentifier withVolume(Value volume) const {
0092     GeometryIdentifier id = *this;
0093     id.setBits(kVolumeMask, volume);
0094     return id;
0095   }
0096 
0097   /// Return a new identifier with the boundary set to @p boundary
0098   /// @param boundary the new boundary identifier
0099   /// @return a new identifier with the boundary set to @p boundary
0100   [[nodiscard]]
0101   constexpr GeometryIdentifier withBoundary(Value boundary) const {
0102     GeometryIdentifier id = *this;
0103     id.setBits(kBoundaryMask, boundary);
0104     return id;
0105   }
0106 
0107   /// Return a new identifier with the layer set to @p layer
0108   /// @param layer the new layer identifier
0109   /// @return a new identifier with the layer set to @p layer
0110   [[nodiscard]]
0111   constexpr GeometryIdentifier withLayer(Value layer) const {
0112     GeometryIdentifier id = *this;
0113     id.setBits(kLayerMask, layer);
0114     return id;
0115   }
0116 
0117   /// Return a new identifier with the approach set to @p approach
0118   /// @param approach the new approach identifier
0119   /// @return a new identifier with the approach set to @p approach
0120   [[nodiscard]]
0121   constexpr GeometryIdentifier withApproach(Value approach) const {
0122     GeometryIdentifier id = *this;
0123     id.setBits(kApproachMask, approach);
0124     return id;
0125   }
0126 
0127   /// Return a new identifier with the passive set to @p passive
0128   /// @param passive the new passive identifier
0129   /// @return a new identifier with the passive set to @p passive
0130   [[nodiscard]]
0131   constexpr GeometryIdentifier withPassive(Value passive) const {
0132     GeometryIdentifier id = *this;
0133     id.setBits(kApproachMask, passive);
0134     return id;
0135   }
0136 
0137   /// Return a new identifier with the sensitive set to @p sensitive
0138   /// @param sensitive the new sensitive identifier
0139   /// @return a new identifier with the sensitive set to @p sensitive
0140   [[nodiscard]]
0141   constexpr GeometryIdentifier withSensitive(Value sensitive) const {
0142     GeometryIdentifier id = *this;
0143     id.setBits(kSensitiveMask, sensitive);
0144     return id;
0145   }
0146 
0147   /// Return a new identifier with the extra set to @p extra
0148   /// @param extra the new extra identifier
0149   /// @return a new identifier with the extra set to @p extra
0150   [[nodiscard]]
0151   constexpr GeometryIdentifier withExtra(Value extra) const {
0152     GeometryIdentifier id = *this;
0153     id.setBits(kExtraMask, extra);
0154     return id;
0155   }
0156 
0157   /// Get the maximum value for the volume identifier.
0158   /// @return the maximum value for the volume identifier
0159   static constexpr Value getMaxVolume() { return getMaxValue(kVolumeMask); }
0160 
0161   /// Get the maximum value for the boundary identifier.
0162   /// @return the maximum value for the boundary identifier
0163   static constexpr Value getMaxBoundary() { return getMaxValue(kBoundaryMask); }
0164 
0165   /// Get the maximum value for the layer identifier.
0166   /// @return the maximum value for the layer identifier
0167   static constexpr Value getMaxLayer() { return getMaxValue(kLayerMask); }
0168 
0169   /// Get the maximum value for the approach identifier.
0170   /// @return the maximum value for the approach identifier
0171   static constexpr Value getMaxApproach() { return getMaxValue(kApproachMask); }
0172 
0173   /// Get the maximum value for the sensitive identifier.
0174   /// @return the maximum value for the sensitive identifier
0175   static constexpr Value getMaxSensitive() {
0176     return getMaxValue(kSensitiveMask);
0177   }
0178 
0179   /// Get the maximum value for the extra identifier.
0180   /// @return the maximum value for the extra identifier
0181   static constexpr Value getMaxExtra() { return getMaxValue(kExtraMask); }
0182 
0183  private:
0184   // clang-format off
0185   /// (2^8)-1 = 255 volumes
0186   static constexpr Value kVolumeMask    = 0xff00000000000000;
0187   /// (2^8)-1 = 255 boundaries
0188   static constexpr Value kBoundaryMask  = 0x00ff000000000000;
0189   /// (2^12)-1 = 4095 layers
0190   static constexpr Value kLayerMask     = 0x0000fff000000000;
0191   /// (2^8)-1 = 255 approach surfaces
0192   static constexpr Value kApproachMask  = 0x0000000ff0000000;
0193   /// (2^20)-1 = 1048575 sensitive surfaces
0194   static constexpr Value kSensitiveMask = 0x000000000fffff00;
0195   /// (2^8)-1 = 255 extra values
0196   static constexpr Value kExtraMask     = 0x00000000000000ff;
0197   // clang-format on
0198 
0199   Value m_value = 0;
0200 
0201   /// Extract the bit shift necessary to access the masked values.
0202   static constexpr int extractShift(Value mask) {
0203     // use compiler builtin to extract the number of trailing bits from the
0204     // mask. the builtin should be available on all supported compilers.
0205     // need unsigned long long version (...ll) to ensure std::uint64_t
0206     // compatibility.
0207     // WARNING undefined behaviour for mask == 0 which we should not have.
0208     return __builtin_ctzll(mask);
0209   }
0210 
0211   constexpr static Value getMaxValue(Value mask) {
0212     return mask >> extractShift(mask);
0213   }
0214 
0215   /// Extract the masked bits from the encoded value.
0216   constexpr Value getBits(Value mask) const {
0217     return (m_value & mask) >> extractShift(mask);
0218   }
0219   /// Set the masked bits to id in the encoded value.
0220   constexpr GeometryIdentifier& setBits(Value mask, Value id) {
0221     if (id > getMaxValue(mask)) {
0222       throw std::invalid_argument(
0223           "Value " + std::to_string(id) + " exceeds maximum value " +
0224           std::to_string(getMaxValue(mask)) + " for this field");
0225     }
0226 
0227     m_value = (m_value & ~mask) | ((id << extractShift(mask)) & mask);
0228     // return *this here that we need to write fewer lines in the setXXX
0229     // methods
0230     return *this;
0231   }
0232 
0233   friend constexpr bool operator==(GeometryIdentifier lhs,
0234                                    GeometryIdentifier rhs) {
0235     return lhs.m_value == rhs.m_value;
0236   }
0237 
0238   friend constexpr bool operator<(GeometryIdentifier lhs,
0239                                   GeometryIdentifier rhs) {
0240     return lhs.m_value < rhs.m_value;
0241   }
0242 };
0243 
0244 /// Stream operator for GeometryIdentifier
0245 /// @param os Output stream
0246 /// @param id GeometryIdentifier to output
0247 /// @return Reference to output stream
0248 std::ostream& operator<<(std::ostream& os, GeometryIdentifier id);
0249 
0250 /// Base class for hooks that can be used to modify the Geometry Identifier
0251 /// during construction. Most common use case is setting the extra bit fields.
0252 struct GeometryIdentifierHook {
0253   virtual ~GeometryIdentifierHook() = default;
0254   /// Decorate a geometry identifier with additional information from a surface
0255   /// @param identifier Base geometry identifier to decorate
0256   /// @param surface Surface providing additional context for decoration
0257   /// @return Decorated geometry identifier with surface-specific information
0258   virtual Acts::GeometryIdentifier decorateIdentifier(
0259       Acts::GeometryIdentifier identifier, const Acts::Surface& surface) const;
0260 };
0261 
0262 }  // namespace Acts
0263 // specialize std::hash so GeometryIdentifier can be used e.g. in an
0264 // unordered_map
0265 namespace std {
0266 template <>
0267 struct hash<Acts::GeometryIdentifier> {
0268   auto operator()(Acts::GeometryIdentifier gid) const noexcept {
0269     return std::hash<Acts::GeometryIdentifier::Value>()(gid.value());
0270   }
0271 };
0272 }  // namespace std