Back to home page

EIC code displayed by LXR

 
 

    


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