|
|
|||
File indexing completed on 2025-12-16 09:24:12
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 <span> 0013 #include <stdexcept> 0014 #include <string> 0015 #include <vector> 0016 0017 #include <boost/functional/hash.hpp> 0018 0019 namespace ActsFatras { 0020 0021 /// Particle identifier that encodes additional event information. 0022 /// 0023 /// The barcode has to fulfill two separate requirements: be able to act as 0024 /// unique identifier for particles within an event and to encode details 0025 /// on the event structure for fast lookup. Since we only care about tracking 0026 /// here, we need to support two scenarios: 0027 /// 0028 /// * Identify which primary/secondary vertex particles belong to. No 0029 /// information on intermediate/unstable/invisible particles needs to be 0030 /// retained. This information is already available in the underlying 0031 /// generator event and should not be duplicated. 0032 /// * If (visible) particles convert, decay, or interact with the detector, 0033 /// we need to be able to identify the initial (primary) particle. Typical 0034 /// examples are pion nuclear interactions or electron/gamma conversions. 0035 /// 0036 /// The vertex information is encoded as two numbers that define the 0037 /// primary and secondary vertex. The primary vertex must be non-zero. 0038 /// Particles with a zero secondary vertex originate directly from the primary 0039 /// vertex. 0040 /// 0041 /// Within one vertex (primary+secondary) each particle is identified by 0042 /// a particle, generation, and sub-particle number. Particles originating 0043 /// from the vertex must have zero generation and zero sub-particle number; 0044 /// a consequence is that only non-zero generation can have non-zero 0045 /// sub-particle numbers. A non-zero generation indicates that the particle 0046 /// is a descendant of the original particle, e.g. from interactions or decay, 0047 /// while the sub-particle number identifies the descendant particle. 0048 /// 0049 /// With this encoding, non-primary particles and their primary parent can 0050 /// be easily identified at the expense of not storing the exact decay history. 0051 /// 0052 /// A barcode with all elements set to zero (the default value) is an invalid 0053 /// value that can be used e.g. to mark missing or unknown particles. 0054 /// 0055 /// ## Example 0056 /// 0057 /// A particle generated in a primary interaction might have the barcode 0058 /// 0059 /// 2|0|14|0|0 -> vertex=2 (primary), particle=14, generation=0, sub=0 0060 /// 0061 /// A simulation module might generate an interaction and create two new 0062 /// particles. These are descendants of the initial particle and the simulation 0063 /// module can generate the new barcodes directly by increasing the 0064 /// generation number and choosing sub-particle identifiers: 0065 /// 0066 /// 2|0|14|1|0 -> vertex=2 (primary), particle=14, generation=1, sub=0 0067 /// 2|0|14|1|1 -> vertex=2 (primary), particle=14, generation=1, sub=1 0068 /// 0069 /// If these secondary particles generate further tertiary particles 0070 /// the barcode would be e.g. 0071 /// 0072 /// 2|0|14|2|0 -> vertex=2 (primary), particle=14, generation=2, sub=0 0073 /// 0074 /// ## Possible issues 0075 /// 0076 /// The hierarchical nature of the barcode allows barcode creation without 0077 /// a central service. Since the full history is not stored, generated barcodes 0078 /// for higher-generation particles can overlap when generated by independent 0079 /// interactions. Assuming an initial primary particle with barcode 0080 /// 0081 /// 3|4|5|0|0 -> particle=5 0082 /// 0083 /// a first interaction might create a secondary particle by increasing the 0084 /// generation number (without destroying the initial particle) 0085 /// 0086 /// 3|4|5|1|0 -> particle=5, generation+=1, first sub-particle 0087 /// 0088 /// The initial particle gets simulated further and at another step a second 0089 /// interaction also creates a new particle. Since it knows nothing about 0090 /// the previously created particle (no central service), it will generate 0091 /// 0092 /// 3|4|5|1|0 -> particle=5, generation+=1, first sub-particle 0093 /// 0094 /// which is identical to the previously create barcode. These cases can be 0095 /// easily solved by renumbering the sub-particle identifier within each 0096 /// generation to contain unique values. However, this can only be done when all 0097 /// particles are known. 0098 class Barcode { 0099 public: 0100 using PrimaryVertexId = std::uint16_t; 0101 using SecondaryVertexId = std::uint16_t; 0102 using ParticleId = std::uint32_t; 0103 using GenerationId = std::uint8_t; 0104 using SubParticleId = std::uint32_t; 0105 0106 // Construct an invalid barcode with all levels set to zero. 0107 static constexpr Barcode Invalid() { return Barcode(); } 0108 0109 /// Empty barcode 0110 constexpr Barcode() = default; 0111 /// Copy constructor 0112 constexpr Barcode(const Barcode&) = default; 0113 /// Move constructor 0114 constexpr Barcode(Barcode&&) = default; 0115 /// Copy assignment operator 0116 /// @return Reference to this barcode after copying 0117 Barcode& operator=(const Barcode&) = default; 0118 /// Move assignment operator 0119 /// @return Reference to this barcode after moving 0120 Barcode& operator=(Barcode&&) = default; 0121 0122 /// Compare two barcodes 0123 bool operator==(const Barcode&) const = default; 0124 friend constexpr auto operator<=>(Barcode lhs, Barcode rhs) { 0125 return lhs.asVector() <=> rhs.asVector(); 0126 } 0127 0128 /// Check validity of the barcode 0129 static constexpr bool isValid(const Barcode& b) { return b != Invalid(); } 0130 constexpr bool isValid() const { return isValid(*this); } 0131 0132 /// Return the primary vertex identifier. 0133 /// @return The primary vertex identifier value 0134 constexpr PrimaryVertexId vertexPrimary() const { return vertexPrimaryID; } 0135 0136 /// Return the secondary vertex identifier. 0137 /// @return The secondary vertex identifier value 0138 constexpr SecondaryVertexId vertexSecondary() const { 0139 return vertexSecondaryID; 0140 } 0141 0142 /// Return the particle identifier. 0143 /// @return The particle identifier value 0144 constexpr ParticleId particle() const { return particleID; } 0145 0146 /// Return the generation identifier. 0147 /// @return The generation identifier value 0148 constexpr GenerationId generation() const { return generationID; } 0149 0150 /// Return the sub-particle identifier. 0151 /// @return The sub-particle identifier value 0152 constexpr SubParticleId subParticle() const { return subParticleID; } 0153 0154 /// Export barcode as vector 0155 constexpr std::vector<std::uint32_t> asVector() const { 0156 return {vertexPrimary(), vertexSecondary(), particle(), generation(), 0157 subParticle()}; 0158 } 0159 0160 /// Create a new barcode with a different primary vertex identifier. 0161 /// @param id Primary vertex identifier to set 0162 /// @return New barcode with modified primary vertex identifier 0163 [[nodiscard]] 0164 constexpr Barcode withVertexPrimary(PrimaryVertexId id) const { 0165 Barcode barcode = *this; 0166 barcode.vertexPrimaryID = id; 0167 return barcode; 0168 } 0169 0170 /// Create a new barcode with a different secondary vertex identifier. 0171 /// @param id Secondary vertex identifier to set 0172 /// @return New barcode with modified secondary vertex identifier 0173 [[nodiscard]] 0174 constexpr Barcode withVertexSecondary(SecondaryVertexId id) const { 0175 Barcode barcode = *this; 0176 barcode.vertexSecondaryID = id; 0177 return barcode; 0178 } 0179 0180 /// Create a new barcode with a different particle identifier. 0181 /// @param id Particle identifier to set 0182 /// @return New barcode with modified particle identifier 0183 [[nodiscard]] 0184 constexpr Barcode withParticle(ParticleId id) const { 0185 Barcode barcode = *this; 0186 barcode.particleID = id; 0187 return barcode; 0188 } 0189 0190 /// Create a new barcode with a different generation identifier. 0191 /// @param id Generation identifier to set 0192 /// @return New barcode with modified generation identifier 0193 [[nodiscard]] 0194 constexpr Barcode withGeneration(GenerationId id) const { 0195 Barcode barcode = *this; 0196 barcode.generationID = id; 0197 return barcode; 0198 } 0199 0200 /// Create a new barcode with a different sub-particle identifier. 0201 /// @param id Sub-particle identifier to set 0202 /// @return New barcode with modified sub-particle identifier 0203 [[nodiscard]] 0204 constexpr Barcode withSubParticle(SubParticleId id) const { 0205 Barcode barcode = *this; 0206 barcode.subParticleID = id; 0207 return barcode; 0208 } 0209 0210 /// Create a new barcode from a vector 0211 /// @param data Vector containing exactly 5 elements 0212 /// @return New barcode with data from the vector 0213 [[nodiscard]] 0214 constexpr Barcode withData(std::span<std::uint32_t> data) { 0215 if (data.size() != 5) { 0216 throw std::invalid_argument( 0217 "Size of the data is " + std::to_string(data.size()) + 0218 " but Barcode requires data vector to have exactly 5 elements"); 0219 } 0220 0221 Barcode barcode = *this; 0222 barcode.vertexPrimaryID = data[0]; 0223 barcode.vertexSecondaryID = data[1]; 0224 barcode.particleID = data[2]; 0225 barcode.generationID = data[3]; 0226 barcode.subParticleID = data[4]; 0227 return barcode; 0228 } 0229 0230 /// Construct a new barcode representing a descendant particle. 0231 /// 0232 /// @param sub sub-particle index of the new barcode. 0233 /// @return New barcode with increased generation and specified sub-particle index 0234 Barcode makeDescendant(SubParticleId sub = 0u) const { 0235 Barcode barcode = *this; 0236 barcode.generationID += 1; 0237 barcode.subParticleID = sub; 0238 return barcode; 0239 } 0240 0241 /// Reduce the barcode to the vertex identifier. 0242 /// @return Barcode containing only vertex and generation information 0243 constexpr Barcode vertexId() const { 0244 // The vertex is identified by primary vertex, secondary vertex, and 0245 // generation. The other components are set to 0 so two particle originating 0246 // from the same vertex will have the same vertex ID. 0247 Barcode barcode = *this; 0248 barcode.particleID = 0u; 0249 barcode.subParticleID = 0u; 0250 return barcode; 0251 } 0252 0253 /// Reduce the barcode to the particle identifier. 0254 constexpr Barcode withoutSubparticle() const { 0255 // Provide a pseudo-barcode that contains all fields but not the 0256 // subparticle counter. This can be used as key in a map to store the 0257 // subparticle information 0258 Barcode barcode = *this; 0259 barcode.subParticleID = 0u; 0260 return barcode; 0261 } 0262 0263 /// Print the barcode 0264 friend inline std::ostream& operator<<(std::ostream& os, Barcode barcode) { 0265 // extra "+" to ensure printing as a number and not as a character 0266 os << "vp=" << +barcode.vertexPrimary() 0267 << "|vs=" << +barcode.vertexSecondary() << "|p=" << +barcode.particle() 0268 << "|g=" << +barcode.generation() << "|sp=" << +barcode.subParticle(); 0269 return os; 0270 } 0271 0272 /// Get hash of the barcode 0273 std::size_t hash() const { 0274 std::size_t seed = 0; 0275 boost::hash_combine(seed, vertexPrimary()); 0276 boost::hash_combine(seed, vertexSecondary()); 0277 boost::hash_combine(seed, particle()); 0278 boost::hash_combine(seed, generation()); 0279 boost::hash_combine(seed, subParticle()); 0280 0281 return seed; 0282 } 0283 0284 private: 0285 PrimaryVertexId vertexPrimaryID = 0u; 0286 SecondaryVertexId vertexSecondaryID = 0u; 0287 ParticleId particleID = 0u; 0288 GenerationId generationID = 0u; 0289 SubParticleId subParticleID = 0u; 0290 }; 0291 0292 } // namespace ActsFatras 0293 0294 // specialize std::hash so Barcode can be used e.g. in an unordered_map 0295 namespace std { 0296 template <> 0297 struct hash<ActsFatras::Barcode> { 0298 auto operator()(ActsFatras::Barcode barcode) const noexcept { 0299 return barcode.hash(); 0300 } 0301 }; 0302 } // namespace std
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|