|
||||
File indexing completed on 2025-01-18 09:28:03
0001 // This file is part of the Acts project. 0002 // 0003 // Copyright (C) 2018-2020 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 http://mozilla.org/MPL/2.0/. 0008 0009 #pragma once 0010 0011 #include "Acts/Utilities/MultiIndex.hpp" 0012 0013 #include <cstdint> 0014 0015 namespace ActsFatras { 0016 0017 /// Particle identifier that encodes additional event information. 0018 /// 0019 /// The barcode has to fulfill two separate requirements: be able to act as 0020 /// unique identifier for particles within an event and to encode details 0021 /// on the event structure for fast lookup. Since we only care about tracking 0022 /// here, we need to support two scenarios: 0023 /// 0024 /// * Identify which primary/secondary vertex particles belong to. No 0025 /// information on intermediate/unstable/invisible particles needs to be 0026 /// retained. This information is already available in the underlying 0027 /// generator event and should not be duplicated. 0028 /// * If (visible) particles convert, decay, or interact with the detector, 0029 /// we need to be able to identify the initial (primary) particle. Typical 0030 /// examples are pion nuclear interactions or electron/gamma conversions. 0031 /// 0032 /// The vertex information is encoded as two numbers that define the 0033 /// primary and secondary vertex. The primary vertex must be non-zero. 0034 /// Particles with a zero secondary vertex originate directly from the primary 0035 /// vertex. 0036 /// 0037 /// Within one vertex (primary+secondary) each particle is identified by 0038 /// a particle, generation, and sub-particle number. Particles originating 0039 /// from the vertex must have zero generation and zero sub-particle number; 0040 /// a consequence is that only non-zero generation can have non-zero 0041 /// sub-particle numbers. A non-zero generation indicates that the particle 0042 /// is a descendant of the original particle, e.g. from interactions or decay, 0043 /// while the sub-particle number identifies the descendant particle. 0044 /// 0045 /// With this encoding, non-primary particles and their primary parent can 0046 /// be easily identified at the expense of not storing the exact decay history. 0047 /// 0048 /// A barcode with all elements set to zero (the default value) is an invalid 0049 /// value that can be used e.g. to mark missing or unknown particles. 0050 /// 0051 /// ## Example 0052 /// 0053 /// A particle generated in a primary interaction might have the barcode 0054 /// 0055 /// 2|0|14|0|0 -> vertex=2 (primary), particle=14, generation=0, sub=0 0056 /// 0057 /// A simulation module might generate an interaction and create two new 0058 /// particles. These are descendants of the initial particle and the simulation 0059 /// module can generate the new barcodes directly by increasing the 0060 /// generation number and choosing sub-particle identifiers: 0061 /// 0062 /// 2|0|14|1|0 -> vertex=2 (primary), particle=14, generation=1, sub=0 0063 /// 2|0|14|1|1 -> vertex=2 (primary), particle=14, generation=1, sub=1 0064 /// 0065 /// If these secondary particles generate further tertiary particles 0066 /// the barcode would be e.g. 0067 /// 0068 /// 2|0|14|2|0 -> vertex=2 (primary), particle=14, generation=2, sub=0 0069 /// 0070 /// ## Possible issues 0071 /// 0072 /// The hierarchical nature of the barcode allows barcode creation without 0073 /// a central service. Since the full history is not stored, generated barcodes 0074 /// for higher-generation particles can overlap when generated by independent 0075 /// interactions. Assuming an initial primary particle with barcode 0076 /// 0077 /// 3|4|5|0|0 -> particle=5 0078 /// 0079 /// a first interaction might create a secondary particle by increasing the 0080 /// generation number (without destroying the initial particle) 0081 /// 0082 /// 3|4|5|1|0 -> particle=5, generation+=1, first sub-particle 0083 /// 0084 /// The initial particle gets simulated further and at another step a second 0085 /// interaction also creates a new particle. Since it knows nothing about 0086 /// the previously created particle (no central service), it will generate 0087 /// 0088 /// 3|4|5|1|0 -> particle=5, generation+=1, first sub-particle 0089 /// 0090 /// which is identical to the previously create barcode. These cases can be 0091 /// easily solved by renumbering the sub-particle identifier within each 0092 /// generation to contain unique values. However, this can only be done when all 0093 /// particles are known. 0094 class Barcode : public Acts::MultiIndex<uint64_t, 12, 12, 16, 8, 16> { 0095 using Base = Acts::MultiIndex<uint64_t, 12, 12, 16, 8, 16>; 0096 0097 public: 0098 using Base::Base; 0099 using Base::Value; 0100 0101 // Construct an invalid barcode with all levels set to zero. 0102 constexpr Barcode() : Base(Base::Zeros()) {} 0103 Barcode(const Barcode&) = default; 0104 Barcode(Barcode&&) = default; 0105 Barcode& operator=(const Barcode&) = default; 0106 Barcode& operator=(Barcode&&) = default; 0107 0108 /// Return the primary vertex identifier. 0109 constexpr Value vertexPrimary() const { return level(0); } 0110 /// Return the secondary vertex identifier. 0111 constexpr Value vertexSecondary() const { return level(1); } 0112 /// Return the particle identifier. 0113 constexpr Value particle() const { return level(2); } 0114 /// Return the generation identifier. 0115 constexpr Value generation() const { return level(3); } 0116 /// Return the sub-particle identifier. 0117 constexpr Value subParticle() const { return level(4); } 0118 0119 /// Set the primary vertex identifier. 0120 constexpr Barcode& setVertexPrimary(Value id) { 0121 set(0, id); 0122 return *this; 0123 } 0124 /// Set the secondary vertex identifier. 0125 constexpr Barcode& setVertexSecondary(Value id) { 0126 set(1, id); 0127 return *this; 0128 } 0129 /// Set the parent particle identifier. 0130 constexpr Barcode& setParticle(Value id) { 0131 set(2, id); 0132 return *this; 0133 } 0134 /// Set the particle identifier. 0135 constexpr Barcode& setGeneration(Value id) { 0136 set(3, id); 0137 return *this; 0138 } 0139 /// Set the process identifier. 0140 constexpr Barcode& setSubParticle(Value id) { 0141 set(4, id); 0142 return *this; 0143 } 0144 0145 /// Construct a new barcode representing a descendant particle. 0146 /// 0147 /// @param sub sub-particle index of the new barcode. 0148 Barcode makeDescendant(Value sub = 0u) const { 0149 return Barcode(*this).setGeneration(generation() + 1).setSubParticle(sub); 0150 } 0151 0152 /// Reduce the barcode to the vertex identifier. 0153 constexpr Barcode vertexId() const { 0154 // The vertex is identified by primary vertex, secondary vertex, and 0155 // generation. The other components are set to 0 so two particle originating 0156 // from the same vertex will have the same vertex ID. 0157 return Barcode(*this).setParticle(0).setSubParticle(0); 0158 } 0159 }; 0160 0161 } // namespace ActsFatras 0162 0163 // specialize std::hash so Barcode can be used e.g. in an unordered_map 0164 namespace std { 0165 template <> 0166 struct hash<ActsFatras::Barcode> { 0167 auto operator()(ActsFatras::Barcode barcode) const noexcept { 0168 return std::hash<ActsFatras::Barcode::Value>()(barcode.value()); 0169 } 0170 }; 0171 } // 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 |