R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BPDGConverter.cxx
Go to the documentation of this file.
1#include "R3BPDGConverter.h"
2#include "R3BException.h"
3#include <G4NistManager.hh>
4#include <TDatabasePDG.h>
5#include <charconv>
6#include <cstdint>
7#include <cstdlib>
8#include <fmt/core.h>
9#include <string>
10#include <string_view>
11#include <system_error>
12
13namespace R3B
14{
15 constexpr auto MASS_POS = 10;
16 constexpr auto ATOMIC_POS = 10000;
17 constexpr auto PDG_FULL_POS = 10000000;
18
19 namespace
20 {
21 using Type = PDGConverter::Type;
22
23 auto convert_to_int(std::string_view str, int& val)
24 {
25 auto res = std::from_chars(str.begin(), str.end(), val);
26 if (res.ec != std::errc())
27 {
28 fmt::println(
29 "conversion failed with the input: {}. Reason: {}", str, std::make_error_code(res.ec).message());
30 }
31 }
32
33 auto convert_nuclear_pid_to_name(int32_t pid) -> std::string
34 {
35 const auto isomeric_number = pid % MASS_POS;
36 const auto mass_number = ((pid % ATOMIC_POS) - isomeric_number) / MASS_POS;
37 const auto atomic_number = ((pid % PDG_FULL_POS) - (mass_number * MASS_POS) - isomeric_number) / ATOMIC_POS;
38
39 auto* nist_manager = G4NistManager::Instance();
40 auto* element = nist_manager->FindOrBuildElement(atomic_number);
41
42 if (isomeric_number == 0)
43 {
44 return fmt::format("{}-{}", element->GetName(), mass_number);
45 }
46 return fmt::format("{}-{}s", element->GetName(), mass_number, isomeric_number);
47 }
48
49 inline auto convert_basic_pid_to_name(int32_t pid) -> std::string
50 {
51 auto* particle = TDatabasePDG::Instance()->GetParticle(pid);
52 if (particle == nullptr)
53 {
54 throw R3B::logic_error(fmt::format("Failed to query a basic particle name from a pid: {}", pid));
55 }
56 return particle->GetName();
57 }
58
59 inline auto convert_basic_name_to_pid(const std::string& name) -> int32_t
60 {
61 auto* particle = TDatabasePDG::Instance()->GetParticle(name.c_str());
62 if (particle == nullptr)
63 {
64 throw R3B::logic_error(fmt::format("Failed to query a basic particle pid from the name: {:?}", name));
65 }
66 return particle->PdgCode();
67 }
68
69 inline auto convert_nuclear_name_to_pid(const std::string_view name) -> int32_t
70 {
71 const auto dash_pos = name.find('-');
72 auto element_name = name.substr(0, dash_pos);
73 const auto s_pos = name.find('s', dash_pos);
74 auto mass_num = 0;
75 auto isomeric_num = 0;
76 if (s_pos != std::string_view::npos)
77 {
78 convert_to_int(name.substr(dash_pos + 1, s_pos - dash_pos - 1), mass_num);
79 convert_to_int(name.substr(s_pos + 1, std::string_view::npos), isomeric_num);
80 }
81 else
82 {
83 convert_to_int(name.substr(dash_pos + 1, std::string_view::npos), mass_num);
84 }
85 auto* nist_manager = G4NistManager::Instance();
86 auto* element = nist_manager->FindOrBuildElement(std::string{ element_name });
87 if (element == nullptr)
88 {
89 throw R3B::logic_error(fmt::format("Cannot find any element with the name {:?}", element_name));
90 }
91 auto atomic_number = static_cast<int32_t>(element->GetZ());
92 return R3B::PDGConverter::nuclear_id_min + isomeric_num + (mass_num * MASS_POS) +
93 (atomic_number * ATOMIC_POS);
94 }
95
96 auto convert_pid_to_name(int32_t pid) -> std::string
97 {
98 switch (PDGConverter::get_type(pid))
99 {
100 case Type::nuclear:
101 return convert_nuclear_pid_to_name(pid);
102 case Type::basic:
103 return convert_basic_pid_to_name(pid);
104 case Type::invalid:
105 return "invalid";
106 }
107 return "invalid";
108 }
109
110 auto convert_name_to_pid(const std::string& name) -> int32_t
111 {
112 switch (PDGConverter::get_type(name))
113 {
114 case Type::nuclear:
115 return convert_nuclear_name_to_pid(name);
116 case Type::basic:
117 return convert_basic_name_to_pid(name);
118 case Type::invalid:
119 return 0;
120 }
121 return 0;
122 }
123
124 } // namespace
125
126 auto PDGConverter::get_pid(const std::string& name) -> int32_t
127 {
128 register_entry(name);
129 return name_to_pid_.at(name);
130 }
131
132 auto PDGConverter::get_name(int32_t pid) -> std::string
133 {
134 register_entry(pid);
135 return pid_to_name_.at(pid);
136 }
137
138 auto PDGConverter::get_type(int32_t pid) -> Type
139 {
140 if (std::abs(pid) > nuclear_id_max)
141 {
142 return Type::invalid;
143 }
144 if (std::abs(pid) > nuclear_id_min)
145 {
146 return Type::nuclear;
147 }
148 return Type::basic;
149 }
150
151 auto PDGConverter::get_type(const std::string& name) -> Type
152 {
153 const auto dash_pos = name.find('-');
154 if (dash_pos == std::string::npos)
155 {
156 return Type::basic;
157 }
158
159 if (name.size() == dash_pos + 1)
160 {
161 return Type::basic;
162 }
163
164 if (dash_pos > 2)
165 {
166 return Type::invalid;
167 }
168 return Type::nuclear;
169 }
170
172 {
173 pid_to_name_.clear();
174 name_to_pid_.clear();
175 }
176
178 {
179 if (pid_to_name_.find(pid) == pid_to_name_.end())
180 {
181 const auto name = convert_pid_to_name(pid);
182 pid_to_name_.emplace(pid, name);
183 name_to_pid_.emplace(name, pid);
184 }
185 }
186
187 void PDGConverter::register_entry(const std::string& name)
188 {
189 if (name_to_pid_.find(name) == name_to_pid_.end())
190 {
191 const auto pid = convert_name_to_pid(name);
192 pid_to_name_.emplace(pid, name);
193 name_to_pid_.emplace(name, pid);
194 }
195 }
196
197} // namespace R3B
std::unordered_map< int32_t, std::string > pid_to_name_
static constexpr auto nuclear_id_min
std::unordered_map< std::string, int32_t > name_to_pid_
static auto get_type(const std::string &name) -> Type
Get the type of the particle from its name.
auto get_pid(const std::string &name) -> int32_t
auto get_name(int32_t pid) -> std::string
static constexpr auto nuclear_id_max
void register_entry(int32_t pid)
constexpr auto PDG_FULL_POS
constexpr auto MASS_POS
constexpr auto ATOMIC_POS