TkN 2.1
Toolkit for Nuclei
tkmanager.cpp
1/********************************************************************************
2 * Copyright (c) : Université de Lyon 1, CNRS/IN2P3, UMR5822, *
3 * IP2I, F-69622 Villeurbanne Cedex, France *
4 * Normandie Université, ENSICAEN, UNICAEN, CNRS/IN2P3, *
5 * LPC Caen, F-14000 Caen, France *
6 * Contibutor(s) : *
7 * Jérémie Dudouet jeremie.dudouet@cnrs.fr [2020] *
8 * Diego Gruyer diego.gruyer@cnrs.fr [2020] *
9 * *
10 * This software is governed by the CeCILL-B license under French law and *
11 * abiding by the rules of distribution of free software. You can use, *
12 * modify and/ or redistribute the software under the terms of the *
13 * CeCILL-B license as circulated by CEA, CNRS and INRIA at the following *
14 * URL \"http://www.cecill.info\". *
15 * *
16 * As a counterpart to the access to the source code and rights to copy, *
17 * modify and redistribute granted by the license, users are provided *
18 * only with a limited warranty and the software's author, the holder of *
19 * the economic rights, and the successive licensors have only limited *
20 * liability. *
21 * *
22 * In this respect, the user's attention is drawn to the risks associated *
23 * with loading, using, modifying and/or developing or reproducing the *
24 * software by the user in light of its specific status of free software, *
25 * that may mean that it is complicated to manipulate, and that also *
26 * therefore means that it is reserved for developers and experienced *
27 * professionals having in-depth computer knowledge. Users are therefore *
28 * encouraged to load and test the software's suitability as regards *
29 * their requirements in conditions enabling the security of their *
30 * systems and/or data to be ensured and, more generally, to use and *
31 * operate it in the same conditions as regards security. *
32 * *
33 * The fact that you are presently reading this means that you have had *
34 * knowledge of the CeCILL-B license and that you accept its terms. *
35 ********************************************************************************/
36
37#include "tkmanager.h"
38#include "tklog.h"
39#include "tkdatabase.h"
40
41namespace tkn {
50}
51
52using namespace tkn;
53
54tkmanager* tkmanager::g_data_manager = nullptr;
55
56tkmanager* tkmanager::the_data_manager()
57{
58 if(g_data_manager) return g_data_manager;
59
60 std::lock_guard<std::recursive_mutex> lock(get_mutex());
61
62 if(g_data_manager == nullptr) {
63 g_data_manager = new tkmanager();
64 }
65
66 return g_data_manager;
67}
68
70{
71 std::lock_guard<std::recursive_mutex> lock(get_mutex());
72
73 preload_nuclei();
74 g_data_manager = this;
75}
76
78{
79 g_data_manager = nullptr;
80}
81
82shared_ptr<tklevel_scheme> tkmanager::get_level_scheme(const tkn::tkstring &_nuc, int _zz, int _aa)
83{
84 if(fmap_of_level_scheme.count(_nuc)) return fmap_of_level_scheme[_nuc];
85
86 std::lock_guard<std::recursive_mutex> lock(get_mutex());
87
88 if(fmap_of_level_scheme.count(_nuc)==0) {
89 fmap_of_level_scheme[_nuc] = make_shared<tklevel_scheme>(_nuc,_zz,_aa);
90 }
91
92 return fmap_of_level_scheme[_nuc];
93}
94
95void tkmanager::preload_nuclei()
96{
97 // try with isotope.*, element.*
98 gdatabase->begin("isotope.*, element.*","isotope INNER JOIN element on isotope.element_id=element.element_id");
99
100 while(gdatabase->next()) {
101 tkdb_table& element = (*gdatabase)["ELEMENT"];
102 tkdb_table& iso_table = (*gdatabase)["ISOTOPE"];
103
104 shared_ptr<tknucleus> anucleus = make_shared<tknucleus>();
105
106 tkstring name = element["symbol"].get_value();
107 anucleus->felement_symbol = name;
108 anucleus->felement_name = element["name"].get_value();
109
110 int zz = element["charge"].get_value().atoi();
111 int aa = iso_table["mass"].get_value().atoi();
112
113 gdebug << aa << name << " loaded" << do_endl;
114
115 name.prepend(iso_table["mass"].get_value());
116
117 anucleus->set_name(name.data());
118 anucleus->fA = aa;
119 anucleus->fZ = zz;
120 anucleus->fN = aa - zz;
121
122 // load element properties
123 for (auto &col : element.get_columns()) {
124 tkstring colname = col.first;
125 if(colname=="element_id") continue;
126 if(colname.ends_with("_unit")) continue;
127
128 tkstring colname_unit = colname + "_unit";
129 tkstring unit("");
130 tkstring value = col.second.get_value();
131 if(element.get_columns().count(colname_unit)) {
132 unit = element.get_columns().at(colname_unit).get_value();
133 }
134 if( colname == "atomic_mass" ||
135 colname == "atomic_radius_van_der_Waals" ||
136 colname == "boiling_point" ||
137 colname == "density" ||
138 colname == "ionization_energy" ||
139 colname == "melting_point"
140 ) {
141 shared_ptr<tkmeasure> data = make_shared<tkmeasure>(value.atof(),unit);
142 data->set_info(tkproperty::kKnown);
143 data->set_type(colname);
144 anucleus->add_property(colname,data);
145 }
146 else if(colname.begins_with("XRay")) {
147 unit = "keV";
148 shared_ptr<tkmeasure> data = make_shared<tkmeasure>(value.atof(),unit);
149 data->set_info(tkproperty::kKnown);
150 data->set_type(colname);
151 if(value.atof()>0) anucleus->add_property(colname,data);
152 }
153 else {
154 anucleus->add_property_str(colname,value,unit);
155 }
156 }
157
158 // load isotope properties
159 vector<tkstring> fNames = {
160 "lifetime", // From ENSDF
161 "abundance", "quadrupoleDeformation", "FY235U", "FY238U", "FY239Pu", "FY241Pu", "FY252Cf", "cFY235U", "cFY238U", "cFY239Pu", "cFY241Pu", "cFY252Cf", // From NUDAT
162 "mass_excess", "radius", "magnetic_dipole", "electric_quadrupole" // From IAEA-NDS API
163 };
164
165 for(auto &property_name: fNames) {
167 iso_table.read_measure(data_struct,property_name);
168 if(data_struct.filled) {
169 shared_ptr<tkmeasure> data = make_shared<tkmeasure>(data_struct.value,data_struct.unit,data_struct.err);
170 if(data_struct.info.contains("ERR=SY")) data->set_info(tkproperty::kSystematic);
171 else data->set_info(tkproperty::kKnown);
172 data->set_type(property_name);
173
174 if(property_name == "lifetime") {
175 if(!data_struct.info.is_empty()) data->set_info_tag(data_struct.info);
176 if(data->get_info_tag().contains("STABLE")) {
177 anucleus->fis_stable = true;
178 data->set_error(0);
179 anucleus->add_property(property_name,data,"STABLE","");
180 }
181 else anucleus->add_property(property_name,data, tkstring::form("%g",data->get_value()));
182 }
183 else {
184 anucleus->add_property(property_name,data);
185 }
186 }
187 }
188
189 anucleus->add_property_str("isotope_year_discovered",iso_table["isotope_year_discovered"].get_value(),"");
190
191 tkstring decay_modes = iso_table["decay_modes"].get_value();
192 anucleus->add_property_str("decay_modes",decay_modes,"");
193
194 tkstring spin_parity_str = iso_table["spin_parity"].get_value();
195 double spin = iso_table["spin"].get_value().atof();
196 int parity = iso_table["parity"].get_value().atoi();
197
198 anucleus->fspin_parity.set_spin(spin);
199 anucleus->fspin_parity.set_parity(parity);
200 anucleus->fspin_parity.set_from_str(spin_parity_str);
201
202 anucleus->add_property_str("spin_parity",spin_parity_str,"");
203
204 fmap_of_nuclei[name] = anucleus;
205 fmap_of_nuclei_per_z[anucleus->fZ].push_back(anucleus);
206 fmap_of_nuclei_per_a[anucleus->fA].push_back(anucleus);
207 fmap_of_nuclei_per_n[anucleus->fN].push_back(anucleus);
208 fmap_of_nuclei_per_z_and_a[anucleus->fZ][anucleus->fA] = anucleus;
209 fvector_of_nuclei.push_back(anucleus);
210
211 if(!fmap_of_symbols.count(anucleus->get_z()))
212 fmap_of_symbols[anucleus->get_z()] = anucleus->get_element_symbol();
213 }
214
215 // separation energy calculation
216 if(!get_nucleus(0,1)||!get_nucleus(1,1)||!get_nucleus(2,4)) return;
217 auto neutron_ME = fmap_of_nuclei_per_z_and_a.at(0).at(1)->get("mass_excess");
218 auto proton_ME = fmap_of_nuclei_per_z_and_a.at(1).at(1)->get("mass_excess");
219 auto alpha_ME = fmap_of_nuclei_per_z_and_a.at(2).at(4)->get("mass_excess");
220 tkmeasure electron_mass(0.51099895000,"MeV",0.00000000015);
221 for(auto &nuc: fmap_of_nuclei) {
222 auto ME = nuc.second->get("mass_excess");
223 if(!ME) continue;
224 // Sn calculation: Sn(A,Z) = − ME(A,Z) + ME(A−1,Z) + ME(n)
225 auto daughter = get_nucleus(nuc.second->get_z(),nuc.second->get_a()-1);
226 if(daughter && daughter->get("mass_excess")) {
227 shared_ptr<tkmeasure> Sn = make_shared<tkmeasure>(-*ME + *daughter->get("mass_excess") + *neutron_ME);
228 Sn->set_type("neutronSeparationEnergy");
229 nuc.second->add_property("neutronSeparationEnergy",Sn);
230 }
231 // S2n calculation: S2n(A,Z) = − ME(A,Z) + ME(A−2,Z) + 2*ME(n)
232 daughter = get_nucleus(nuc.second->get_z(),nuc.second->get_a()-2);
233 if(daughter && daughter->get("mass_excess")) {
234 shared_ptr<tkmeasure> S2n = make_shared<tkmeasure>(-*ME + *daughter->get("mass_excess") + 2.*(*neutron_ME));
235 S2n->set_type("twoNeutronSeparationEnergy");
236 nuc.second->add_property("twoNeutronSeparationEnergy",S2n);
237 }
238 // Sp calculation: Sp(A,Z) = − ME(A,Z) + ME(A−1,Z-1) + ME(p)
239 daughter = get_nucleus(nuc.second->get_z()-1,nuc.second->get_a()-1);
240 if(daughter && daughter->get("mass_excess")) {
241 shared_ptr<tkmeasure> Sp = make_shared<tkmeasure>(-*ME + *daughter->get("mass_excess") + *proton_ME);
242 Sp->set_type("protonSeparationEnergy");
243 nuc.second->add_property("protonSeparationEnergy",Sp);
244 }
245 // S2p calculation: S2p(A,Z) = − ME(A,Z) + ME(A−2,Z-2) + 2*ME(p)
246 daughter = get_nucleus(nuc.second->get_z()-2,nuc.second->get_a()-2);
247 if(daughter && daughter->get("mass_excess")) {
248 shared_ptr<tkmeasure> S2p = make_shared<tkmeasure>(-*ME + *daughter->get("mass_excess") + 2.*(*proton_ME));
249 S2p->set_type("twoProtonSeparationEnergy");
250 nuc.second->add_property("twoProtonSeparationEnergy",S2p);
251 }
252
253 // Qalpha
254 daughter = get_nucleus(nuc.second->get_z()-2,nuc.second->get_a()-4);
255 if(daughter && daughter->get("mass_excess")) {
256 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess") - *alpha_ME);
257 Q->set_type("Qalpha");
258 nuc.second->add_property("Qalpha",Q);
259 }
260 // QbetaMinus
261 daughter = get_nucleus(nuc.second->get_z()+1,nuc.second->get_a());
262 if(daughter && daughter->get("mass_excess")) {
263 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess"));
264 Q->set_type("QbetaMinus");
265 nuc.second->add_property("QbetaMinus",Q);
266 }
267 // QbetaMinusOneNeutronEmission
268 daughter = get_nucleus(nuc.second->get_z()+1,nuc.second->get_a()-1);
269 if(daughter && daughter->get("mass_excess")) {
270 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess") - *neutron_ME);
271 Q->set_type("QbetaMinusOneNeutronEmission");
272 nuc.second->add_property("QbetaMinusOneNeutronEmission",Q);
273 }
274 // QbetaMinusTwoNeutronEmission
275 daughter = get_nucleus(nuc.second->get_z()+1,nuc.second->get_a()-2);
276 if(daughter && daughter->get("mass_excess")) {
277 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess") - 2.*(*neutron_ME) );
278 Q->set_type("QbetaMinusTwoNeutronEmission");
279 nuc.second->add_property("QbetaMinusTwoNeutronEmission",Q);
280 }
281 // QdeltaAlpha: 0.5*(Qa(Z+2,N+2)-Qa(Z,N))
282 daughter = get_nucleus(nuc.second->get_z()+2,nuc.second->get_a()+4);
283 if(daughter && daughter->get("mass_excess") && nuc.second->get("Qalpha")) {
284 auto Qa = nuc.second->get("Qalpha");
285 auto Qa2 = *daughter->get("mass_excess") - *ME - *alpha_ME;
286 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( 0.5*(Qa2 - *Qa ));
287 Q->set_type("QdeltaAlpha");
288 nuc.second->add_property("QdeltaAlpha",Q);
289 }
290 // QdoubleBetaMinus
291 daughter = get_nucleus(nuc.second->get_z()+2,nuc.second->get_a());
292 if(daughter && daughter->get("mass_excess")) {
293 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess"));
294 Q->set_type("QdoubleBetaMinus");
295 nuc.second->add_property("QdoubleBetaMinus",Q);
296 }
297 // QelectronCapture
298 daughter = get_nucleus(nuc.second->get_z()-1,nuc.second->get_a());
299 if(daughter && daughter->get("mass_excess")) {
300 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess"));
301 Q->set_type("QelectronCapture");
302 nuc.second->add_property("QelectronCapture",Q);
303 }
304 // QdoubleElectronCapture
305 daughter = get_nucleus(nuc.second->get_z()-2,nuc.second->get_a());
306 if(daughter && daughter->get("mass_excess")) {
307 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess"));
308 Q->set_type("QdoubleElectronCapture");
309 nuc.second->add_property("QdoubleElectronCapture",Q);
310 }
311 // QelectronCaptureOneProtonEmission
312 daughter = get_nucleus(nuc.second->get_z()-2,nuc.second->get_a()-1);
313 if(daughter && daughter->get("mass_excess")) {
314 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess") - *proton_ME);
315 Q->set_type("QelectronCaptureOneProtonEmission");
316 nuc.second->add_property("QelectronCaptureOneProtonEmission",Q);
317 }
318 // QpositronEmission
319 daughter = get_nucleus(nuc.second->get_z()-1,nuc.second->get_a());
320 if(daughter && daughter->get("mass_excess")) {
321 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( *ME - *daughter->get("mass_excess") - 2.*electron_mass);
322 Q->set_type("QpositronEmission");
323 nuc.second->add_property("QpositronEmission",Q);
324 }
325
326 // binding energy
327 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( 1./nuc.second->get_a()*(nuc.second->get_z()*(*proton_ME) + nuc.second->get_n()*(*neutron_ME) - *ME));
328 Q->set_type("binding_energy_overA");
329 nuc.second->add_property("binding_energy_overA",Q);
330
331 // pairingGap PG=0.5 x (-1)N x ( 2BE(Z,N) - BE(Z,N-1) -BE(Z,N+1) )
332 auto nuc_minus = get_nucleus(nuc.second->get_z(),nuc.second->get_a()-1);
333 auto nuc_plus = get_nucleus(nuc.second->get_z(),nuc.second->get_a()+1);
334 if(nuc_minus && nuc_plus && nuc_minus->get("mass_excess") && nuc_plus->get("mass_excess")) {
335 shared_ptr<tkmeasure> Q = make_shared<tkmeasure>( 0.5 * pow(-1,nuc.second->get_n()) * ( -2* (*ME) + *nuc_minus->get("mass_excess") + *nuc_plus->get("mass_excess")));
336 Q->set_type("pairingGap");
337 nuc.second->add_property("pairingGap",Q);
338 }
339 }
340}
341
343{
344 size_t nnuc=fvector_of_nuclei.size(),inuc=0;
345 for(const auto &nuc : fvector_of_nuclei){
346 if(_verbose) glog.progress_bar(nnuc,inuc,"... pre-loading");
347 get_level_scheme(nuc->get_symbol(),nuc->get_z(),nuc->get_a());
348 inuc++;
349 }
350}
351
367vector<shared_ptr<tknucleus> > tkmanager::get_nuclei(const std::function<bool (shared_ptr<tknucleus>)> &_selection)
368{
369 vector<shared_ptr<tknucleus>> res;
370 for(const auto &nuc : fvector_of_nuclei)
371 if(_selection(nuc)) res.push_back(nuc);
372 return res;
373}
374
376 tkstring symbol=_nuc.extract_alpha();
377 for(auto &nuc_test: fmap_of_nuclei) {
378 if(nuc_test.first.copy().extract_alpha() == symbol) {
379 _z = nuc_test.second->get_z();
380 return true;
381 }
382 }
383 return false;
384}
385
387{
388 std::lock_guard<std::recursive_mutex> lock(get_mutex());
389 fmax_level_id++;
390 return fmax_level_id;
391}
392
394{
395 std::lock_guard<std::recursive_mutex> lock(get_mutex());
396 fmax_decay_id++;
397 return fmax_decay_id;
398}
399
400#ifdef HAS_ROOT
402ClassImp(tkmanager)
403#endif
Representaiton of a sqlite data table.
Definition: tkdb_table.h:52
void read_measure(measure_data_struct &_struct, const tkstring &_col_base_name)
Definition: tkdb_table.cpp:304
row & get_columns()
Definition: tkdb_table.h:139
Manages the database loading and provides access to the physics properties.
Definition: tkmanager.h:55
int get_new_level_id()
define a new unique level id
Definition: tkmanager.cpp:386
shared_ptr< tknucleus > get_nucleus(const tkstring &_nuc)
return a shared pointer to a nucleus from its name
Definition: tkmanager.h:126
const vector< shared_ptr< tknucleus > > & get_nuclei()
return a vector containing all the known nuclei
Definition: tkmanager.h:107
int get_new_decay_id()
define a new unique decay id
Definition: tkmanager.cpp:393
virtual ~tkmanager()
Definition: tkmanager.cpp:77
bool known_element(tkstring _nuc, int &_z)
is the element symbol is known (ex: "C")
Definition: tkmanager.cpp:375
void preload_level_schemes(bool _verbose=false)
preload all the level schemes from the database
Definition: tkmanager.cpp:342
Stores information on an experimental measure.
Definition: tkmeasure.h:60
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
Definition: tkstring.h:54
tkstring extract_alpha()
Returns a tkstring composed only of the alphabetic letters of the original tkstring.
Definition: tkstring.cpp:387
static const char * form(const char *_format,...)
Definition: tkstring.cpp:431
bool is_empty() const
Definition: tkstring.h:163
bool ends_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition: tkstring.cpp:241
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition: tkstring.h:197
tkstring & prepend(const tkstring &_st)
Definition: tkstring.h:224
bool begins_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition: tkstring.h:185
double atof() const
Converts a string to double value.
Definition: tkstring.cpp:191
Definition: tklog.cpp:39
tklog & do_endl(tklog &log)
Definition: tklog.h:235
data structure used to fill a tkmeasure object from the sqlite database
Definition: tkdb_table.h:72