Back to home page

EIC code displayed by LXR

 
 

    


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

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 #include "Acts/Definitions/ParticleData.hpp"
0010 
0011 #include "Acts/Definitions/PdgParticle.hpp"
0012 
0013 #include <algorithm>
0014 #include <array>
0015 #include <cassert>
0016 #include <cmath>
0017 #include <cstdint>
0018 #include <iterator>
0019 #include <limits>
0020 #include <optional>
0021 #include <ostream>
0022 #include <type_traits>
0023 #include <utility>
0024 
0025 #include "ParticleDataTable.hpp"
0026 
0027 namespace {
0028 
0029 enum class Type {
0030   Charge,
0031   Mass,
0032   Name,
0033 };
0034 
0035 // Template function depending on the PDG and *type* of data
0036 // so we can use statically cached values
0037 template <typename T, Acts::PdgParticle pdg, Type type>
0038 std::optional<T> findCachedImpl(const std::map<std::int32_t, T>& map) {
0039   const static std::optional<T> value = [&map]() -> std::optional<T> {
0040     const auto it = map.find(static_cast<std::int32_t>(pdg));
0041     if (it == map.end()) {
0042       return std::nullopt;
0043     }
0044     return it->second;
0045   }();
0046 
0047   return value;
0048 }
0049 
0050 // Cache lookup for particle data
0051 // Uses a switch statement to map the PDG code to the correct cached value
0052 template <typename T, Type type>
0053 std::optional<T> findCached(Acts::PdgParticle pdg,
0054                             const std::map<std::int32_t, T>& map) {
0055   using enum Acts::PdgParticle;
0056   switch (pdg) {
0057     case eElectron:
0058       return findCachedImpl<T, eElectron, type>(map);
0059     case ePositron:
0060       return findCachedImpl<T, ePositron, type>(map);
0061     case eMuon:
0062       return findCachedImpl<T, eMuon, type>(map);
0063     case eAntiMuon:
0064       return findCachedImpl<T, eAntiMuon, type>(map);
0065     case eTau:
0066       return findCachedImpl<T, eTau, type>(map);
0067     case eAntiTau:
0068       return findCachedImpl<T, eAntiTau, type>(map);
0069     case eGamma:
0070       return findCachedImpl<T, eGamma, type>(map);
0071     case ePionZero:
0072       return findCachedImpl<T, ePionZero, type>(map);
0073     case ePionPlus:
0074       return findCachedImpl<T, ePionPlus, type>(map);
0075     case ePionMinus:
0076       return findCachedImpl<T, ePionMinus, type>(map);
0077     case eKaonPlus:
0078       return findCachedImpl<T, eKaonPlus, type>(map);
0079     case eKaonMinus:
0080       return findCachedImpl<T, eKaonMinus, type>(map);
0081     case eNeutron:
0082       return findCachedImpl<T, eNeutron, type>(map);
0083     case eAntiNeutron:
0084       return findCachedImpl<T, eAntiNeutron, type>(map);
0085     case eProton:
0086       return findCachedImpl<T, eProton, type>(map);
0087     case eAntiProton:
0088       return findCachedImpl<T, eAntiProton, type>(map);
0089     case eLead:
0090       return findCachedImpl<T, eLead, type>(map);
0091     default:
0092       return std::nullopt;
0093   }
0094 }
0095 
0096 }  // namespace
0097 
0098 std::optional<float> Acts::findCharge(Acts::PdgParticle pdg) {
0099   if (auto cached = findCached<float, Type::Charge>(pdg, kParticlesMapCharge);
0100       cached) {
0101     return cached;
0102   }
0103 
0104   const auto it = kParticlesMapCharge.find(pdg);
0105   if (it == kParticlesMapCharge.end()) {
0106     if (isNucleus(pdg)) {
0107       return Acts::findChargeOfNucleus(pdg);
0108     } else {
0109       return std::nullopt;
0110     }
0111   }
0112   return it->second;
0113 }
0114 
0115 float Acts::findChargeOfNucleus(Acts::PdgParticle pdg) {
0116   if (!isNucleus(pdg)) {
0117     throw std::invalid_argument("PDG must represent a nucleus");
0118   }
0119   auto pdgGround = makeNucleusGroundState(pdg);
0120   const auto it = kParticlesMapCharge.find(pdgGround);
0121   if (it == kParticlesMapCharge.end()) {
0122     // extract charge from PDG number
0123     auto ZandA = extractNucleusZandA(pdg);
0124     return static_cast<float>(ZandA.first);
0125   }
0126   return it->second;
0127 }
0128 
0129 std::optional<float> Acts::findMass(Acts::PdgParticle pdg) {
0130   if (auto cached = findCached<float, Type::Mass>(pdg, kParticlesMapMass);
0131       cached) {
0132     return cached;
0133   }
0134 
0135   const auto it = kParticlesMapMass.find(pdg);
0136   if (it == kParticlesMapMass.end()) {
0137     if (isNucleus(pdg)) {
0138       return Acts::findMassOfNucleus(pdg);
0139     } else {
0140       return std::nullopt;
0141     }
0142   }
0143   return it->second;
0144 }
0145 
0146 float Acts::findMassOfNucleus(Acts::PdgParticle pdg) {
0147   if (!isNucleus(pdg)) {
0148     throw std::invalid_argument("PDG must represent a nucleus");
0149   }
0150   auto pdgGround = makeNucleusGroundState(pdg);
0151   const auto it = kParticlesMapMass.find(pdgGround);
0152   if (it == kParticlesMapMass.end()) {
0153     // calculate mass using Bethe-Weizsacker formula
0154     return calculateNucleusMass(pdg);
0155   }
0156   return it->second;
0157 }
0158 
0159 float Acts::calculateNucleusMass(Acts::PdgParticle pdg) {
0160   if (!isNucleus(pdg)) {
0161     throw std::invalid_argument("PDG must represent a nucleus");
0162   }
0163 
0164   auto ZandA = extractNucleusZandA(pdg);
0165   int Z = std::abs(ZandA.first);
0166   int A = ZandA.second;
0167 
0168   float a_Vol = 15.260f * Acts::UnitConstants::MeV;
0169   float a_Surf = 16.267f * Acts::UnitConstants::MeV;
0170   float a_Col = 0.689f * Acts::UnitConstants::MeV;
0171   float a_Sym = 22.209f * Acts::UnitConstants::MeV;
0172   float a_Pair =
0173       (1 - 2 * (Z % 2)) * (1 - A % 2) * 10.076f * Acts::UnitConstants::MeV;
0174 
0175   float massP = 0.938272f * Acts::UnitConstants::GeV;
0176   float massN = 0.939565f * Acts::UnitConstants::GeV;
0177 
0178   float bindEnergy = 0.f;
0179   bindEnergy += a_Vol * A;
0180   bindEnergy -= a_Surf * std::pow(A, 2. / 3.);
0181   bindEnergy -= a_Col * Z * (Z - 1) * std::pow(A, -1. / 3.);
0182   bindEnergy -= a_Sym * std::pow(A - 2 * Z, 2.) / A;
0183   bindEnergy -= a_Pair * std::pow(A, -1. / 2.);
0184 
0185   return massP * Z + massN * (A - Z) - bindEnergy;
0186 }
0187 
0188 std::optional<std::string_view> Acts::findName(Acts::PdgParticle pdg) {
0189   if (auto cached =
0190           findCached<const char* const, Type::Name>(pdg, kParticlesMapName);
0191       cached) {
0192     return cached;
0193   }
0194 
0195   const auto it = kParticlesMapName.find(pdg);
0196   if (it == kParticlesMapName.end()) {
0197     if (isNucleus(pdg)) {
0198       return Acts::findNameOfNucleus(pdg);
0199     } else {
0200       return std::nullopt;
0201     }
0202   }
0203   return it->second;
0204 }
0205 
0206 std::optional<std::string_view> Acts::findNameOfNucleus(Acts::PdgParticle pdg) {
0207   if (!isNucleus(pdg)) {
0208     throw std::invalid_argument("PDG must represent a nucleus");
0209   }
0210 
0211   auto pdgGround = makeNucleusGroundState(pdg);
0212   const auto it = kParticlesMapName.find(pdgGround);
0213   if (it == kParticlesMapName.end()) {
0214     return std::nullopt;
0215   }
0216   return it->second;
0217 }
0218 
0219 std::optional<Acts::ParticleData> Acts::findParticleData(PdgParticle pdg) {
0220   auto charge = findCharge(pdg);
0221   auto mass = findMass(pdg);
0222   auto name = findName(pdg);
0223 
0224   if (charge.has_value() && mass.has_value() && name.has_value()) {
0225     return ParticleData{charge.value(), mass.value(), name.value()};
0226   }
0227 
0228   return std::nullopt;
0229 }
0230 
0231 std::ostream& Acts::operator<<(std::ostream& os, Acts::PdgParticle pdg) {
0232   const auto name = Acts::findName(pdg);
0233   if (name) {
0234     os << *name;
0235   } else {
0236     os << static_cast<std::int32_t>(pdg);
0237   }
0238   return os;
0239 }
0240 
0241 std::optional<std::string_view> Acts::pdgToShortAbsString(PdgParticle pdg) {
0242   pdg = makeAbsolutePdgParticle(pdg);
0243   if (pdg == eElectron) {
0244     return "e";
0245   }
0246   if (pdg == eMuon) {
0247     return "mu";
0248   }
0249   if (pdg == eTau) {
0250     return "t";
0251   }
0252   if (pdg == eGamma) {
0253     return "g";
0254   }
0255   if (pdg == ePionZero) {
0256     return "pi0";
0257   }
0258   if (pdg == ePionPlus) {
0259     return "pi";
0260   }
0261   if (pdg == eKaonPlus) {
0262     return "K";
0263   }
0264   if (pdg == eNeutron) {
0265     return "n";
0266   }
0267   if (pdg == eProton) {
0268     return "p";
0269   }
0270   if (pdg == eLead) {
0271     return "lead";
0272   }
0273   return std::nullopt;
0274 }