TkN 2.3
Toolkit for Nuclei
Loading...
Searching...
No Matches
tkisotope_builder.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 "tkisotope_builder.h"
38
39#include <algorithm>
40#include <iostream>
41#include <fstream>
42
43#include "tklog.h"
44
45namespace tkn {
52}
53
54using namespace tkn;
55using namespace std;
56
57// Decay Mode : decay modes.
58// Mass excess : Mass excess
59// β2 : quadrupole deformation parameter obtained from the B(E2) value, as explained in the 2001 work of Raman et al. Basically,
60// β2=(4π/3ZR0^2)[B(E2)]^(1/2), where R0=1.2A^(1/3), Z and A are the number of protons and the number of nucleons respectively,
61// and the B(E2) values are obtained from ENSDF. B(E2) values can have large uncertainties, or be defined as upper/lower limits.
62// The cell will not be colored for the latter cases and furthermore, it will not be colored if the uncertainty of the derived β2 exceeds 50%.
63// FY235U : thermal neutron-induced fission yields for 235-Uranium. The fission yields are normalized so that their sum is equal to 2.
64// FY238U : neutron-induced fission yields for 238-Uranium. The fission yields are normalized so that their sum is equal to 2.
65// FY239Pu : thermal neutron-induced fission yields for 239-Plutonium. The fission yields are normalized so that their sum is equal to 2.
66// FY241Pu : neutron-induced fission yields for 239-Plutonium. The fission yields are normalized so that their sum is equal to 2.
67// FY252Cf : spontaneous fission yields for 252-Californium. The fission yields are normalized so that their sum is equal to 2.
68// cFY235U : cumulative fission yields
69// cFY238U : cumulative fission yields
70// cFY239Pu : cumulative fission yields
71// cFY241Pu : cumulative fission yields
72// cFY252Cf : cumulative fission yields
73
74
75tkisotope_builder::tkisotope_builder(tkdatabase *_database, const char *_table_name) : tkdb_builder(_database, _table_name)
76{
77 fTable = &fDataBase->new_table(fTableName);
78
79 fTable->add_column("isotope_id", "INT PRIMARY KEY NOT NULL");
80 fTable->add_column("element_id", "INT NOT NULL");
81 fTable->add_column("mass", "INT");
82
83 // data taken from IAEA API
84
85 fTable->add_column("isotope_year_discovered", "INT");
86
87 add_measure("mass_excess",false);
88 add_measure("electric_quadrupole",false);
89 add_measure("magnetic_dipole",false);
90 add_measure("radius",false);
91
92 // data taken from NUDAT3 json file
93
94 add_measure("abundance",false);
95 add_measure("quadrupoleDeformation",false);
96
97 add_measure("FY235U",false);
98 add_measure("FY238U",false);
99 add_measure("FY239Pu",false);
100 add_measure("FY241Pu",false);
101 add_measure("FY252Cf",false);
102
103 add_measure("cFY235U",false);
104 add_measure("cFY238U",false);
105 add_measure("cFY239Pu",false);
106 add_measure("cFY241Pu",false);
107 add_measure("cFY252Cf",false);
108
109 fTable->add_column("decay_modes", "TEXT");
110
111 // columns created here but filled later by ensdf values
112
113 fTable->add_column("spin","REAL");
114 fTable->add_column("parity","INT");
115 fTable->add_column("spin_parity","TEXT");
116
117 add_measure("lifetime",false);
118
119 fTable->add_constraint("FOREIGN KEY (element_id) REFERENCES ELEMENT (element_id)"); // hold this link with a constraints
120 fTable->write_to_database();
121
122 glog << info << "Creating '" << _table_name << "' table" << do_endl;
123}
124
126
127void tkisotope_builder::fill_isotope(const json_nucleus &_json_nuc)
128{
129 fIsotopeIdx++;
130
131// glog << debug << "filling db with : " << _json_nuc.name.data() << " " << fIsotopeIdx<< do_endl;
132
133 (*fTable)["isotope_id"].set_value(fIsotopeIdx);
134 (*fTable)["element_id"].set_value(_json_nuc.Z+1);
135 (*fTable)["mass"].set_value(_json_nuc.A);
136 (*fTable)["isotope_year_discovered"].set_value(_json_nuc.year);
137
138 fill_measure("mass_excess",_json_nuc.mass_excess,false);
139 fill_measure("abundance",_json_nuc.abundance,false);
140 fill_measure("quadrupoleDeformation",_json_nuc.quadrupoleDeformation,false);
141
142 fill_measure("FY235U",_json_nuc.FY235U,false);
143 fill_measure("FY238U",_json_nuc.FY235U,false);
144 fill_measure("FY239Pu",_json_nuc.FY239Pu,false);
145 fill_measure("FY241Pu",_json_nuc.FY239Pu,false);
146 fill_measure("FY252Cf",_json_nuc.FY252Cf,false);
147
148 fill_measure("cFY235U",_json_nuc.cFY235U,false);
149 fill_measure("cFY238U",_json_nuc.cFY235U,false);
150 fill_measure("cFY239Pu",_json_nuc.cFY239Pu,false);
151 fill_measure("cFY241Pu",_json_nuc.cFY239Pu,false);
152 fill_measure("cFY252Cf",_json_nuc.cFY252Cf,false);
153
154 fill_measure("electric_quadrupole",_json_nuc.electric_quadrupole,false);
155 fill_measure("magnetic_dipole",_json_nuc.magnetic_dipole,false);
156 fill_measure("radius",_json_nuc.radius,false);
157
158 // fill the neutron lifetime
159 if(_json_nuc.Z==0 && _json_nuc.N ==1) {
161 lifetime.value = 613.9;
162 lifetime.err = 0.6;
163 lifetime.unit = "S";
164 lifetime.filled = true;
165 fill_measure("lifetime",lifetime,false);
166 }
167
168 tkstring decays;
169 for(auto &dec: _json_nuc.decay_modes) decays.append(tkstring::form("[%s;%g]",dec.first.data(),dec.second));
170 (*fTable)["decay_modes"].set_value(decays.data());
171
172 fTable->push_row();
173}
174
175int tkisotope_builder::fill_database(const char *_json_filename,const char *_gs_filename, int _only_charge, int _only_mass)
176{
177 glog.set_class("db_isotope_builder");
178 glog.set_method(tkstring::form("fill_database('%s','%s')",_json_filename,_gs_filename));
179
180 tkdb_table &fTable = (*fDataBase)[fTableName.data()];
181
182 tkstring message = "Building '" + fTable.get_name() + "' table";
183
184 std::ifstream ifs(_json_filename);
185 if(!ifs.good()) {
186 glog<< error_v << "data file cannot be opened" << do_endl;
187 glog.clear();
188 return 1;
189 }
190
191 json jf = json::parse(ifs);
192
193 auto &nuclides = jf.at("nuclides");
194 int NNucs = nuclides.size();
195 int inuc=0;
196
197 map<int, map<int, json_nucleus>> nuclei;
198 tkstring nread;
199
200 for(auto &nuc: nuclides) {
201 json_nucleus json_nuc = read_nucleus(nuc);
202
203 bool do_push = ((_only_charge==0) && (_only_mass==0));
204 if((_only_charge == json_nuc.Z) && (_only_mass == 0)) do_push = true;
205 if((_only_charge == json_nuc.Z) && (_only_mass == json_nuc.A)) do_push = true;
206 if((_only_charge == 0) && (_only_mass == json_nuc.A)) do_push = true;
207
208 if(do_push) {
209 nuclei[json_nuc.Z][json_nuc.A] = json_nuc;
210 nread += tkstring::form("(%d,%d)", json_nuc.Z, json_nuc.A);
211 }
212 glog.progress_bar(NNucs,inuc,message.data());
213 inuc++;
214 }
215
216 tkn::tkstring line="";
217 fstream file (_gs_filename, ios::in);
218 if(file.is_open())
219 {
220 // read the first line to fill the <number,name> column map
221 if(!getline(file,line)) return 1;
222 int ic=0;
223
224 std::map<int,tkn::tkstring> gs_columns;
225 for(const auto &cname : line.tokenize(",")) gs_columns[ic++] = cname;
226
227 // now read all lines and fill the <name, value> map
228 while(getline(file, line))
229 {
230 std::map<tkn::tkstring, tkn::tkstring> values;
231 line.replace_all(",,",", ,");
232 line.replace_all(",,",", ,");
233 ic=0;
234 for(auto val : line.tokenize(",")) {val.remove_all(" "); values[gs_columns[ic]] = val; ic++;}
235 tkstring dum = tkstring::form("(%d,%d)",values["z"].atoi(),values["n"].atoi()+values["z"].atoi());
236
237 if(!nread.contains(tkstring::form("(%d,%d)",values["z"].atoi(),values["n"].atoi()+values["z"].atoi()))) continue;
238 auto& nuc = nuclei[values["z"].atoi()][values["n"].atoi()+values["z"].atoi()];
239 if(!values["massexcess"].is_empty()) nuc.mass_excess = {values["massexcess"].atof(),values["unc_me"].atof(),-1.,-1.,"keV",values["me_systematics"].equal_to("Y")?";ERR=SY":"",true};
240 if(!values["radius"].is_empty())nuc.radius = {values["radius"].atof(),values["unc_r"].atof(),-1.,-1.,"fm","",true};
241 if(!values["electric_quadrupole"].is_empty()) nuc.electric_quadrupole = {values["electric_quadrupole"].atof(),values["unc_eq"].atof(),-1.,-1.,"barn","",true};
242 if(!values["magnetic_dipole"].is_empty()) nuc.magnetic_dipole = {values["magnetic_dipole"].atof(),values["unc_md"].atof(),-1.,-1.,"mun","",true};
243 if(!values["discovery"].is_empty()) nuc.year = values["discovery"].atoi();
244 }
245 }
246
247 fDataBase->exec_sql("BEGIN TRANSACTION");
248
249 inuc=0;
250 for(auto &z: nuclei) {
251 for(auto &a: z.second) {
252// glog << debug << "filling db with : " << a.second.name.data() << do_endl;
253
254 fill_isotope(a.second);
255 // json_nuc.print();
256 fDataBase->exec_sql(tkstring::form("CREATE VIEW nuc%s as select * from isotope INNER JOIN element on isotope.element_id=element.element_id where element.charge=%d AND isotope.mass=%d",a.second.name.data(),a.second.Z,a.second.A));
257 glog.progress_bar(NNucs,inuc,message.data());
258 inuc++;
259 }
260 }
261
262 fDataBase->exec_sql("END TRANSACTION");
263
264 fDataBase->exec_sql("CREATE INDEX element_index ON isotope(element_id)");
265 fDataBase->exec_sql("CREATE INDEX mass_index ON isotope(mass)");
266
267
268 glog.clear();
269
270 return 0;
271}
272
273void tkisotope_builder::read_measure(const tkstring &key, const json &entry, tkdb_table::measure_data_struct &_data, bool _fromstd)
274{
275 auto to_number = [](const json &value) {
276 if(value.is_string()) return value.get<tkstring>().atof();
277 if(value.is_number()) return value.get<double>();
278 return 0.0;
279 };
280 bool value_set = false;
281 for(auto &_item: entry.items()) {
282 const auto &_key = _item.key();
283 const auto &_val = _item.value();
284 if(_key == "formats") continue;
285 if(_key == "uncertainty") {
286 if(_val.is_object()) {
287 const auto type = _val.value("type", "");
288 if(type == "symmetric") _data.err = to_number(_val.at("value"));
289 else if(type == "range") {
290 if(_val.contains("upperLimit") && _val.contains("lowerLimit")) {
291 const double upper = to_number(_val.at("upperLimit"));
292 const double lower = to_number(_val.at("lowerLimit"));
293 if(!value_set) _data.value = 0.5 * (upper + lower);
294 _data.err = 0.0;
295 _data.err_low = _data.value - lower;
296 _data.err_high = upper - _data.value;
297 }
298 }
299 } else {
300 _data.err = to_number(_val);
301 }
302 }
303 else if(_key == "value") {
304 _data.value = to_number(_val);
305 value_set = true;
306 }
307 else if(_key == "unit") _data.unit = _val.get<tkstring>();
308 else if(_key == "evaluatorInput") continue;
309 else if(_key == "isSystematics" && (_val == "true" || (_val.is_boolean() && _val.get<bool>()))) _data.info.append(";ERR=SY");
310 else {
311 glog << error << key << ": unkown key: " << _key << " type: "<< _item.value().type_name() << do_endl;
312 cout << _val << endl;
313 }
314 }
315 if(_fromstd) {
316 // extract value and err from nudat formated values
317 if(entry.contains("formats") && entry.at("formats").contains("STD")) {
318 tkstring format = entry.at("formats").at("STD").get<tkstring>();
319 auto tokens = format.tokenize();
320 _data.value = tokens.front().atof();
321 if(tokens.size()==2) {
322 _data.err = tokens.back().atof();
323 }
324 }
325 }
326 _data.filled = true;
327}
328
329tkisotope_builder::json_nucleus tkisotope_builder::read_nucleus(json &entry) {
330 json_nucleus nuc;
331 bool pause = false;
332 for(auto &item: entry.items())
333 {
334 auto &key = item.key();
335 auto &val = item.value();
336 if(key == "name") nuc.name = val;
337 else if(key == "z") nuc.Z = val;
338 else if(key == "n") nuc.N = val;
339 else if(key == "a") nuc.A = val;
340 else if(key == "bindingEnergy") continue;
341 else if(key == "bindingEnergyLDMFit") continue;
342 else if(key == "levels") {
343 // pick the ground state level when isomers are present
344 auto is_ground_state = [](const json &level) {
345 if(!level.contains("energy")) return false;
346 const auto &energy = level.at("energy");
347 if(!energy.is_object() || !energy.contains("value")) return false;
348 const auto &energy_val = energy.at("value");
349 if(energy_val.is_string()) return energy_val.get<tkstring>().atof() == 0.0;
350 if(energy_val.is_number()) return energy_val.get<double>() == 0.0;
351 return false;
352 };
353 const json *level_ptr = nullptr;
354 const auto it = std::find_if(val.begin(), val.end(), is_ground_state);
355 bool picked_ground = (it != val.end());
356 if(picked_ground) level_ptr = &(*it);
357 else if(!val.empty()) level_ptr = &val.front();
358 if(!level_ptr) continue;
359 for(auto &_item: level_ptr->items()) {
360 const auto &_key = _item.key();
361 const auto &_val = _item.value();
362 if(_key == "decayModes") {
363 if(_val.is_object() && (_val.contains("observed") || _val.contains("predicted"))) {
364 if(_val.contains("observed")) {
365 for(const auto &mode : _val.at("observed")) {
366 tkstring type = mode.value("mode", "");
367 tkstring ratio = "-1";
368 if(mode.contains("value")) {
369 if(mode.at("value").is_string()) ratio = mode.at("value").get<tkstring>();
370 else if(mode.at("value").is_number()) ratio = tkstring::form("%g", mode.at("value").get<double>());
371 }
372 nuc.decay_modes.emplace_back(type, ratio.atof());
373 }
374 }
375 if(_val.contains("predicted")) {
376 for(const auto &mode : _val.at("predicted")) {
377 tkstring type = mode.value("mode", "");
378 tkstring ratio = "-1";
379 nuc.decay_modes.emplace_back(type, ratio.atof());
380 }
381 }
382 } else {
383 for(auto &mode: _val.items()) {
384 if(mode.value().size()==3) {
385 tkstring type = mode.value().at("name");
386 tkstring symbol = mode.value().at("symbol");
387 tkstring ratio;
388 // unkown ratios
389 if(symbol == "?") {
390 symbol = "=";
391 ratio = "-1";
392 }
393 else ratio = mode.value().at("value");
394 nuc.decay_modes.emplace_back(type,ratio.atof());
395 }
396 else {
397 tkstring type = mode.value().at("name");
398 type.remove_all("?");
399 tkstring symbol = "=";
400 tkstring ratio = "-1";
401 nuc.decay_modes.emplace_back(type,ratio.atof());
402 }
403 }
404 }
405 }
406 else if(_key == "energy") {
407 if(_val.empty()) continue;
408 if(_val.size()<2) continue;
409 double ener = 0.0;
410 const auto &energy_val = _val.at("value");
411 if(energy_val.is_string()) ener = energy_val.get<tkstring>().atof();
412 else if(energy_val.is_number()) ener = energy_val.get<double>();
413 if(ener != 0. && picked_ground) {
414 glog << error << nuc.name << ": level is not ground state ! " << _val << do_endl;
415 }
416 }
417 else if(_key == "massExcess") read_measure(_key, _val, nuc.mass_excess);
418 else if(_key == "abundance") {
419 read_measure(_key, _val, nuc.abundance,true);
420 nuc.abundance.unit = "%";
421 }
422 // include in the ensdf parsing
423 else if(_key == "halflife" || _key == "spinAndParity" || _key == "spinParity") continue;
424 else {
425 glog << error << "levels: unkown key: " << _key << " type: "<< _item.value().type_name() << do_endl;
426 cout << _val << endl;
427 }
428 }
429 }
430 else if(key == "pairingGap") continue;
431 else if(key == "qValues") continue;
432 else if(key == "separationEnergies") continue;
433 else if(key == "webLinks") continue;
434 else if(key == "BE4DBE2") continue;
435 else if(key == "excitedStateEnergies") {
436 for(auto &_item: val.items()) {
437 const auto &_key = _item.key();
438 const auto &_val = _item.value();
439 if(_key == "firstExcitedStateEnergy") continue;
440 if(_key == "firstTwoPlusEnergy") continue;
441 if(_key == "firstFourPlusEnergy") continue;
442 if(_key == "firstFourPlusOverFirstTwoPlusEnergy") continue;
443 if(_key == "firstThreeMinusEnergy") continue;
444 glog << error << key << ": unkown key: " << _key << " type: "<< _item.value().type_name() << do_endl;
445 cout << _val << endl;
446 }
447 }
448 else if(key == "fissionYields") {
449 for(auto &_item: val.items()) {
450 const auto &_key = _item.key();
451 const auto &_val = _item.value();
452 if(_key == "FY235U") read_measure(_key, _val, nuc.FY235U);
453 else if(_key == "FY238U") read_measure(_key, _val, nuc.FY238U);
454 else if(_key == "FY239Pu") read_measure(_key, _val, nuc.FY239Pu);
455 else if(_key == "FY241Pu") read_measure(_key, _val, nuc.FY241Pu);
456 else if(_key == "FY252Cf") read_measure(_key, _val, nuc.FY252Cf);
457 else if(_key == "cFY235U") read_measure(_key, _val, nuc.cFY235U);
458 else if(_key == "cFY238U") read_measure(_key, _val, nuc.cFY238U);
459 else if(_key == "cFY239Pu") read_measure(_key, _val, nuc.cFY239Pu);
460 else if(_key == "cFY241Pu") read_measure(_key, _val, nuc.cFY241Pu);
461 else if(_key == "cFY252Cf") read_measure(_key, _val, nuc.cFY252Cf);
462 else {
463 glog << error << key << ": unkown key: " << _key << " type: "<< _item.value().type_name() << do_endl;
464 cout << _val << endl;
465 }
466 }
467 }
468 else if(key == "quadrupoleDeformation") read_measure(key, val, nuc.quadrupoleDeformation);
469 else if(key == "thermalNeutronCapture") continue;
470 else if(key == "thermalNeutronFission") continue;
471 else if(key == "discovery") continue;
472 else {
473 glog << warning << "unknown key: " << key << do_endl;
474 cout<< "value: " << endl;
475 cout<<val<<endl;
476 pause = true;
477 }
478 }
479 if(pause) {
480 nuc.print();
481 cin.get();
482 }
483 return nuc;
484}
485
486#ifdef HAS_ROOT
487ClassImp(tkisotope_builder);
488#endif
Interface to the sqlite database.
Definition tkdatabase.h:57
tkdb_builder(tkdatabase *_database, const char *_table_name)
Representaiton of a sqlite data table.
Definition tkdb_table.h:52
Decoding of the NUDAT isotope properties.
int fill_database(const char *_json_filename, const char *_gs_filename, int _only_charge=0, int _only_mass=0)
virtual ~tkisotope_builder() override
tkisotope_builder(tkdatabase *_database, const char *_table_name="ISOTOPE")
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
Definition tkstring.h:54
static const char * form(const char *_format,...)
Definition tkstring.cpp:431
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
Definition tkstring.cpp:254
tkstring & remove_all(const tkstring &_s1)
Definition tkstring.h:215
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition tkstring.h:197
tkstring & append(const tkstring &_st)
Definition tkstring.h:227
tkstring & replace_all(const tkstring &_s1, const tkstring &_s2)
Definition tkstring.h:203
double atof() const
Converts a string to double value.
Definition tkstring.cpp:191
Definition tklog.cpp:39
tklog & error_v(tklog &log)
Definition tklog.h:430
tklog & info(tklog &log)
Definition tklog.h:336
tklog & error(tklog &log)
Definition tklog.h:367
tklog & do_endl(tklog &log)
Definition tklog.h:235
tklog & warning(tklog &log)
Definition tklog.h:354
data structure used to fill a tkmeasure object from the sqlite database
Definition tkdb_table.h:72