14#include "tkisotope_builder.h"
53 fTable = &fDataBase->new_table(fTableName);
55 fTable->add_column(
"isotope_id",
"INT PRIMARY KEY NOT NULL");
56 fTable->add_column(
"element_id",
"INT NOT NULL");
57 fTable->add_column(
"mass",
"INT");
61 fTable->add_column(
"isotope_year_discovered",
"INT");
63 add_measure(
"mass_excess",
false);
64 add_measure(
"electric_quadrupole",
false);
65 add_measure(
"magnetic_dipole",
false);
66 add_measure(
"radius",
false);
70 add_measure(
"abundance",
false);
71 add_measure(
"quadrupoleDeformation",
false);
73 add_measure(
"FY235U",
false);
74 add_measure(
"FY238U",
false);
75 add_measure(
"FY239Pu",
false);
76 add_measure(
"FY241Pu",
false);
77 add_measure(
"FY252Cf",
false);
79 add_measure(
"cFY235U",
false);
80 add_measure(
"cFY238U",
false);
81 add_measure(
"cFY239Pu",
false);
82 add_measure(
"cFY241Pu",
false);
83 add_measure(
"cFY252Cf",
false);
85 fTable->add_column(
"decay_modes",
"TEXT");
89 fTable->add_column(
"spin",
"REAL");
90 fTable->add_column(
"parity",
"INT");
91 fTable->add_column(
"spin_parity",
"TEXT");
93 add_measure(
"lifetime",
false);
95 fTable->add_constraint(
"FOREIGN KEY (element_id) REFERENCES ELEMENT (element_id)");
96 fTable->write_to_database();
98 glog <<
info <<
"Creating '" << _table_name <<
"' table" <<
do_endl;
103void tkisotope_builder::fill_isotope(
const json_nucleus &_json_nuc)
109 (*fTable)[
"isotope_id"].set_value(fIsotopeIdx);
110 (*fTable)[
"element_id"].set_value(_json_nuc.Z + 1);
111 (*fTable)[
"mass"].set_value(_json_nuc.A);
112 (*fTable)[
"isotope_year_discovered"].set_value(_json_nuc.year);
114 fill_measure(
"mass_excess", _json_nuc.mass_excess,
false);
115 fill_measure(
"abundance", _json_nuc.abundance,
false);
116 fill_measure(
"quadrupoleDeformation", _json_nuc.quadrupoleDeformation,
false);
118 fill_measure(
"FY235U", _json_nuc.FY235U,
false);
119 fill_measure(
"FY238U", _json_nuc.FY238U,
false);
120 fill_measure(
"FY239Pu", _json_nuc.FY239Pu,
false);
121 fill_measure(
"FY241Pu", _json_nuc.FY241Pu,
false);
122 fill_measure(
"FY252Cf", _json_nuc.FY252Cf,
false);
124 fill_measure(
"cFY235U", _json_nuc.cFY235U,
false);
125 fill_measure(
"cFY238U", _json_nuc.cFY238U,
false);
126 fill_measure(
"cFY239Pu", _json_nuc.cFY239Pu,
false);
127 fill_measure(
"cFY241Pu", _json_nuc.cFY241Pu,
false);
128 fill_measure(
"cFY252Cf", _json_nuc.cFY252Cf,
false);
130 fill_measure(
"electric_quadrupole", _json_nuc.electric_quadrupole,
false);
131 fill_measure(
"magnetic_dipole", _json_nuc.magnetic_dipole,
false);
132 fill_measure(
"radius", _json_nuc.radius,
false);
135 if (_json_nuc.Z == 0 && _json_nuc.N == 1) {
137 lifetime.
value = 613.9;
141 fill_measure(
"lifetime", lifetime,
false);
145 for (
auto &dec : _json_nuc.decay_modes) decays.
append(
tkstring::form(
"[%s;%g]", dec.first.data(), dec.second));
146 (*fTable)[
"decay_modes"].set_value(decays.data());
153 glog.set_class(
"db_isotope_builder");
154 glog.set_method(
tkstring::form(
"fill_database('%s','%s')", _json_filename, _gs_filename));
156 tkdb_table &fTable = (*fDataBase)[fTableName.data()];
158 tkstring message =
"Building '" + fTable.get_name() +
"' table";
160 std::ifstream ifs(_json_filename);
167 json jf = json::parse(ifs);
169 auto &nuclides = jf.at(
"nuclides");
170 int NNucs = nuclides.size();
173 map<int, map<int, json_nucleus>> nuclei;
176 for (
auto &nuc : nuclides) {
177 json_nucleus json_nuc = read_nucleus(nuc);
179 bool do_push = ((_only_charge == 0) && (_only_mass == 0));
180 if ((_only_charge == json_nuc.Z) && (_only_mass == 0)) do_push =
true;
181 if ((_only_charge == json_nuc.Z) && (_only_mass == json_nuc.A)) do_push =
true;
182 if ((_only_charge == 0) && (_only_mass == json_nuc.A)) do_push =
true;
185 nuclei[json_nuc.Z][json_nuc.A] = json_nuc;
188 glog.progress_bar(NNucs, inuc, message.data());
193 fstream file(_gs_filename, ios::in);
194 if (!file.is_open()) {
195 glog <<
error_v <<
"IAEA ground state file cannot be opened: '" << _gs_filename <<
"'" <<
do_endl;
196 glog <<
error_v <<
"mass_excess, radius, electric_quadrupole and magnetic_dipole will be missing from the database." <<
do_endl;
197 glog <<
error_v <<
"Download it manually from: https://nds.iaea.org/relnsd/v1/data?fields=ground_states&nuclides=all" <<
do_endl;
198 glog <<
error_v <<
"and place it at: " << _gs_filename <<
do_endl;
203 if (!getline(file, line))
return 1;
206 std::map<int, tkn::tkstring> gs_columns;
207 for (
const auto &cname : line.
tokenize(
",")) gs_columns[ic++] = cname;
210 while (getline(file, line)) {
211 std::map<tkn::tkstring, tkn::tkstring> values;
215 for (
auto val : line.
tokenize(
",")) {
217 values[gs_columns[ic]] = val;
222 if (!nread.
contains(
tkstring::form(
"(%d,%d)", values[
"z"].atoi(), values[
"n"].atoi() + values[
"z"].atoi())))
continue;
223 auto &nuc = nuclei[values[
"z"].atoi()][values[
"n"].atoi() + values[
"z"].atoi()];
224 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};
225 if (!values[
"radius"].is_empty()) nuc.radius = {values[
"radius"].atof(), values[
"unc_r"].atof(), -1., -1.,
"fm",
"",
true};
226 if (!values[
"electric_quadrupole"].is_empty()) nuc.electric_quadrupole = {values[
"electric_quadrupole"].atof(), values[
"unc_eq"].atof(), -1., -1.,
"barn",
"",
true};
227 if (!values[
"magnetic_dipole"].is_empty()) nuc.magnetic_dipole = {values[
"magnetic_dipole"].atof(), values[
"unc_md"].atof(), -1., -1.,
"mun",
"",
true};
228 if (!values[
"discovery"].is_empty()) nuc.year = values[
"discovery"].atoi();
232 fDataBase->exec_sql(
"BEGIN TRANSACTION");
235 for (
auto &z : nuclei) {
236 for (
auto &a : z.second) {
239 fill_isotope(a.second);
241 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));
242 glog.progress_bar(NNucs, inuc, message.data());
247 fDataBase->exec_sql(
"END TRANSACTION");
249 fDataBase->exec_sql(
"CREATE INDEX element_index ON isotope(element_id)");
250 fDataBase->exec_sql(
"CREATE INDEX mass_index ON isotope(mass)");
259 auto to_number = [](
const json &value) {
260 if (value.is_string())
return value.get<
tkstring>().atof();
261 if (value.is_number())
return value.get<
double>();
264 bool value_set =
false;
265 for (
auto &_item : entry.items()) {
266 const auto &_key = _item.key();
267 const auto &_val = _item.value();
268 if (_key ==
"formats")
continue;
269 if (_key ==
"uncertainty") {
270 if (_val.is_object()) {
271 const auto type = _val.value(
"type",
"");
272 if (type ==
"symmetric")
273 _data.
err = to_number(_val.at(
"value"));
274 else if (type ==
"range") {
275 if (_val.contains(
"upperLimit") && _val.contains(
"lowerLimit")) {
276 const double upper = to_number(_val.at(
"upperLimit"));
277 const double lower = to_number(_val.at(
"lowerLimit"));
278 if (!value_set) _data.
value = 0.5 * (upper + lower);
285 _data.
err = to_number(_val);
287 }
else if (_key ==
"value") {
288 _data.
value = to_number(_val);
290 }
else if (_key ==
"unit")
291 _data.
unit = _val.get<tkstring>();
292 else if (_key ==
"evaluatorInput")
294 else if (_key ==
"isSystematics" && (_val ==
"true" || (_val.is_boolean() && _val.get<
bool>())))
297 glog <<
error << key <<
": unkown key: " << _key <<
" type: " << _item.value().type_name() <<
do_endl;
298 cout << _val << endl;
303 if (entry.contains(
"formats") && entry.at(
"formats").contains(
"STD")) {
304 tkstring format = entry.at(
"formats").at(
"STD").get<tkstring>();
307 if (tokens.size() == 2) {
308 _data.
err = tokens.back().
atof();
315tkisotope_builder::json_nucleus tkisotope_builder::read_nucleus(json &entry)
319 for (
auto &item : entry.items()) {
320 auto &key = item.key();
321 auto &val = item.value();
330 else if (key ==
"bindingEnergy")
332 else if (key ==
"bindingEnergyLDMFit")
334 else if (key ==
"levels") {
336 auto is_ground_state = [](
const json &level) {
337 if (!level.contains(
"energy"))
return false;
338 const auto &energy = level.at(
"energy");
339 if (!energy.is_object() || !energy.contains(
"value"))
return false;
340 const auto &energy_val = energy.at(
"value");
341 if (energy_val.is_string())
return energy_val.get<tkstring>().atof() == 0.0;
342 if (energy_val.is_number())
return energy_val.get<
double>() == 0.0;
345 const json *level_ptr =
nullptr;
346 const auto it = std::find_if(val.begin(), val.end(), is_ground_state);
347 bool picked_ground = (it != val.end());
350 else if (!val.empty())
351 level_ptr = &val.front();
352 if (!level_ptr)
continue;
353 for (
auto &_item : level_ptr->items()) {
354 const auto &_key = _item.key();
355 const auto &_val = _item.value();
356 if (_key ==
"decayModes") {
357 if (_val.is_object() && (_val.contains(
"observed") || _val.contains(
"predicted"))) {
358 if (_val.contains(
"observed")) {
359 for (
const auto &mode : _val.at(
"observed")) {
360 tkstring type = mode.value(
"mode",
"");
361 tkstring ratio =
"-1";
362 if (mode.contains(
"value")) {
363 if (mode.at(
"value").is_string())
364 ratio = mode.at(
"value").get<tkstring>();
365 else if (mode.at(
"value").is_number())
368 nuc.decay_modes.emplace_back(type, ratio.
atof());
371 if (_val.contains(
"predicted")) {
372 for (
const auto &mode : _val.at(
"predicted")) {
373 tkstring type = mode.value(
"mode",
"");
374 tkstring ratio =
"-1";
375 nuc.decay_modes.emplace_back(type, ratio.
atof());
379 for (
auto &mode : _val.items()) {
380 if (mode.value().size() == 3) {
381 tkstring type = mode.value().at(
"name");
382 tkstring symbol = mode.value().at(
"symbol");
389 ratio = mode.value().at(
"value");
390 nuc.decay_modes.emplace_back(type, ratio.
atof());
392 tkstring type = mode.value().at(
"name");
394 tkstring symbol =
"=";
395 tkstring ratio =
"-1";
396 nuc.decay_modes.emplace_back(type, ratio.
atof());
400 }
else if (_key ==
"energy") {
401 if (_val.empty())
continue;
402 if (_val.size() < 2)
continue;
404 const auto &energy_val = _val.at(
"value");
405 if (energy_val.is_string())
406 ener = energy_val.get<tkstring>().atof();
407 else if (energy_val.is_number())
408 ener = energy_val.get<
double>();
409 if (ener != 0. && picked_ground) {
410 glog <<
error << nuc.name <<
": level is not ground state ! " << _val <<
do_endl;
412 }
else if (_key ==
"massExcess")
414 else if (_key ==
"abundance") {
415 read_measure(_key, _val, nuc.abundance,
true);
416 nuc.abundance.unit =
"%";
419 else if (_key ==
"halflife" || _key ==
"spinAndParity" || _key ==
"spinParity")
422 glog <<
error <<
"levels: unkown key: " << _key <<
" type: " << _item.value().type_name() <<
do_endl;
423 cout << _val << endl;
426 }
else if (key ==
"pairingGap")
428 else if (key ==
"qValues")
430 else if (key ==
"separationEnergies")
432 else if (key ==
"webLinks")
434 else if (key ==
"BE4DBE2")
436 else if (key ==
"excitedStateEnergies") {
437 for (
auto &_item : val.items()) {
438 const auto &_key = _item.key();
439 const auto &_val = _item.value();
440 if (_key ==
"firstExcitedStateEnergy")
continue;
441 if (_key ==
"firstTwoPlusEnergy")
continue;
442 if (_key ==
"firstFourPlusEnergy")
continue;
443 if (_key ==
"firstFourPlusOverFirstTwoPlusEnergy")
continue;
444 if (_key ==
"firstThreeMinusEnergy")
continue;
445 glog <<
error << key <<
": unkown key: " << _key <<
" type: " << _item.value().type_name() <<
do_endl;
446 cout << _val << endl;
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")
453 read_measure(_key, _val, nuc.FY235U);
454 else if (_key ==
"FY238U")
455 read_measure(_key, _val, nuc.FY238U);
456 else if (_key ==
"FY239Pu")
457 read_measure(_key, _val, nuc.FY239Pu);
458 else if (_key ==
"FY241Pu")
459 read_measure(_key, _val, nuc.FY241Pu);
460 else if (_key ==
"FY252Cf")
461 read_measure(_key, _val, nuc.FY252Cf);
462 else if (_key ==
"cFY235U")
463 read_measure(_key, _val, nuc.cFY235U);
464 else if (_key ==
"cFY238U")
465 read_measure(_key, _val, nuc.cFY238U);
466 else if (_key ==
"cFY239Pu")
467 read_measure(_key, _val, nuc.cFY239Pu);
468 else if (_key ==
"cFY241Pu")
469 read_measure(_key, _val, nuc.cFY241Pu);
470 else if (_key ==
"cFY252Cf")
471 read_measure(_key, _val, nuc.cFY252Cf);
473 glog <<
error << key <<
": unkown key: " << _key <<
" type: " << _item.value().type_name() <<
do_endl;
474 cout << _val << endl;
477 }
else if (key ==
"quadrupoleDeformation")
478 read_measure(key, val, nuc.quadrupoleDeformation);
479 else if (key ==
"thermalNeutronCapture")
481 else if (key ==
"thermalNeutronFission")
483 else if (key ==
"discovery")
487 cout <<
"value: " << endl;
Interface to the sqlite database.
tkdb_builder(tkdatabase *_database, const char *_table_name)
Representaiton of a sqlite data table.
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....
static const char * form(const char *_format,...)
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
tkstring & remove_all(const tkstring &_s1)
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
tkstring & append(const tkstring &_st)
tkstring & replace_all(const tkstring &_s1, const tkstring &_s2)
double atof() const
Converts a string to double value.
tklog & error_v(tklog &log)
tklog & error(tklog &log)
tklog & do_endl(tklog &log)
tklog & warning(tklog &log)
data structure used to fill a tkmeasure object from the sqlite database